Persona

Build your own chat UI

Prefer your own interface? Use the same API the widget uses. You still create sessions on your server (or anonymous sessions from your page); your front end then calls the chat endpoint directly. Your origin must be on your Allowed sites so the browser's CORS check passes.

Stream a reply

POST /api/v1/chat?client_id=cli_…

Include client_id in the URL when calling from a browser: the CORS preflight carries no token, so that's how we know which allowed sites to check.

Authorization: Bearer cs_…
Content-Type: application/json

{
  "id": "a-conversation-id",           // 8-64 chars [A-Za-z0-9_-], one per thread
  "messages": [
    { "id": "m1", "role": "user", "parts": [{ "type": "text", "text": "Where should I start?" }] }
  ]
}

Send the whole thread each time (the last 30 messages are used). The response is a Vercel AI SDK UI message stream (server-sent events). The first event carries the sources the reply may cite:

data: {"type":"start","messageMetadata":{"sources":[{"n":1,"title":"Risk management","origin":null}]}}
data: {"type":"text-delta","id":"…","delta":"Never risk more than 1%"}
…
data: {"type":"finish"}

Replies cite sources as [1], [2], matching sources[].n. When the persona recommends an offer you'll see a tool-recommend_offer part with output.offer (title, url, price_label, pitch).

With the AI SDK (React)

import { useChat } from "@ai-sdk/react";
import { DefaultChatTransport } from "ai";

const { messages, sendMessage } = useChat({
  transport: new DefaultChatTransport({
    api: "https://persona.ignited.tools/api/v1/chat?client_id=cli_YOUR_ID",
    headers: () => ({ Authorization: `Bearer ${sessionToken}` }),
  }),
});

useChat sends id and messages in the right shape and parses the stream. When a call returns 401 invalid_session, get a new session and retry.