notiflowsDocs
AI

Agent Toolkit

The Notiflows agent toolkit (@notiflows/agent-toolkit) turns your published notiflows into typed, callable tools for your own AI agents — Vercel AI SDK, OpenAI function calling, and LangChain.

The agent toolkit (@notiflows/agent-toolkit) exposes your notiflows as typed, callable tools for AI agents. Where the MCP server lets an editor manage notiflows, the toolkit lets your own agents use Notiflows at runtime — sending the right notification, to the right people, with a schema-safe payload, where every send is attributed and auditable.

Each published notiflow in your project becomes a typed tool (e.g. trigger_welcome_series), alongside a generic trigger_notiflow tool that takes the handle as an argument. The toolkit runs inside your agent, on your model — the account token authorizes API calls server-side and is never exposed to the LLM.

npm i @notiflows/agent-toolkit

Create the toolkit

import { createNotiflowsToolkit } from "@notiflows/agent-toolkit";

const toolkit = createNotiflowsToolkit({
  accountToken: process.env.NOTIFLOWS_TOKEN!, // nf_at_...
  project: "acme",
});
OptionRequiredDescription
accountTokenyesNotiflows account token (nf_at_...).
projectyesProject slug.
baseUrlnoManagement API base (defaults to https://api.notiflows.com/management/v1).
notiflowsnoAn allowlist of handles, or a (notiflow) => boolean predicate. Omit to expose all published notiflows.

Tool arguments

Every trigger tool takes the same arguments — provide recipients or a topic:

ArgumentDescription
recipientsUsers to notify (provide this or topic). Each recipient is external_id (required) plus optional email, phone, first_name, last_name — used to auto-create the user if they don't exist yet.
topicTopic name — notifies all of its subscribers (provide this or recipients).
dataTemplate variables, available in the notification as data.*.
actorThe user who caused the action ({ external_id }), available as actor.*.

The generic trigger_notiflow tool also takes handle, plus an optional draft ("published" — the default — or "draft" to test the current unpublished version).

Vercel AI SDK

import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";
import { createNotiflowsToolkit } from "@notiflows/agent-toolkit";
import { toAISDKTools } from "@notiflows/agent-toolkit/ai-sdk";

const toolkit = createNotiflowsToolkit({
  accountToken: process.env.NOTIFLOWS_TOKEN!,
  project: "acme",
});

const tools = await toAISDKTools(await toolkit.getTools());

await generateText({
  model: openai("gpt-4o"),
  prompt: "Email jane@acme.com the welcome series; her id is user_42.",
  tools, // trigger_welcome_series, trigger_order_shipped, ... + trigger_notiflow
});

OpenAI function calling

import OpenAI from "openai";
import { createNotiflowsToolkit, toOpenAITools } from "@notiflows/agent-toolkit";

const toolkit = createNotiflowsToolkit({ accountToken: process.env.NOTIFLOWS_TOKEN!, project: "acme" });
const { tools, execute } = toOpenAITools(await toolkit.getTools());

const completion = await new OpenAI().chat.completions.create({
  model: "gpt-4o",
  messages,
  tools,
});

for (const call of completion.choices[0].message.tool_calls ?? []) {
  const result = await execute(call.function); // { notiflow_run_id }
}

LangChain

import { toLangChainTools } from "@notiflows/agent-toolkit/langchain";

const tools = await toLangChainTools(await toolkit.getTools()); // DynamicStructuredTool[]

Framework-agnostic

getTools() returns plain tool descriptors you can wire into any framework:

const tools = await toolkit.getTools(); // [{ name, description, inputSchema, execute }]

await tools[0].execute({
  recipients: [{ external_id: "user_42" }],
  data: { plan: "pro" },
});

Human-in-the-loop

requireHumanInput triggers an approval notiflow (typically an in-app channel) before an agent proceeds, then you wait for the human's response out-of-band:

const { notiflow_run_id } = await toolkit.requireHumanInput({
  notiflow: "agent-approval",
  recipients: [{ external_id: "ops_admin" }],
  message: "Agent wants to issue a $200 refund. Approve?",
  data: { amount: 200 },
});
// Wait for the response via webhook/poll on the delivery, then continue.

Why it's safe to hand to an agent

  • Scoped — the toolkit only exposes notiflows you allow (the notiflows allowlist or predicate), and only published ones.
  • Schema-safe — each tool advertises a JSON Schema; recipients, topic, and data are validated by the API before anything sends.
  • Auditable — every trigger goes through the Management API with your account token, so it shows up in the dashboard's "Triggered by" as the token.
  • Server-side only — the account token is never exposed to the model.

API surface

  • createNotiflowsToolkit(config)NotiflowsToolkit
  • toolkit.getTools({ perNotiflow?, includeGeneric? })NotiflowTool[]
  • toolkit.genericTool() → the trigger_notiflow tool (handle as an argument; supports draft)
  • toolkit.listNotiflows() → the published notiflows exposed as tools
  • toolkit.requireHumanInput(opts) → trigger an approval notiflow
  • Adapters: toAISDKTools, toOpenAITools, toLangChainTools

The peer dependencies ai, openai, and @langchain/core are optional and loaded lazily — install only the adapter(s) you actually use.

On this page