# API Reference Programmatic access to your prompt2bot bots. All endpoints use `POST https://api.prompt2bot.com/api` with a JSON body containing `{ endpoint, payload }`. Authentication uses your **API token** (`p2b_` prefix, from [Settings](https://prompt2bot.com/settings)) and **bot ID** together. ## TypeScript Client Library The easiest way to integrate with prompt2bot from TypeScript or JavaScript. The [@prompt2bot/client](https://jsr.io/@prompt2bot/client) package provides typed functions for every API endpoint, plus `extractSignedParams` for verifying incoming signed requests. Works with Deno, Node.js, and Bun. ### Install ```bash # Deno deno add jsr:@prompt2bot/client # Node / Bun npx jsr add @prompt2bot/client ``` **Exports:** `setCustomTools`, `setPrompt`, `createRemoteTask`, `injectContext`, `createBotApi`, `deleteBotApi`, `listBots`, `createProgressBar`, `uiUpdate`, `setSupergreenWhatsapp`, `rotateWebhookSecret`, `extractSignedParams` — Types: `RemoteTool`, `RemoteSkill`, `SignedToolRequest`, `CreateRemoteTaskInput`, `InjectContextInput` ## Webhook Signing > Using the [client library](#typescript-client-library)? `extractSignedParams` > handles signature verification, timestamp checks, and typed parameter > extraction in a single call. The manual approach below is for non-TS > environments. Every request to your endpoints is signed with your bot's Webhook Secret using HMAC SHA-256. The signature covers JSON.stringify(payload). Verify the signature and check the timestamp is within 5 minutes to prevent replay attacks. Recommended provisioning flow: 1. Create or identify the bot and keep its `apiToken` + `botId` 2. Call `rotate-webhook-secret` once from your backend 3. Store the returned `webhookSecret` in your own secret manager or env vars You do not need a separate read endpoint for the webhook secret. Rotate it when you first provision the integration, then store the returned value on your side. ### Request Envelope ```typescript type SignedToolRequest = { payload: { meta: { botId: string; conversationId: string; userId: string; network: string; timestamp: string; // unix ms as string nonce: string; toolCallId?: string; // unique ID for this tool invocation toolName?: string; // name of the tool being called }; params: T; }; signature: string; // hex hmac sha256 of JSON.stringify(payload) }; ``` ### Verify Helper (Node.js / TypeScript) Drop this into your server to verify incoming signed requests. Replace `YOUR_WEBHOOK_SECRET` with your bot's current webhook secret. The recommended way to obtain it programmatically is to call `rotate-webhook-secret` and store the returned value. ```typescript import { createHmac } from "node:crypto"; const secret = "YOUR_WEBHOOK_SECRET"; type SignedToolRequest = { payload: { meta: { botId: string; conversationId: string; userId: string; network: string; timestamp: string; // unix ms as string nonce: string; toolCallId?: string; // unique ID for this tool invocation toolName?: string; // name of the tool being called }; params: T; }; signature: string; // hex hmac sha256 of JSON.stringify(payload) }; const extractSignedParams = (input: SignedToolRequest): T => { if (!input || typeof input !== "object") throw new Error("Bad payload"); const { payload, signature } = input; if (!payload || typeof signature !== "string") { throw new Error("Bad payload"); } const payloadStr = JSON.stringify(payload); const expected = createHmac("sha256", secret).update(payloadStr).digest( "hex", ); if (expected !== signature) throw new Error("Bad signature"); const { meta, params } = payload as SignedToolRequest["payload"]; const ts = Number(meta?.timestamp); if (!Number.isFinite(ts)) throw new Error("Bad timestamp"); if (Math.abs(Date.now() - ts) > 5 * 60_000) { throw new Error("Stale request"); } if (params === undefined) throw new Error("Missing params"); return params as T; }; ``` ## Custom Tools & Skills Define remote tools your bot can call. Each tool exposes an HTTP endpoint with JSON schema parameters following OpenAI tool format. When the agent calls your tool, it sends a signed `POST` to the URL you configured, with parameters in `payload.params` and conversation metadata in `payload.meta`. Recommended setup: 1. Provision the bot and keep its `apiToken` + `botId` 2. Call `rotate-webhook-secret` once during provisioning and store the returned `webhookSecret` 3. Use that `webhookSecret` in your tool server to verify signed requests > **remote_config:** If you create a tool named `remote_config`, it will be > called on every incoming message to fetch dynamic conversation config. It > won't be available as a callable tool for the agent. Return optional JSON > fields like `prompt` and `timezoneIANA`. Leave parameters empty for this tool. ### Your Endpoint Receives ```typescript // Your tool endpoint receives this POST body: type SignedToolRequest = { payload: { meta: { botId: string; conversationId: string; userId: string; network: string; timestamp: string; // unix ms as string nonce: string; toolCallId?: string; // unique ID for this tool invocation toolName?: string; // name of the tool being called }; params: T; }; signature: string; // hex hmac sha256 of JSON.stringify(payload) }; // For a tool with parameters { orderId: string }, params will be: // { orderId: "ORD-123" } // For remote_config, params will be: {} // Return plain text or JSON — the agent uses it as the tool result. ``` **Response format:** Your endpoint can return plain text or JSON. If JSON, objects and arrays are pretty-printed for the agent; strings are used as-is. ### Deferred (Async) Tools Some tools need time to complete — video processing, report generation, external API calls that take minutes. Instead of making the agent wait (and risk it hallucinating a result), return `{ "deferred": true }` from your endpoint. This tells the agent to pause and wait for the real result. When your async work finishes, call [inject-context](#inject-context) with the `toolCallId` and `toolName` from the original request's `meta` to deliver the result. The agent resumes with the actual tool result. #### Flow 1. Agent calls your tool endpoint with `toolCallId` in `meta` 2. Your endpoint starts async work, immediately returns `{ "deferred": true }` 3. Agent pauses — no further model turns until the result arrives 4. Async work completes — your server calls `inject-context` with the result, `toolCallId`, and `toolName` 5. Agent resumes with the real tool result in context ```typescript import { extractSignedParams, injectContext, rotateWebhookSecret, } from "@prompt2bot/client"; // Provision once and store securely in your own env / secret manager. const API_TOKEN = Deno.env.get("P2B_API_TOKEN")!; const BOT_ID = Deno.env.get("P2B_BOT_ID")!; const { webhookSecret: WEBHOOK_SECRET } = await rotateWebhookSecret({ apiToken: API_TOKEN, botId: BOT_ID, }).then((result) => { if (!result.success) throw new Error(result.error); return result; }); // Your tool endpoint — starts async work, returns immediately app.post("/tools/generate-report", async (req) => { const { meta, params } = extractSignedParams(WEBHOOK_SECRET, req.body); const { toolCallId, toolName, conversationId, network } = meta; // Fire off async work generateReport(params).then(async (result) => { // When done, deliver the result back to the agent await injectContext({ apiToken: API_TOKEN, botId: BOT_ID, context: JSON.stringify(result), toolCallId, // ties result to the original tool call toolName, // required with toolCallId preferredNetwork: network, targetConversationId: conversationId, }); }); // Return immediately — agent pauses until inject-context is called return { deferred: true }; }); ``` ### End-to-End Example Register tools and handle signed requests using [@prompt2bot/client](https://jsr.io/@prompt2bot/client): ```typescript import { extractSignedParams, type RemoteTool, rotateWebhookSecret, setCustomTools, type SignedToolRequest, } from "@prompt2bot/client"; // Provision once and store securely in your own env / secret manager. const API_TOKEN = Deno.env.get("P2B_API_TOKEN")!; const BOT_ID = Deno.env.get("P2B_BOT_ID")!; const { webhookSecret: WEBHOOK_SECRET } = await rotateWebhookSecret({ apiToken: API_TOKEN, botId: BOT_ID, }).then((result) => { if (!result.success) throw new Error(result.error); return result; }); const tools: RemoteTool[] = [ { name: "lookup_order", description: "Look up an order by ID.", url: "https://your-server.com/tools/lookup-order", parameters: { type: "object", properties: { orderId: { type: "string" } }, required: ["orderId"], }, }, ]; // Register with prompt2bot (call once on startup / deploy) await setCustomTools({ apiToken: API_TOKEN, botId: BOT_ID, tools }); // Handle incoming signed tool calls app.post("/tools/:name", async (req) => { const { params } = extractSignedParams(WEBHOOK_SECRET, req.body); const tool = tools.find(({ name }) => name === req.params.name); if (!tool) return res.status(404).json({ error: "Unknown tool" }); const result = await handler(params); res.json(result); }); ``` ### Tool Schema | Parameter | Type | Description | |-----------|------|-------------| | `name` * | string | Tool name the agent uses to invoke this tool. | | `description` * | string | Human-readable description of what the tool does. | | `url` * | string | HTTPS endpoint the bot POSTs to when calling. | | `parameters` * | unknown | | ### Skills Group related tools into skills. Skills are loaded on demand by the agent when relevant, which helps keep context focused. Each tool within a skill works the same as a standalone custom tool — an HTTP endpoint called with the same webhook secret. #### Skill Structure | Parameter | Type | Description | |-----------|------|-------------| | `name` * | string | Skill name. | | `description` * | string | Human-readable description of the skill. | | `instructions` * | string | Instructions the agent receives when using this skill. | | `tools` * | array | HTTP tool endpoints grouped under this skill. | ## Conversation Recorder Webhook Provide a webhook URL to receive conversation events. Every message (user, bot, tool calls, tool results) is POSTed as a signed request using the same authentication as Custom Tools. Recommended setup: 1. Keep the bot's `apiToken` + `botId` 2. Call `rotate-webhook-secret` once during provisioning 3. Store the returned `webhookSecret` in your own secret manager or env vars 4. Use that secret to verify the signed recorder webhook requests ### Event Payload ```typescript // Your webhook receives SignedToolRequest type ConvoEvent = { from: string; text: string; time: number; }; // Example: { from: "user", text: "Hello!", time: 1700000000000 } // Also receives: bot messages, tool_call, tool_result events ``` The request envelope and signature verification are identical to Custom Tools. Use `extractSignedParams(webhookSecret, req.body)` from `@prompt2bot/client`, or the manual verification helper from the auth section. ## set-custom-tools Programmatically configure your bot's tools and skills. Useful for CI/CD pipelines or dynamic tool registration. ### Parameters | Parameter | Type | Description | |-----------|------|-------------| | `secret` | string | Deprecated. Webhook secret for backward-compatible bot auth. Prefer apiToken + botId. | | `apiToken` | string | Your p2b API token (starts with p2b_). Use together with botId. Recommended. | | `botId` | string | Bot ID. Use together with apiToken. Recommended. | | `tools` | array | Custom HTTP tool endpoints the bot can call. Each tool has a name, description, URL, and JSON Schema parameters. | | `skills` | array | Remote skills grouping related tools. Each skill has a name, description, instructions, and an array of tools. | ### Example ```bash curl -X POST https://api.prompt2bot.com/api \ -H "Content-Type: application/json" \ -d '{ "endpoint": "set-custom-tools", "payload": { "apiToken": "p2b_YOUR_API_TOKEN", "botId": "YOUR_BOT_ID", "tools": [ { "name": "lookup_order", "description": "Look up an order by ID", "url": "https://your-server.com/tools/lookup-order", "parameters": { "type": "object", "properties": { "orderId": { "type": "string" } }, "required": [ "orderId" ] } } ], "skills": [ { "name": "crm", "description": "CRM operations", "instructions": "Use to query and update CRM records", "tools": [ { "name": "get_contact", "description": "Fetch CRM contact", "url": "https://your-server.com/tools/crm/get-contact", "parameters": { "type": "object", "properties": { "email": { "type": "string" } }, "required": [ "email" ] } } ] } ] } }' ``` ```typescript import { type RemoteTool, setCustomTools } from "@prompt2bot/client"; const API_TOKEN = Deno.env.get("P2B_API_TOKEN")!; const BOT_ID = Deno.env.get("P2B_BOT_ID")!; const tools: RemoteTool[] = [ { name: "lookup_order", description: "Look up an order by ID", url: "https://your-server.com/tools/lookup-order", parameters: { type: "object", properties: { orderId: { type: "string" } }, required: ["orderId"], }, }, ]; await setCustomTools({ apiToken: API_TOKEN, botId: BOT_ID, tools }); ``` ### Response ```json // Success { "success": true } // Error { "success": false, "error": "string" } ``` ## set-prompt Update your bot's system prompt programmatically. ### Parameters | Parameter | Type | Description | |-----------|------|-------------| | `secret` | string | Deprecated. Webhook secret for backward-compatible bot auth. Prefer apiToken + botId. | | `apiToken` | string | Your p2b API token (starts with p2b_). Use together with botId. Recommended. | | `botId` | string | Bot ID. Use together with apiToken. Recommended. | | `prompt` * | string | | ### Example ```bash curl -X POST https://api.prompt2bot.com/api \ -H "Content-Type: application/json" \ -d '{ "endpoint": "set-prompt", "payload": { "apiToken": "p2b_YOUR_API_TOKEN", "botId": "YOUR_BOT_ID", "prompt": "You are a helpful customer support agent for Acme Inc..." } }' ``` ```typescript import { setPrompt } from "@prompt2bot/client"; await setPrompt({ apiToken: "p2b_YOUR_API_TOKEN", botId: "YOUR_BOT_ID", prompt: "You are a helpful customer support agent for Acme Inc...", }); ``` ### Response ```json // Success { "success": true } // Error { "success": false, "error": "string" } ``` ## create-remote-task Schedule proactive outbound tasks. The bot will execute the described action at the specified time on the chosen messaging network. Unlike `inject-context`, tasks are placed in a background queue, use a "proactive task" prompt framing, and are best for scheduling reminders or initiating new outbound conversations. Omit `preferredNetwork` to run the task in an internal thread. No external message will be sent; the agent processes the description privately and can use tools to act on it. Attachments may be included and will be passed to the agent. ### Parameters | Parameter | Type | Description | |-----------|------|-------------| | `secret` | string | Deprecated. Webhook secret for backward-compatible bot auth. Prefer apiToken + botId. | | `apiToken` | string | Your p2b API token (starts with p2b_). Use together with botId. Recommended. | | `botId` | string | Bot ID. Use together with apiToken. Recommended. | | `creatorContactId` | string | ID of the contact creating the scheduled action. Omit to use the current user's contact. | | `contactId` | string | ID of the contact with whom to interact. Omit if it's for the current user. | | `targetConversationId` | string | Optional explicit target conversation ID override (e.g. a WhatsApp group id that ends with @g.us). | | `description` * | string | Description of what needs to be done, including context of why and who this is for. Formulate as an internal thought. | | `preferredNetwork` | `"alice-and-bot"` \| `"email"` \| `"facebook-messenger"` \| `"slack"` \| `"teams"` \| `"telegram"` \| `"whatsapp"` | Which messaging network to use for the scheduled action, valid options are: alice-and-bot, email, facebook-messenger, slack, teams, telegram, whatsapp. Omit for internal thread (no external message sent). | | `recurrenceRule` | string | Recurrence rule for the scheduled action. Accepts: 'daily', 'weekly', 'monthly', a number (ms), or a full RFC 5545 RRULE string (e.g., 'RRULE:FREQ=DAILY'). Prefer the RRULE format for advanced recurrence. Leave empty for non-recurring tasks. | | `recurrenceEnd` | string | End date/time for recurrence (optional, in local time format). | | `runAt` | number | | | `contactWhatsAppNumber` | string | WhatsApp phone number including country code, digits only (e.g. 972501234567). | | `contactTelegramId` | string | Telegram user ID (numeric string) to message. | | `contactSlackId` | string | Slack user ID or conversation ID to message. | | `contactTeamsId` | string | Microsoft Teams user ID to message. | | `contactAliceAndBotHandle` | string | Alice-and-Bot handle to message (human-friendly alias, no spaces). | | `contactAliceAndBotPublicId` | string | Alice-and-Bot public id (public signing key) to message. | | `contactEmail` | string | Email address of the contact. | | `subject` | string | Email subject line. Required when preferredNetwork is 'email', must not be provided otherwise. | | `attachments` | array | Optional media attachments (images, files, etc.) to include with the task description. Only used when preferredNetwork is omitted (internal thread). | Provide at most one contact identifier (WhatsApp number, handle, public ID, or email). If omitted, the task is created without a specific contact. ### Example — outbound message ```bash curl -X POST https://api.prompt2bot.com/api \ -H "Content-Type: application/json" \ -d '{ "endpoint": "create-remote-task", "payload": { "apiToken": "p2b_YOUR_API_TOKEN", "botId": "YOUR_BOT_ID", "description": "Follow up on invoice #42", "runAt": 1731323400000, "preferredNetwork": "whatsapp", "contactWhatsAppNumber": "972501234567" } }' ``` ```typescript import { createRemoteTask } from "@prompt2bot/client"; await createRemoteTask({ apiToken: "p2b_YOUR_API_TOKEN", botId: "YOUR_BOT_ID", description: "Follow up on invoice #42", runAt": 1731323400000, preferredNetwork: "whatsapp", contactWhatsAppNumber: "972501234567", }); ``` ### Example — internal thread ```typescript import { createRemoteTask } from "@prompt2bot/client"; await createRemoteTask({ apiToken: "p2b_YOUR_API_TOKEN", botId: "YOUR_BOT_ID", description: "Analyze this ticket trade message and record it", attachments: [ { kind: "file", mimeType: "image/jpeg", fileUri: "https://example.com/flyer.jpg", }, ], }); ``` ```typescript import { createRemoteTask } from "@prompt2bot/client"; await createRemoteTask({ apiToken: "p2b_YOUR_API_TOKEN", botId: "YOUR_BOT_ID", description: "Follow up on invoice #42", runAt: 1731323400000, preferredNetwork: "whatsapp", contactWhatsAppNumber: "972501234567", }); ``` ### Response ```json // Success { "success": true, "taskId": "abc123", "runAt": 1731323400000, "message": "Task scheduled" } // Error { "success": false, "error": "string" } ``` ## inject-context Push context into an existing conversation and trigger the agent to act on it. Unlike `create-remote-task`, this bypasses the background queue and executes immediately without any "proactive task" prompt framing, making it ideal for real-time webhook reactions or resolving deferred tools. **Two modes:** By default, context is injected as an internal thought. If you include `toolCallId` and `toolName`, the context is injected as the **tool result** for that specific tool call — this is how [deferred tools](#deferred-async-tools) deliver their results back to the agent. ### Parameters | Parameter | Type | Description | |-----------|------|-------------| | `secret` | string | Deprecated. Webhook secret for backward-compatible bot auth. Prefer apiToken + botId. | | `apiToken` | string | Your p2b API token (starts with p2b_). Use together with botId. Recommended. | | `botId` | string | Bot ID. Use together with apiToken. Recommended. | | `context` * | string | The context string to inject into the conversation as an own_thought. The agent will act on this. | | `toolCallId` | string | If provided, the context is injected as a tool_result instead of own_thought, preventing hallucinations from async tools. | | `preferredNetwork` * | `"alice-and-bot"` \| `"email"` \| `"facebook-messenger"` \| `"slack"` \| `"teams"` \| `"telegram"` \| `"whatsapp"` | Which messaging network the conversation is on, valid options are: alice-and-bot, email, facebook-messenger, slack, teams, telegram, whatsapp | | `targetConversationId` | string | Optional explicit target conversation ID. For WhatsApp groups use the group ID ending with @g.us. | | `contactId` | string | ID of the contact to target. | | `contactWhatsAppNumber` | string | WhatsApp phone number including country code, digits only (e.g. 972501234567). | | `contactTelegramId` | string | Telegram user ID (numeric string) to target. | | `contactSlackId` | string | Slack user ID or conversation ID to target. | | `contactTeamsId` | string | Microsoft Teams user ID to target. | | `contactAliceAndBotHandle` | string | Alice-and-Bot handle to target (human-friendly alias, no spaces). | | `contactAliceAndBotPublicId` | string | Alice-and-Bot public id (public signing key) to target. | | `contactEmail` | string | Email address of the contact. | | `subject` | string | Email subject line. Required when preferredNetwork is 'email', must not be provided otherwise. | | `attachments` | array | Optional media attachments (images, files, etc.) to include with the injected context. Passed through to the agent so it can reason over non-text content. | Provide at most one contact identifier (WhatsApp number, handle, public ID, or email). ### Example — Internal Thought ```bash curl -X POST https://api.prompt2bot.com/api \ -H "Content-Type: application/json" \ -d '{ "endpoint": "inject-context", "payload": { "apiToken": "p2b_YOUR_API_TOKEN", "botId": "YOUR_BOT_ID", "context": "The report generation is 75% complete.", "preferredNetwork": "whatsapp", "contactWhatsAppNumber": "972501234567" } }' ``` ```typescript import { injectContext } from "@prompt2bot/client"; await injectContext({ apiToken: "p2b_YOUR_API_TOKEN", botId: "YOUR_BOT_ID", context: "The report generation is 75% complete.", preferredNetwork: "whatsapp", contactWhatsAppNumber: "972501234567", }); ``` ### Example — Deferred Tool Result Pass `toolCallId` and `toolName` from the original request's `meta` to deliver a tool result instead of an internal thought. ```typescript import { injectContext } from "@prompt2bot/client"; // After async work completes, deliver the tool result: await injectContext({ apiToken: "p2b_YOUR_API_TOKEN", botId: "YOUR_BOT_ID", context: JSON.stringify({ status: "ready", url: "https://..." }), toolCallId: meta.toolCallId, // from the original SignedToolRequest toolName: meta.toolName, // from the original SignedToolRequest preferredNetwork: meta.network, targetConversationId: meta.conversationId, }); ``` ### Response ```json // Success { "success": true } // Error { "success": false, "error": "string" } ``` ## Spinner & Progress Bar The bot can show spinners to give users visual feedback during long operations across all messaging channels (Alice & Bot, Telegram, WhatsApp). When the bot calls `start_spinner`, the tool result includes an `elementId` and an `updateUrl`. Remote tools can use these to stop the spinner directly without going back through the bot. Progress bars are created automatically by remote tools via a dedicated endpoint and updated through the same UI update mechanism. POST to `https://api.prompt2bot.com/ui-update` with a JSON body. No authentication is needed — the `elementId` UUID serves as the access token. ### Update progress bar ```bash curl -X POST https://api.prompt2bot.com/ui-update \ -H "Content-Type: application/json" \ -d '{"elementId":"","percentage":0.75}' ``` ### Stop spinner ```bash curl -X POST https://api.prompt2bot.com/ui-update \ -H "Content-Type: application/json" \ -d '{"elementId":"","active":false}' ``` ### Fields | Field | Type | Description | | ---------- | ------- | ----------------------------------------- | | elementId | string | Required. The UUID from the tool result. | | active | boolean | For spinners. Set to false to stop. | | percentage | number | For progress bars. Value between 0 and 1. | Elements are automatically cleaned up when stopped (spinners) or completed at 100% (progress bars). ### Client Library ```typescript import { createProgressBar, uiUpdate } from "@prompt2bot/client"; // Create a progress bar (from inside a tool handler) const { elementId } = await createProgressBar({ apiToken: API_TOKEN, botId: BOT_ID, conversationId: meta.conversationId, network: meta.network, label: "Processing...", }); // Update progress await uiUpdate({ elementId, percentage: 0.5 }); // Complete await uiUpdate({ elementId, percentage: 1 }); ``` ## create-bot-api Create a new bot programmatically using an API token. Generate API tokens from [Settings](https://prompt2bot.com/settings). The response includes the `botId`, a `chatLink` to talk to the bot, a `conversationsLink` to view its conversations, the `viewChatGroupId` for programmatic conversation access, and the `aliceAndBotPublicId` for messaging the bot via Alice & Bot. Use the `apiToken` and `botId` together for subsequent API calls (set-prompt, set-custom-tools, inject-context, create-remote-task). Optionally pass `skills` (community skill source URLs, validated before creation), `inlineSkills` (custom HTTP tool skills), `secrets` (encrypted and scoped to hostnames), `isolateUsers` (conversation-level isolation, defaults to true), and `enableCodeExecution` (sandbox and VM access, defaults to true) to fully configure the bot in a single call. > This endpoint uses an **API token** (prefixed `p2b_`) instead of a bot secret. > API tokens are scoped to your user account and can create bots on your behalf. ### Parameters | Parameter | Type | Description | |-----------|------|-------------| | `apiToken` * | string | | | `name` * | string | | | `prompt` * | string | | | `inlineSkills` | array | Inline remote skills with custom HTTP tool endpoints. Each skill groups related tools under a name, description, and instructions. | | `skills` | array | Community skill source URLs (npm package names or GitHub URLs pointing to a SKILL.md). Validated before bot creation. | | `secrets` | array | Encrypted secrets scoped to specific hostnames for outbound API access from VMs. | | `isolateUsers` | boolean | When true, each conversation gets its own isolated context — cross-user tools (contacts, active conversations, scheduling, OAuth) are removed and Google OAuth tokens are scoped per-conversation. Defaults to true. | | `enableCodeExecution` | boolean | When true, the bot can run code in sandboxes and create/manage virtual machines. Defaults to true. | | `showToolUseSpinner` | boolean | When true, users see a spinner when tool calls take longer than 5 seconds. Defaults to false. | ### Skill Source Formats The `skills` array accepts community skill sources in these formats: - Tank skill: `tank:` - Example: `tank:weather-forecast` - GitHub repository: `https://github.com//` - Example: `https://github.com/acme/support-agent-skill` - GitHub subpath: `https://github.com///tree//` - Example: `https://github.com/acme/agent-skills/tree/main/skills/support` - npm package (community skill package): package name only - Example: `agent-skill-web-search` Validation behavior: - All entries are validated before bot creation. - Tank skills must exist and pass scan (`pass` or `pass_with_notes`). - GitHub and npm sources must expose a readable `SKILL.md`. ### Example ```bash curl -X POST https://api.prompt2bot.com/api \ -H "Content-Type: application/json" \ -d '{ "endpoint": "create-bot-api", "payload": { "apiToken": "p2b_YOUR_API_TOKEN", "name": "My Support Bot", "prompt": "You are a helpful customer support agent for Acme Inc...", "skills": [ "tank:weather-forecast", "https://github.com/acme/support-agent-skill", "agent-skill-web-search" ], "inlineSkills": [ { "name": "crm", "description": "CRM operations", "instructions": "Use to query and update CRM records", "tools": [ { "name": "get_contact", "description": "Fetch CRM contact by email", "url": "https://your-server.com/tools/crm/get-contact", "parameters": { "type": "object", "properties": { "email": { "type": "string" } }, "required": [ "email" ] } } ] } ], "secrets": [ { "name": "CRM_API_KEY", "value": "sk_live_...", "hosts": [ "api.your-crm.com" ] } ] } }' ``` ```typescript import { createBotApi } from "@prompt2bot/client"; const result = await createBotApi({ apiToken: "p2b_YOUR_API_TOKEN", name: "My Support Bot", prompt: "You are a helpful customer support agent for Acme Inc...", skills: [ "tank:weather-forecast", "https://github.com/acme/support-agent-skill", "agent-skill-web-search", ], inlineSkills: [ { name: "crm", description: "CRM operations", instructions: "Use to query and update CRM records", tools: [ { name: "get_contact", description: "Fetch CRM contact by email", url: "https://your-server.com/tools/crm/get-contact", parameters: { type: "object", properties: { email: { type: "string" } }, required: ["email"], }, }, ], }, ], secrets: [ { name: "crm-api-key", value: "sk_live_...", hosts: ["api.your-crm.com"], }, ], }); if (result.success) { console.log("Bot ID:", result.botId); console.log("Chat:", result.chatLink); console.log("Conversations:", result.conversationsLink); console.log("View Chat Group ID:", result.viewChatGroupId); console.log("Alice & Bot Public ID:", result.aliceAndBotPublicId); } ``` ### Response ```typescript // Success { success: true; botId: string; chatLink: string; conversationsLink: string; viewChatGroupId: string; aliceAndBotPublicId: string; } // Error { success: false; error: string; } ``` ## list-bots List bots you own, with pagination. Generate API tokens from [Settings](https://prompt2bot.com/settings). Each bot in the response includes its `id`, `name`, `chatLink`, and `aliceAndBotPublicId`. Use `nextOffset` to paginate through all bots. > This endpoint uses an **API token** (prefixed `p2b_`) instead of a bot secret. > API tokens are scoped to your user account. ### Parameters | Parameter | Type | Description | |-----------|------|-------------| | `apiToken` * | string | Your p2b_ API token (from Settings). | | `limit` | number | Maximum number of bots to return (1–100, default 50). | | `offset` | number | Number of bots to skip (for pagination, default 0). | ### Example ```bash curl -X POST https://api.prompt2bot.com/api \ -H "Content-Type: application/json" \ -d '{ "endpoint": "list-bots", "payload": { "apiToken": "p2b_YOUR_API_TOKEN", "limit": 10, "offset": 0 } }' ``` ```typescript import { listBots } from "@prompt2bot/client"; const result = await listBots({ apiToken: "p2b_YOUR_API_TOKEN", limit: 10, }); if (result.success) { for (const bot of result.bots) { console.log(bot.name, bot.chatLink); } if (result.nextOffset !== null) { const nextPage = await listBots({ apiToken: "p2b_YOUR_API_TOKEN", limit: 10, offset: result.nextOffset, }); } } ``` ### Response ```typescript // Success { success: true; bots: Array<{ id: string; name: string; chatLink: string; aliceAndBotPublicId: string; }>; nextOffset: number | null; } // Error { success: false; error: string; } ``` ## delete-bot-api Delete a bot you own using an API token. This permanently removes the bot and destroys its associated data, including memory and virtual machines. > This endpoint uses an **API token** (prefixed `p2b_`) instead of a bot secret. > API tokens are scoped to your user account. ### Parameters | Parameter | Type | Description | |-----------|------|-------------| | `apiToken` * | string | Your p2b_ API token (from Settings). | | `botId` * | string | The ID of the bot to delete. | ### Example ```bash curl -X POST https://api.prompt2bot.com/api \ -H "Content-Type: application/json" \ -d '{ "endpoint": "delete-bot-api", "payload": { "apiToken": "p2b_YOUR_API_TOKEN", "botId": "YOUR_BOT_ID" } }' ``` ```typescript import { deleteBotApi } from "@prompt2bot/client"; const result = await deleteBotApi({ apiToken: "p2b_YOUR_API_TOKEN", botId: "YOUR_BOT_ID", }); if (!result.success) { console.error(result.error); } ``` ### Response ```typescript // Success { success: true; } // Error { success: false; error: string; } ``` ## Alice & Bot (Chat Transport) [Alice & Bot](https://alice-and-bot.com) is the default chat transport layer for prompt2bot. It provides end-to-end encrypted messaging with a web chat widget you can embed on any website, plus native apps for iOS and Android. You don't have to use Alice & Bot — prompt2bot works with WhatsApp, Telegram, Facebook Messenger, and email too. But if you want a branded web chat experience, Alice & Bot is the recommended option. ### Web Embed Widget Add a chat widget to your website with a single script tag. Configure it from your bot's dashboard under **Integrations → Web Embed**, or use the `@alice-and-bot/core` npm package directly. The widget supports: - Light and dark mode with customizable colors - Custom button text and initial messages - Auto-open on page load - User name pre-fill ### Links - **Website:** [alice-and-bot.com](https://alice-and-bot.com) - **NPM package:** [@alice-and-bot/core](https://jsr.io/@alice-and-bot/core) - **GitHub:** [github.com/uriva/alice-and-bot](https://github.com/uriva/alice-and-bot) ## Abilities A partial list of built-in agent capabilities: - Send messages to admins - Search the web - Manage WhatsApp groups - Read and edit Google Spreadsheets and Docs - Read conversations with other users - Schedule tasks - Manage an address book - Get available slots from Calendly - Search Google Calendar events - Remember certain facts - Store internal reasoning - Get coordinates for locations - Query a personal Google Map - Read a web page - Shopify integration - Query LinkedIn profiles - Search Facebook posts ## create-guest Create a guest user programmatically. Returns a long-lived `p2b_` API token for subsequent API calls (like `create-bot-api`) and the user's `aliceAndBotCredentials` for building a chat UI with [Alice & Bot](https://alice-and-bot.com). No authentication required. Pass an optional `attribution` tag to track which platform created the guest. ### Parameters | Parameter | Type | Description | |-----------|------|-------------| | `attribution` | string | Attribution tag identifying the 3rd-party platform that created this guest (e.g. 'my-skill-marketplace'). | ### Example ```bash curl -X POST https://api.prompt2bot.com/api \ -H "Content-Type: application/json" \ -d '{ "endpoint": "create-guest", "payload": { "attribution": "my-skill-marketplace" } }' ``` ```typescript import { createGuest } from "@prompt2bot/client"; const result = await createGuest({ attribution: "my-skill-marketplace" }); if (result.success) { console.log("API Token:", result.token); console.log("Public Key:", result.aliceAndBotCredentials.publicSignKey); } ``` ### Response ```typescript // Success { success: true; token: string; // p2b_ API token — store securely, does not expire aliceAndBotCredentials: { publicSignKey: string; // public identity, used for chat links privateSignKey: string; // signs outgoing messages privateEncryptKey: string; // decrypts conversation keys } } // Error { success: false; error: string; } ``` ## login-with-token Exchange a `p2b_` API token for a fresh InstantDB refresh token. The refresh token can be used with `auth.signInWithToken()` on the prompt2bot frontend to sign the user into their dashboard. No authentication required — the `p2b_` token in the payload serves as the credential. ### Parameters | Parameter | Type | Description | |-----------|------|-------------| | `token` * | string | The p2b_ API token for the guest user. | ### Example ```bash curl -X POST https://api.prompt2bot.com/api \ -H "Content-Type: application/json" \ -d '{ "endpoint": "login-with-token", "payload": { "token": "p2b_YOUR_API_TOKEN" } }' ``` ```typescript import { loginWithToken } from "@prompt2bot/client"; const result = await loginWithToken({ token: "p2b_YOUR_API_TOKEN" }); if (result.success) { // Redirect user to prompt2bot with the refresh token window.location.href = `https://prompt2bot.com/bots?token=${ encodeURIComponent(result.refreshToken) }`; } ``` ### Response ```typescript // Success { success: true; refreshToken: string; // pass to auth.signInWithToken() or as ?token= URL param } // Error { success: false; error: string; } ``` ## 3rd Party Integration Build a skill marketplace, SaaS integration, or any platform that creates and manages prompt2bot bots on behalf of your users. Three API endpoints handle the full lifecycle: user creation, bot provisioning, and dashboard access. ### Overview Your platform acts as the orchestrator. You create guest accounts for your users, provision bots with specific prompts and tools, and optionally let users configure their bots directly in the prompt2bot dashboard. The chat UI is powered by [Alice & Bot](https://alice-and-bot.com), which provides end-to-end encrypted messaging with embeddable web widgets and native mobile apps. ### Step 1: Create a guest user Call `create-guest` to provision a new user. Store the returned `p2b_` API token securely on your backend — it's the long-lived credential for all subsequent API calls on behalf of this user. The `attribution` field tags the user as coming from your platform. ```bash curl -X POST https://api.prompt2bot.com/api \ -H "Content-Type: application/json" \ -d '{ "endpoint": "create-guest", "payload": { "attribution": "acme-marketplace" } }' ``` The response includes `aliceAndBotCredentials` — the keypair needed to build a chat interface using the `@alice-and-bot/core` library. Store the full credentials object alongside the API token. ### Step 2: Create bots for the user Use `create-bot-api` with the guest's `p2b_` token to create bots. Each bot gets its own prompt, tools, skills, and secrets. ```bash curl -X POST https://api.prompt2bot.com/api \ -H "Content-Type: application/json" \ -d '{ "endpoint": "create-bot-api", "payload": { "apiToken": "p2b_THE_GUEST_TOKEN", "name": "Support Bot", "prompt": "You are a support agent for Acme Corp...", "skills": ["agent-skill-web-search"] } }' ``` The response includes `chatLink` (a direct URL to chat with the bot), `aliceAndBotPublicId` (the bot's public key for embedding), and `botId`. Use the `apiToken` and `botId` together for further API calls like `set-prompt` or `set-custom-tools`. `skills` supports multiple source formats: - Tank: `tank:` (example: `tank:weather-forecast`) - GitHub repo URL (example: `https://github.com/acme/support-agent-skill`) - GitHub subpath URL (example: `https://github.com/acme/agent-skills/tree/main/skills/support`) - npm package name (example: `agent-skill-web-search`) For full details, see [create-bot-api](./11-create-bot-api.md). If your platform will receive signed tool calls or recorder webhooks, call `rotate-webhook-secret` once after bot creation and store the returned `webhookSecret` on your side. That secret is only for verifying signed webhook requests. ### Step 3: Build the chat UI Use [Alice & Bot](https://alice-and-bot.com) to embed a chat widget on your platform. The `@alice-and-bot/core` package handles end-to-end encryption, message delivery, and real-time updates. You need two pieces from the previous steps: - The user's `aliceAndBotCredentials` (from `create-guest`) - The bot's `aliceAndBotPublicId` (from `create-bot-api`) Alice & Bot provides a web embed widget, React components, and native iOS and Android apps. See the [Alice & Bot docs](https://alice-and-bot.com) for integration details. ### Step 4: Let users configure their bot When a user wants to tweak their bot's prompt, tools, or settings directly in the prompt2bot dashboard, call `login-with-token` with their stored `p2b_` token to get a fresh session token, then redirect them. ```typescript const result = await fetch("https://api.prompt2bot.com/api", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ endpoint: "login-with-token", payload: { token: storedP2bToken }, }), }).then((r) => r.json()); if (result.success) { // Redirect to prompt2bot dashboard — auto-signs in via ?token= param window.location.href = `https://prompt2bot.com/bots?token=${ encodeURIComponent(result.refreshToken) }`; } ``` The `?token=` parameter triggers automatic sign-in on the prompt2bot frontend. The user lands on their bot dashboard, fully authenticated, ready to configure. ### Token lifecycle | Token | Purpose | Lifetime | Storage | | ------------------------ | -------------------------- | -------------------------------- | ----------------------------------------- | | `p2b_` API token | Server-to-server API calls | Does not expire | Your backend (treat as secret) | | InstantDB refresh token | Browser sign-in | Short-lived, generated on demand | Ephemeral (pass to frontend, don't store) | | `aliceAndBotCredentials` | Chat encryption keys | Does not expire | Your backend (treat as secret) | The `p2b_` token is the single long-lived credential you store. Whenever the user needs browser access, call `login-with-token` to generate a fresh session token. This way you never worry about token expiration. ### Full flow diagram ``` Your Platform prompt2bot API prompt2bot Dashboard | | | |-- create-guest ------------->| | |<-- p2b_ token + credentials -| | | | | |-- create-bot-api ----------->| | |<-- botId, chatLink, etc. ----| | | | | | (user wants to configure) | | |-- login-with-token --------->| | |<-- refreshToken -------------| | | | | |-- redirect user w/ ?token= -------------------------------->| | | (auto sign-in, bot config) ``` ## set-supergreen-whatsapp Connect a [Supergreen](https://supergreen.cc) WhatsApp line to your bot. This sets up the webhook so incoming WhatsApp messages are forwarded to your bot. ### Parameters | Parameter | Type | Description | |-----------|------|-------------| | `secret` | string | Deprecated. Webhook secret for backward-compatible bot auth. Prefer apiToken + botId. | | `apiToken` | string | Your p2b API token (starts with p2b_). Use together with botId. Recommended. | | `botId` | string | Bot ID. Use together with apiToken. Recommended. | | `whatsappNumber` * | string | The WhatsApp number from your Supergreen account (digits only) | | `secretToken` * | string | The secret token from your Supergreen account | ### Example ```bash curl -X POST https://api.prompt2bot.com/api \ -H "Content-Type: application/json" \ -d '{ "endpoint": "set-supergreen-whatsapp", "payload": { "apiToken": "p2b_YOUR_API_TOKEN", "botId": "YOUR_BOT_ID", "whatsappNumber": "14155551234", "secretToken": "YOUR_SUPERGREEN_SECRET_TOKEN" } }' ``` ```typescript import { setSupergreenWhatsapp } from "@prompt2bot/client"; await setSupergreenWhatsapp({ apiToken: "p2b_YOUR_API_TOKEN", botId: "YOUR_BOT_ID", whatsappNumber: "14155551234", secretToken: "YOUR_SUPERGREEN_SECRET_TOKEN", }); ``` ### Response ```json // Success { "success": true } // Error { "success": false, "error": "string" } ``` ## rotate-webhook-secret Generates a new webhook signing secret for a bot and returns it once. Use this for programmatic provisioning or rotation of custom tool / recorder webhook verification. Authentication: - Either a bot auth pair: `apiToken` + `botId` - Or the deprecated `secret` Input schema: | Parameter | Type | Description | |-----------|------|-------------| | `secret` | string | Deprecated. Webhook secret for backward-compatible bot auth. Prefer apiToken + botId. | | `apiToken` | string | Your p2b API token (starts with p2b_). Use together with botId. Recommended. | | `botId` | string | Bot ID. Use together with apiToken. Recommended. | Example: ```bash curl -X POST https://api.prompt2bot.com/api \ -H 'Content-Type: application/json' \ -d '{ "endpoint": "rotate-webhook-secret", "payload": { "apiToken": "p2b_your_bot_or_user_token", "botId": "your-bot-id" } }' ``` Successful response: ```json { "success": true, "webhookSecret": "b6d7d7d4-0b66-4a44-b4af-0be27c8b7c87" } ```