Agents SDK

Chat

SSE streaming chat endpoint with AI SDK compatibility. Send messages and receive streaming responses.

Send Message

POSThttps://relay.an.dev/v1/chat/:slug

Sends a message to the agent and returns an SSE stream of the response.

Path Parameters

NameTypeRequiredDescription
slugstringRequiredAgent slug

Request Body

NameTypeRequiredDescription
messagesMessage[]RequiredAI SDK-style message array. The relay uses the last user message as the next turn.
sandboxIdstringRequiredSandbox ID returned by your server, for example the id from POST /v1/sandboxes
threadIdstringOptionalThread ID to continue. If omitted, the latest thread in the sandbox is reused or created if none exists
optionsobjectOptionalPer-request runtime overrides
options.systemPromptobjectOptionalSystem prompt override (type, preset, append)
options.maxTurnsnumberOptionalMaximum number of agent turns
options.maxBudgetUsdnumberOptionalMaximum cost in USD for this request
options.disallowedToolsstring[]OptionalTools the agent cannot use

sandboxId + threadId: continue a specific thread in that sandbox.

sandboxId only: reuse the latest thread in the sandbox. If none exists yet, a new thread is created.

Need a fresh conversation in the same sandbox: create a new thread explicitly via /v1/sandboxes/:id/threads and send that threadId.

No sandboxId: returns a 400 error.

History persistence: the relay appends only the new turn to stored thread history. It does not replace thread history with the full request body.

Request Body
{
  "sandboxId": "uuid-of-existing-sandbox",
  "options": {
    "systemPrompt": {
      "type": "preset",
      "preset": "claude_code",
      "append": "Focus on regressions, risky edge cases, and missing tests. Do not edit files."
    },
    "maxTurns": 4,
    "maxBudgetUsd": 0.2,
    "disallowedTools": ["Bash"]
  },
  "messages": [
    {
      "id": "msg-1",
      "role": "user",
      "parts": [{ "type": "text", "text": "Your message" }]
    }
  ]
}
cURL
curl -N -X POST https://relay.an.dev/v1/chat/YOUR_AGENT_SLUG \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sandboxId": "uuid-of-existing-sandbox",
    "messages": [{
      "id": "msg-1",
      "role": "user",
      "parts": [{ "type": "text", "text": "Hello" }]
    }]
  }'

SSE Response Format

The response is a Server-Sent Events stream. Each event is a JSON object prefixed with data: . The stream ends with data: [DONE].

data: {"type":"start"}
data: {"type":"text-start","id":"..."}
data: {"type":"text-delta","id":"...","delta":"Hello world"}
data: {"type":"text-end","id":"..."}
data: {"type":"message-metadata","messageMetadata":{
  "sessionId":"...",
  "totalCostUsd":0.034,
  "inputTokens":3,
  "outputTokens":5,
  "durationMs":2487
}}
data: {"type":"finish"}
data: [DONE]

Resume Stream

GEThttps://relay.an.dev/v1/chat/:slug/:sandboxId/stream

Reconnect to an active SSE stream for a sandbox. Use this when a client connection drops and you need to resume receiving events.

Path Parameters

NameTypeRequiredDescription
slugstringRequiredAgent slug
sandboxIdstringRequiredSandbox ID

Cancel Stream

DELETEhttps://relay.an.dev/v1/chat/:slug/:sandboxId/stream

Cancel an active stream. Use this for deterministic server-side cancellation.

Path Parameters

NameTypeRequiredDescription
slugstringRequiredAgent slug
sandboxIdstringRequiredSandbox ID

Returns 204 No Content on success.

React (AI SDK)

Direct usage with AI SDK — useful for custom transports or non-Next.js frameworks.

agent-chat.tsx
import { Chat, DefaultChatTransport } from "ai"
import { useChat } from "@ai-sdk/react"

const sandboxId = "sb_abc123" // Use the sandbox ID returned by your server

const chat = new Chat({
  transport: new DefaultChatTransport({
    api: "https://relay.an.dev/v1/chat/YOUR_AGENT_SLUG",
    headers: async () => ({
      Authorization: "Bearer YOUR_API_KEY",
    }),
    body: {
      sandboxId,
      // threadId: "uuid-of-existing-thread",
    },
  }),
})

export function AgentChat() {
  const { messages, sendMessage } = useChat({ chat })

  return (
    <div>
      {messages.map((m) => <div key={m.id}>{m.content}</div>)}
      <button onClick={() => sendMessage({ text: "Hello" })}>
        Send
      </button>
    </div>
  )
}

SDK Integration

For the recommended approach using @21st-sdk/nextjs with server-side token exchange, see the Get Started guide. For server-side sandbox and thread management, see the Server SDK page.