Everything you need to build realtime apps and AI agents on DNotifier

Copy-paste reference for the JavaScript and TypeScript SDK. Python uses snake_case for the same methods, and Dart uses camelCase.

Download printable PDF

01Set up your app

Sign up with Google at app.dnotifier.com, then Apps → Create app and copy the appId and secret.

# .env  (add .env to .gitignore, never commit it)
DNOTIFIER_APP_ID=your-app-id
DNOTIFIER_SECRET=your-secret

Add your model keys in AI Studio → Providers (OpenAI, Anthropic, Gemini…).

02Install

JavaScript / TypeScript (Node.js also needs ws for WebSocket)

npm install @dnotifier-realtime/dnotifier
npm install ws

Python

pip install dnotifier

Dart / Flutter

flutter pub add dnotifier

03Connect

import { DNotifier } from "@dnotifier-realtime/dnotifier";

const notifier = new DNotifier({
  appId: process.env.DNOTIFIER_APP_ID,
  secret: process.env.DNOTIFIER_SECRET,
  transport: "http",      // or "ws"
  userId: "user-123",
});

await notifier.connect();

Check plan limits and whether AI is on

notifier.getPlanLimits();   notifier.aiEnabled;

Node.js with ws: pass the WebSocket class

import WebSocket from "ws";   // then: WebSocketImpl: WebSocket

04Pick a transport

"ws"Live chat, realtime messages, binary data, remote agents, waiting for replies
"http"sendAI, search, knowledge-base documents, runWorkflow. Each call returns its answer.

Common setup: the chat client on ws, the AI backend on http.

05Realtime messaging

Send to one user (direct, by userId)

await notifier.send({
  senderId: "alice", receiverId: "bob",
  data: { type: "text", text: "Hi Bob" },
});

Send to many users

receiverIds: ["bob", "carol", "dave"]

Receive

onMessage: (msg) => {
  msg.metadata.sender;      // who sent it
  msg.payload.toJSON();     // { type, text }
}

Images, audio, files

data: { type: "image", content: bytes, fileName, mimeType }

Raw bytes (ws only). Read with msg.payload.raw()

notifier.sendBinary({ senderId, receiverIds, buffer, type: "binary" });

06Chat history

History is saved by default. Skip it per message:

saveHistory: false

Load a conversation

await notifier.fetchChatHistory({ senderId: "alice", receiverIds: ["bob"] });

Delete a message (id from msg.metadata.id)

await notifier.deleteChatHistoryMessage({ senderId, messageId });

07Ask the AI

const res = await notifier.sendAI({
  senderId: "user-123",
  message: { text: "Summarize this ticket." },
});
const answer = res?.data?.content;

Chat-style with a system prompt

message: { messages: [
  { role: "system", content: "You are a billing expert." },
  { role: "user", content: "I was charged twice." },
] }

Choose provider and model per call

provider: "open_ai", model: "gpt-4o"

Keep context across turns

const sessionId = res?.metadata?.packet?.id;
await notifier.sendAI({ senderId, sessionId, message: { text: "And next?" } });

AI history

notifier.fetchAIHistory({ senderId });
notifier.deleteAIHistoryMessage({ senderId, messageId });

08Knowledge base (RAG)

Add a document. No vector database to run.

await notifier.addDocument({
  senderId, recordId: "refund-policy",
  content: "Refunds take 5 business days.",
  type: "text", metadata: { source: "help-center" },
});

Update, read, list, delete

updateDocument()  getDocument()  listDocuments({ limit, offset })  deleteDocument()

Semantic search

const hits = await notifier.search({
  senderId, query: "how long do refunds take",
  limit: 5, minSimilarity: 0.7, filterbySource: "help-center",
});

Answer from your docs: pass hits as context in a system message to sendAI.

09Agents and tools

Register a tool

const add = notifier.tools.register({
  name: "math.add", description: "Add two numbers",
  inputSchema: { type: "object", properties: {
    a: { type: "number" }, b: { type: "number" } } },
  async execute(input) { return { sum: input.a + input.b }; },
});

Define an agent that can use it

const agent = DNotifier.defineAgent({
  name: "math-assistant",
  instructions: "Use math.add for sums.",
  provider: "open_ai", model: "gpt-4o",
  tools: [add],
  permissions: { "math.add": ["execute"] },
});

Run it

const r = await notifier.runAgent(agent, { input: "21 + 21?", maxToolRounds: 6 });
r.output;  r.finishReason;  r.executionId;

Enforce permissions on the server: permissionEnforcement: "backend" in the constructor.

10MCP servers

const mermaid = await notifier.mcp.connect({
  id: "mermaid", name: "Agentic Mermaid",
  transport: "http",
  endpoint: "https://agentic-mermaid.dev/mcp",
});
const tools = mermaid.tools();  // "mermaid.verify", …

Give them to an agent with tools: tools. Tool names are prefixed with the server id.

11Multi-agent workflows

const flow = new DNotifier.Workflow({
  name: "support-router",
  observability: true,
  async entry(ctx) {
    const intent = await ctx.runAgent("intent-agent");
    return ctx.runAgent("general-agent", { input: ctx.input });
  },
}).registerAgents({
  "intent-agent": intentAgent,
  "general-agent": generalAgent,
});

const run = await notifier.runWorkflow({ workflow: flow, input: "How do refunds work?" });

Inside ctx

ctx.runAgents([…])run agents in parallelctx.stateshare data between agentsctx.sendAI / ctx.searchAI and RAG inside a stepctx.waitForMessage()pause for a human reply (ws)ctx.recordStep({ label })add your own step to the graph

Custom agent logic

DNotifier.defineAgent({ name: "writer", async run(ctx) {
  return ctx.sendAI({ message: { text: ctx.input } });
} });

Agent on another server: register { receiverId: "svc-agent-writer" }, and on that host call workflow.listen(notifier) (ws).

12Model providers

"open_ai""anthropic""google_gemini""hugging_face""perplexity""azure_ai""aws_bedrock""ollama"

Set a default on the agent; override per call with provider and model.

13See what happened

observability: trueexecution graph in Dashboard → Workflowslogs: trueAI sessions in Dashboard → Logslabel: "Intent check"name a step in the graphonAgentEventstream tool calls in your code

Usage and quotas: Dashboard → Usage and Plan & limits.

14Same calls in Python and Dart

JS / DartPythonNotesendAIsend_aisender_id=addDocumentadd_documentdoc_type=runWorkflowrun_workflowinput_data=ctx.runAgentctx.run_agentasyncdefineAgentdefine_agentimport from dnotifier