Skip to content

Embed API

The Embed API is the client-side JavaScript interface for apps running inside Poe canvas frames. It provides store initialization, data access, bot interaction, and permissions — all from your app's frontend code.

Poe Employee Note

Currently the platform injects an import map into the app's index.html at serve time, which is what makes import { Poe } from "poe-apps-sdk/embed-api/v1.js" work without a bundler. In the future we'll probably want creators to include a script tag instead (e.g. <script src="https://poe.com/v1/embed-api.js"></script>) so the mechanism is more explicit and doesn't require server-side HTML rewriting.

Core APIs

Poe.setupStore()

Initialize a synced store inside your app.

javascript
async function addTodo(ctx, input) {
  await ctx
    .table("todos")
    .set({ itemKey: input.id, value: { text: input.text, done: false } });
}

const client = Poe.setupStore({ mutators: { addTodo }, schemaVersion: 1 });

Poe.store

A SyncedStoreClient reference. Available after calling setupStore().

Poe.stream()

Stream a response from a Poe bot. Returns an async iterator that yields partial message chunks as they arrive.

javascript
for await (const chunk of Poe.stream({
  botName: "Claude-3.5-Sonnet",
  prompts: "What is the capital of France?",
})) {
  console.log(chunk.text);
}

prompts can be a string, a single message object { role, content }, or an array of either.

Poe Employee Note

Poe.stream() is not thoroughly tested outside of unit tests and may have rough edges.

Poe.call()

Call a bot with automatic tool execution. Like stream(), but runs an agentic loop — when the bot emits tool calls, they are executed automatically and the results are fed back until the bot produces a final response.

javascript
const weatherTool = Poe.createTool({
  name: "get_weather",
  description: "Get current weather for a city",
  parameters: {
    type: "object",
    properties: { city: { type: "string" } },
    required: ["city"],
  },
  run: async ({ city }) => `Weather in ${city}: 72F sunny`,
});

for await (const event of Poe.call({
  botName: "GPT-4o",
  prompts: "What's the weather in Tokyo?",
  tools: [weatherTool],
  maxIterations: 10, // default
})) {
  console.log(event.text);
}

Poe Employee Note

Poe.call() is not thoroughly tested outside of unit tests and may have rough edges.

Poe.createTool()

Create an executable tool definition for use with Poe.call(). Tools define a JSON Schema for their parameters and a run function that returns a string result.

javascript
const calculator = Poe.createTool({
  name: "calculate",
  description: "Evaluate a math expression",
  parameters: {
    type: "object",
    properties: { expression: { type: "string" } },
    required: ["expression"],
  },
  run: async ({ expression }) => String(eval(expression)),
});

Poe Employee Note

Poe.createTool() is not thoroughly tested outside of unit tests and may have rough edges.

Poe.listModels()

List all available Poe models. Returns an array of Model objects with metadata like id, description, owned_by, architecture, pricing, and context_window.

javascript
const models = await Poe.listModels();
console.log(models.map(m => m.id)); // ["Claude-3.5-Sonnet", "GPT-4o", ...]

Use this to discover valid bot names for Poe.stream() / Poe.call(), or to build a model picker UI.

Permissions

Request and check permissions from the host application. The host shows consent UI when permissions haven't been granted yet.

Poe.permissions.request(scope)

Request one or more permission scopes. Accepts a single scope string or an array of scopes. Shows consent UI if not already granted. Always returns { granted: string[], denied: string[], error?: string }.

javascript
// Single scope
const { granted, denied } = await Poe.permissions.request("google_drive.read");
if (granted.includes("google_drive.read")) {
  Poe.store.mutate.continueMessage({
    messageId: messageThatRequestedGoogleDriveAccess,
  });
}

// Multiple scopes
const result = await Poe.permissions.request([
  "google_drive.read",
  "github.read",
]);
// result.granted: ["google_drive.read"], result.denied: ["github.read"]

Poe.permissions.check(scope)

Check whether a permission is granted without showing any UI.

javascript
const { granted } = await Poe.permissions.check("google_drive.read");

Poe Employee Note

The permissions API is still in progress. It is not thoroughly tested outside of unit tests and the set of available permission scopes is not yet finalized.

No-Build vs Bundled

No-BuildBundled
Importpoe-apps-sdk/embed-api/v1.jspoe-apps-sdk/embed-api/v1.js
SchemaInline mutatorsdefineSchema() + defineClientConfig()
Config{ mutators, schemaVersion }Pre-built client config object
TypesNone (plain JS)Full type inference from Zod schema