API ReferenceOverview

Introduction

Start conversations with your agents and exchange messages from your own website or backend.

The Dispatch API lets your website talk to a live agent: start a conversation, send the visitor's messages, and show the agent's replies as they are written.

Base URL

https://api.rundispatch.ai/v1

Every request and response body is JSON, except replies to a message when you ask for another reply type: Server-Sent Events, Markdown or plain text.

Authentication

The API uses two kinds of credentials, both sent as a bearer token:

Authorization: Bearer <credential>
CredentialWhat it isUsed for
API keyYour Dispatch API key. It only allows starting conversations with the agents you chose.Starting a conversation, Getting a conversation
Participant tokenThe visitor's token. Returned when you start or get a conversation, and works in every conversation the visitor takes part in for 90 days.Sending a message, Listing messages

To get an API key, contact the Dispatch team. Tell us which agents it should be able to start conversations with.

Your API key is visible

If you call the API from the visitor's browser, the API key is visible in your page's source. That is expected: it can only start conversations with the agents it allows. Keep each participant's token to that visitor.

The typical flow

Start a conversation with POST /agents/{agent}/conversations, using your API key. Send what you know about the visitor in user, and anything the agent should know in context.

Keep the token. The response's _embedded.participants[0] is the visitor. Store its token: it works in every conversation that visitor takes part in, until token_expires_at (90 days). A visitor you start another conversation for with the same email keeps the same token, unless it expires within 7 days: then they get a new one.

Send messages with POST /conversations/{conversation}/messages and the visitor's token. The Accept header picks the reply type; text/event-stream streams it back as it is written.

Show the history with GET /conversations/{conversation}/messages, newest first, for example when the visitor comes back.

Lost a token, or is it about to expire? Get the conversation again with the API key that started it. From 7 days before token_expires_at, even once it has passed, that returns a new token.

Responses carry _links: absolute URLs for what you can do next, such as list_messages and send_message on a conversation.

Reply types

Sending a message returns the agent's reply in the type the Accept header asks for:

AcceptReply
application/json (or none)All at once, as JSON: data.markdown, the files the agent shared in data.attachments, and the web pages it cited in data.citations (each {url, title}, title may be null; empty when the agent's Show sources is off).
text/event-streamStreamed as it is written.
text/markdownAll at once, as Markdown. Shared files appear as images or links where they were written.
text/plainAll at once, as plain text without Markdown, for places such as SMS. The agent shares no files.

Any other type returns 406.

Streaming replies

A streamed reply is a series of data: lines, each holding one JSON event, ending with data: [DONE]. Append the delta of each text_delta event to show the reply as it is written:

const response = await fetch(conversation._links.send_message.href, {
    method: 'POST',
    headers: {
        Authorization: `Bearer ${participant.token}`,
        Accept: 'text/event-stream',
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({ content: 'Do you deliver on Sundays?' }),
});

const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
let buffer = '';
let reply = '';

while (true) {
    const { value, done } = await reader.read();
    if (done) break;

    buffer += value;
    const lines = buffer.split('\n');
    buffer = lines.pop();

    for (const line of lines) {
        if (!line.startsWith('data: ')) continue;
        const data = line.slice('data: '.length);
        if (data === '[DONE]') break;

        const event = JSON.parse(data);
        if (event.type === 'text_delta') reply += event.delta; // render `reply` here
    }
}

An embed_file event is a file the agent shared, with its name, mime_type and url. Ignore event types you don't use; new ones may be added.

Errors

Errors return a JSON body with a message:

{ "message": "This agent is not live." }
StatusMeaning
401The credential is missing or not valid, or the token has expired.
403The agent is in draft ("This agent is not live."), the API key doesn't allow this agent, or the token's visitor doesn't take part in the conversation.
404The agent or conversation doesn't exist, or your credential can't see it.
406The Accept header asks for no reply type the API returns.
422The request is not valid. errors lists the messages for each field: { "message": "…", "errors": { "content": ["…"] } }
429Too many requests. Wait for the Retry-After seconds and try again.
502The agent could not reply (any reply type but streaming). Your message was saved.

Rate limits

Each IP address can make 60 requests per minute. Past that, requests return 429 until the minute is up.

OpenAPI

The full API is described in openapi.yaml, which you can load into a code generator. To try the API in Postman, Insomnia or Bruno, download the collection.

On this page