> ## Documentation Index
> Fetch the complete documentation index at: https://ago.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# SDK API

> Build custom chat experiences with the AGO SDK API

The SDK API lets you build custom chat interfaces on top of AGO. Use it to manage conversations, send and receive messages, create tickets, and retrieve workspace configuration from your own application.

## Base URL

```
https://your-instance.useago.com/api/sdk/v1/
```

All endpoint paths below are relative to this base URL.

## Authentication

The SDK API uses the same authentication as the embedded widget. Requests are authorized by the `X-User-Anon-Id` header and validated against your allowed domains list, which you configure in [Widget & SDK Configuration](/features/sdk-integration).

Include these headers in every request:

```bash theme={null}
curl https://your-instance.useago.com/api/sdk/v1/conversations \
  -H "X-User-Anon-Id: unique_user_id" \
  -H "Origin: https://your-app.com"
```

| Header                | Required | Description                                                                                    |
| --------------------- | -------- | ---------------------------------------------------------------------------------------------- |
| `X-User-Anon-Id`      | Yes\*    | A unique identifier for the current user. `X-Widget-Id` is the legacy name and still accepted. |
| `Origin`              | No       | The origin domain of your application (validated against allowed domains)                      |
| `Authorization`       | No       | `Bearer {jwt}` for authenticated users                                                         |
| `X-Widget-Email`      | No       | User email (when not using JWT)                                                                |
| `X-Widget-Permission` | No       | Permission override for the user                                                               |

\*When you send a JWT in the `Authorization` header, `X-User-Anon-Id` can be omitted: the user identity is taken from the token's `sub` claim.

```bash theme={null}
# JWT-only request — no X-User-Anon-Id needed
curl https://your-instance.useago.com/api/sdk/v1/conversations \
  -H "Authorization: Bearer eyJhbGciOi..." \
  -H "Origin: https://your-app.com"
```

***

## Conversations

### List Conversations

```
GET /conversations
```

Returns a paginated list of the authenticated user's conversations.

**Query parameters:**

| Parameter   | Type    | Default | Description              |
| ----------- | ------- | ------- | ------------------------ |
| `page`      | integer | `1`     | Page number              |
| `page_size` | integer | `50`    | Number of items per page |

**Example request:**

```bash theme={null}
curl "https://your-instance.useago.com/api/sdk/v1/conversations?page=1&page_size=20" \
  -H "X-User-Anon-Id: unique_user_id"
```

**Example response:**

```json theme={null}
{
  "object": "list",
  "data": [
    {
      "object": "conversation",
      "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
      "title": "Help with billing",
      "created_at": "2025-01-15T10:30:00Z",
      "last_message_at": "2025-01-15T11:00:00Z"
    }
  ],
  "has_more": false,
  "total": 1
}
```

### Get Unread Count

```
GET /conversations/unread
```

Returns the number of unread conversations and the ID of the most recent unread conversation.

**Example request:**

```bash theme={null}
curl "https://your-instance.useago.com/api/sdk/v1/conversations/unread" \
  -H "X-User-Anon-Id: unique_user_id"
```

**Example response:**

```json theme={null}
{
  "unread_count": 3,
  "last_unread_conversation_id": "a1b2c3d4-5678-90ab-cdef-1234567890ab"
}
```

### Get Conversation

```
GET /conversations/{conversation_id}
```

Returns a single conversation with all its messages.

**Path parameters:**

| Parameter         | Type          | Description         |
| ----------------- | ------------- | ------------------- |
| `conversation_id` | string (UUID) | The conversation ID |

**Example request:**

```bash theme={null}
curl "https://your-instance.useago.com/api/sdk/v1/conversations/a1b2c3d4-5678-90ab-cdef-1234567890ab" \
  -H "X-User-Anon-Id: unique_user_id"
```

**Example response:**

```json theme={null}
{
  "object": "conversation",
  "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
  "title": "Help with billing",
  "created_at": "2025-01-15T10:30:00Z",
  "last_message_at": "2025-01-15T11:00:00Z",
  "messages": [
    {
      "object": "message",
      "id": "f1e2d3c4-5678-90ab-cdef-abcdefabcdef",
      "content": "Hello, I need help with my invoice.",
      "role": "user",
      "created_at": "2025-01-15T10:30:00Z",
      "agent": null,
      "sources": [],
      "attachments": [],
      "tool_call_data": []
    },
    {
      "object": "message",
      "id": "b9a8c7d6-5432-10fe-dcba-abcdefabcdef",
      "content": "I found your invoice. Here is the current status.",
      "role": "assistant",
      "created_at": "2025-01-15T10:30:05Z",
      "agent": {
        "id": "e5f6a7b8-1234-5678-9abc-def012345678",
        "name": "Billing Agent"
      },
      "sources": [
        {
          "id": "c1d2e3f4-0000-1111-2222-333344445555",
          "title": "Invoice FAQ",
          "url": "https://help.example.com/invoices"
        }
      ],
      "attachments": [
        {
          "id": "d4e5f6a7-1111-2222-3333-444455556666",
          "name": "invoice_guide.pdf",
          "content_type": "application/pdf",
          "file_size": 204800,
          "file_url": "https://your-instance.useago.com/files/d4e5f6a7.pdf"
        }
      ],
      "tool_call_data": [
        {
          "tool_call_data": true,
          "id": "a7b8c9d0-1111-2222-3333-444455556666",
          "status": "done",
          "tool_name": "lookup_invoice",
          "tool_display_name": "Look up invoice",
          "thread": { "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab" },
          "type": "status_message",
          "message": "Invoice #4521 — paid",
          "result": { "message": "Invoice #4521 — paid" },
          "variant": "success"
        }
      ]
    }
  ]
}
```

Each message includes a `tool_call_data` array listing the tool calls the agent
made while producing that message, in the order they ran. The array is empty
when no tool was used. Each entry carries the tool's `status`, `tool_name`, a
display name, and a `type` that tells your interface how to render it (for
example `status_message`, `progress_indicator`, `confirmation_input`, or
`form`). Calls to your own client-side functions also include an `arguments`
object with the values the function was called with, so you can show what ran.
This is the same shape used by the built-in chat interface, so you can replay a
past conversation — including its tool calls — in a custom UI.

***

## Messages

### Send Message

```
POST /messages
```

Sends a message and returns a streaming response using [Server-Sent Events (SSE)](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events).

<Note>
  This endpoint returns a `text/event-stream` response. You need an SSE-compatible client to consume the stream. If the stream disconnects, use the [Get Message Status](#get-message-status) endpoint to poll for the final result.
</Note>

**JSON request body:**

| Field                   | Type          | Required | Description                                                                                                                                                                                                                                                                                                                                                                  |
| ----------------------- | ------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `content`               | string        | Yes      | The message text                                                                                                                                                                                                                                                                                                                                                             |
| `conversation_id`       | string (UUID) | No       | ID of an existing conversation. Omit to start a new one.                                                                                                                                                                                                                                                                                                                     |
| `agent_id`              | string (UUID) | No       | Target a specific agent                                                                                                                                                                                                                                                                                                                                                      |
| `client_functions`      | array         | No       | Client-side function definitions the agent can call                                                                                                                                                                                                                                                                                                                          |
| `client_functions_mode` | string        | No       | How the agent handles client function calls: `placeholder` (default) or `pause`. See [Continue Message](#continue-message).                                                                                                                                                                                                                                                  |
| `metadata`              | object        | No       | Arbitrary key-value metadata to attach to the message                                                                                                                                                                                                                                                                                                                        |
| `hidden`                | boolean       | No       | Mark the message as an event sent by your application code, not typed by the user (for example "the user completed the payment"). The agent reads it and replies as usual, but the message is stored and returned with `role: "system"` so your interface can skip rendering it as a user bubble. Requires `conversation_id` — a hidden message cannot start a conversation. |

**Example request (JSON):**

```bash theme={null}
curl -N "https://your-instance.useago.com/api/sdk/v1/messages" \
  -H "X-User-Anon-Id: unique_user_id" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "How do I update my payment method?",
    "conversation_id": "a1b2c3d4-5678-90ab-cdef-1234567890ab"
  }'
```

**File uploads:** To attach files, send the request as `multipart/form-data` with `content`, `conversation_id`, and `agent_id` as form fields and `files` for file attachments.

```bash theme={null}
curl -N "https://your-instance.useago.com/api/sdk/v1/messages" \
  -H "X-User-Anon-Id: unique_user_id" \
  -F "content=Here is the screenshot of the error" \
  -F "conversation_id=a1b2c3d4-5678-90ab-cdef-1234567890ab" \
  -F "files=@screenshot.png"
```

**Response:** The response is a `text/event-stream`. Each event is a line of text prefixed with `data: `.

### Continue Message

```
POST /messages/{message_id}/continue
```

Resumes an agent turn that paused on client function calls. Only relevant when
you send messages with `client_functions_mode: "pause"`.

The two modes differ in when the agent sees your function results:

* **`placeholder`** (default): when the agent calls one of your client
  functions, the turn continues immediately without the result. The result you
  submit is only visible to the agent on the next message.
* **`pause`**: the turn stops when the agent calls your client function(s).
  The SSE stream ends with a `status: "WAITING_CLIENT"` event that lists
  `waiting_tool_call_ids`. Execute each function, submit its result via
  `POST /tool-calls/{id}/submit` (body: `{"formData": {...}}`), then call this
  endpoint. The agent continues the same turn with the real results — useful
  when a function changes what the agent should do next (for example a page
  navigation followed by filling the destination page).

The pause survives page reloads: reload the conversation with
[Get Conversation](#get-conversation), look for an assistant message with
`status: "WAITING_CLIENT"` and tool calls in `waiting_input` status, then
submit and continue as usual.

**Path parameters:**

| Parameter    | Type          | Description                                                       |
| ------------ | ------------- | ----------------------------------------------------------------- |
| `message_id` | string (UUID) | The paused assistant message ID (from the `WAITING_CLIENT` event) |

**JSON request body:**

| Field              | Type   | Required | Description                                                                         |
| ------------------ | ------ | -------- | ----------------------------------------------------------------------------------- |
| `client_functions` | array  | No       | The CURRENT page's function definitions (the page may have changed since the pause) |
| `client_context`   | object | No       | Fresh client context snapshot                                                       |

**Example flow:**

```bash theme={null}
# 1. The submit response tells you when the turn is ready to resume
curl "https://your-instance.useago.com/api/sdk/v1/tool-calls/{tool_call_id}/submit" \
  -H "X-User-Anon-Id: unique_user_id" \
  -H "Content-Type: application/json" \
  -d '{"formData": {"navigated": true}}'
# -> {"status": "completed", "result": {...}, "resume": {"message_id": "...", "ready": true}}

# 2. Once ready, resume the turn (returns a new SSE stream)
curl -N "https://your-instance.useago.com/api/sdk/v1/messages/{message_id}/continue" \
  -H "X-User-Anon-Id: unique_user_id" \
  -H "Content-Type: application/json" \
  -d '{"client_functions": [...]}'
```

A turn that called several client functions resumes only once every one of
them has been submitted — the submit response's `resume.ready` flag flips to
`true` on the last one. Sending a new message to the conversation abandons any
paused turn. The endpoint returns `409` if the message is not paused, if some
tool calls are still waiting, or if the conversation moved on.

**Response:** a `text/event-stream`, same format as [Send Message](#send-message).

### Get Message Status

```
GET /messages/{message_id}/status
```

Poll the current status of a message. Use this as a fallback when the SSE stream disconnects or as an alternative to streaming.

**Path parameters:**

| Parameter    | Type          | Description    |
| ------------ | ------------- | -------------- |
| `message_id` | string (UUID) | The message ID |

**Example request:**

```bash theme={null}
curl "https://your-instance.useago.com/api/sdk/v1/messages/f1e2d3c4-5678-90ab-cdef-abcdefabcdef/status" \
  -H "X-User-Anon-Id: unique_user_id"
```

**Example response:**

```json theme={null}
{
  "object": "message_status",
  "id": "aa11bb22-3344-5566-7788-99aabbccddee",
  "message_id": "f1e2d3c4-5678-90ab-cdef-abcdefabcdef",
  "conversation_id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
  "content": "You can update your payment method in Settings > Billing.",
  "status": "DONE",
  "agent": {
    "id": "e5f6a7b8-1234-5678-9abc-def012345678",
    "name": "Billing Agent"
  },
  "sources": [
    {
      "id": "c1d2e3f4-0000-1111-2222-333344445555",
      "title": "Payment Methods",
      "url": "https://help.example.com/payments"
    }
  ],
  "ask_to_talk_to_human": false
}
```

The `status` field is one of:

| Status             | Meaning                                                                                                          |
| ------------------ | ---------------------------------------------------------------------------------------------------------------- |
| `TODO`             | The message is queued and has not started processing yet                                                         |
| `IN_PROGRESS`      | The agent is still generating a response                                                                         |
| `DONE`             | The response is complete                                                                                         |
| `ERROR`            | An error occurred while generating the response                                                                  |
| `CANCELED`         | The message was canceled before completion                                                                       |
| `WAITING_APPROVAL` | A background agent run is waiting for a staff member to approve a sensitive tool action                          |
| `WAITING_CLIENT`   | The turn is paused on client function calls — submit the results, then use [Continue Message](#continue-message) |

### Submit Feedback

```
POST /messages/{message_id}/feedback
```

Submit positive or negative feedback for an agent response.

**Path parameters:**

| Parameter    | Type          | Description    |
| ------------ | ------------- | -------------- |
| `message_id` | string (UUID) | The message ID |

**Request body:**

| Field    | Type   | Required | Description                  |
| -------- | ------ | -------- | ---------------------------- |
| `rating` | string | Yes      | `"positive"` or `"negative"` |

**Example request:**

```bash theme={null}
curl -X POST "https://your-instance.useago.com/api/sdk/v1/messages/f1e2d3c4-5678-90ab-cdef-abcdefabcdef/feedback" \
  -H "X-User-Anon-Id: unique_user_id" \
  -H "Content-Type: application/json" \
  -d '{"rating": "positive"}'
```

**Response:** `204 No Content`

***

## Tickets

### Create Ticket

```
POST /tickets
```

Creates a support ticket. Send as `multipart/form-data` to support file attachments.

**Form fields:**

| Field             | Type          | Required | Description                                                |
| ----------------- | ------------- | -------- | ---------------------------------------------------------- |
| `subject`         | string        | Yes      | Ticket subject line                                        |
| `body`            | string        | Yes      | Ticket description                                         |
| `priority`        | string        | No       | `low`, `medium` (default), `high`, or `urgent`             |
| `typology`        | string        | No       | `technical`, `billing`, or `general` (default)             |
| `conversation_id` | string (UUID) | No       | Link the ticket to an existing conversation                |
| `email`           | string        | No       | Requester email address                                    |
| `custom_fields`   | string (JSON) | No       | JSON-encoded array of `{"id": "field-id", "value": "val"}` |
| `ticket_form_id`  | string (UUID) | No       | ID of a specific ticket form to use                        |
| `files`           | file(s)       | No       | File attachments                                           |

**Example request:**

```bash theme={null}
curl -X POST "https://your-instance.useago.com/api/sdk/v1/tickets" \
  -H "X-User-Anon-Id: unique_user_id" \
  -F "subject=Cannot access dashboard" \
  -F "body=I get a 403 error when I try to open the analytics page." \
  -F "priority=high" \
  -F "email=user@example.com" \
  -F "files=@error_screenshot.png"
```

**Example response (201 Created):**

```json theme={null}
{
  "object": "ticket",
  "id": "t1u2v3w4-5678-90ab-cdef-1234567890ab",
  "url": "https://your-instance.useago.com/tickets/t1u2v3w4-5678-90ab-cdef-1234567890ab"
}
```

***

## Configuration

### Get Config

```
GET /config
```

Returns workspace configuration for the authenticated user, including available permissions, pre-chat form status, and active incident banners.

**Example request:**

```bash theme={null}
curl "https://your-instance.useago.com/api/sdk/v1/config" \
  -H "X-User-Anon-Id: unique_user_id"
```

**Example response:**

```json theme={null}
{
  "object": "config",
  "permissions": [
    {
      "id": "p1q2r3s4-5678-90ab-cdef-1234567890ab",
      "name": "default",
      "display_name": "Default",
      "agents": [
        {
          "id": "e5f6a7b8-1234-5678-9abc-def012345678",
          "name": "Support Agent"
        }
      ],
      "ticket_form": null,
      "file_attachments_enabled": true
    }
  ],
  "pre_chat_form_required": false,
  "incident_banners": [],
  "proactive": { "enabled": false }
}
```

The `proactive` block tells the SDK whether [proactive mode](/features/proactive-mode) is enabled for the workspace. When `enabled` is `false`, the SDK never shows a nudge and never calls the proactive endpoints.

### Get Pre-Chat Form Status

```
GET /pre-chat-form/status
```

Check whether the pre-chat form is required for the current user before they can start a conversation.

**Example request:**

```bash theme={null}
curl "https://your-instance.useago.com/api/sdk/v1/pre-chat-form/status" \
  -H "X-User-Anon-Id: unique_user_id"
```

**Example response:**

```json theme={null}
{
  "form_required": true,
  "form": {
    "id": "f1a2b3c4-5678-90ab-cdef-1234567890ab",
    "options": [
      {
        "id": "opt-001",
        "label": "I have a billing question"
      },
      {
        "id": "opt-002",
        "label": "I need technical support"
      }
    ]
  },
  "completed_today": false,
  "assigned_permission_id": null
}
```

### Submit Pre-Chat Form

```
POST /pre-chat-form/submit
```

Submit the user's pre-chat form selection. After a successful submission, the user is assigned a permission and can start conversations.

**Request body:**

| Field       | Type   | Required | Description                          |
| ----------- | ------ | -------- | ------------------------------------ |
| `option_id` | string | Yes      | The selected option ID from the form |

**Example request:**

```bash theme={null}
curl -X POST "https://your-instance.useago.com/api/sdk/v1/pre-chat-form/submit" \
  -H "X-User-Anon-Id: unique_user_id" \
  -H "Content-Type: application/json" \
  -d '{"option_id": "opt-001"}'
```

**Example response:**

```json theme={null}
{
  "success": true,
  "assigned_permission_id": "p1q2r3s4-5678-90ab-cdef-1234567890ab"
}
```

### Get Active Incident Banners

```
GET /incident-info-banners/active
```

Returns any active incident or informational banners configured for the workspace.

**Example request:**

```bash theme={null}
curl "https://your-instance.useago.com/api/sdk/v1/incident-info-banners/active" \
  -H "X-User-Anon-Id: unique_user_id"
```

**Example response:**

```json theme={null}
{
  "banners": [
    {
      "id": "b1c2d3e4-5678-90ab-cdef-1234567890ab",
      "title": "Scheduled Maintenance",
      "message": "We will perform scheduled maintenance on Saturday from 2:00 AM to 4:00 AM UTC.",
      "background_color": "#FFF3CD",
      "text_color": "#856404",
      "agent_ids": []
    }
  ]
}
```

When `agent_ids` is empty, the banner applies to all agents. When populated, it only appears for conversations with the listed agents.

***

## Proactive Mode

Used by the SDK's [proactive mode](/features/proactive-mode). The evaluate endpoint requires proactive mode to be enabled for the workspace; the events endpoint accepts lifecycle reports regardless, so batches sent around a configuration change are not lost.

### Evaluate an Intervention

```
POST /proactive/evaluate
```

Called by the SDK after a client-side trigger matched, when the trigger is configured with `intervene: "agent"`. A fast model decides whether a nudge is worth showing right now and drafts its message.

**Request body:**

```json theme={null}
{
  "client_nudge_id": "d4f8a1b2-3c5e-4f6a-8b9c-0d1e2f3a4b5c",
  "trigger_id": "kyc-doc-stuck",
  "goal": "Help the user upload their KYC documents",
  "agent": "support",
  "signals": {
    "route": "/dossier/42",
    "idle_ms": 21000,
    "rage_clicks": 0,
    "route_bounces": 2,
    "field_errors": {},
    "recent_routes": ["/dossier/42", "/help"],
    "page_state": { "step": "documents", "uploaded": 0 }
  },
  "client_context": { "entries": {} },
  "client_functions": [
    {
      "name": "prefill_form",
      "description": "Prefill the KYC form",
      "parameters": { "type": "object", "properties": {} }
    }
  ]
}
```

`client_nudge_id` is a UUID generated by the SDK for this nudge instance; lifecycle events sent later reference it. `agent` (optional) is the agent id or name. `signals` only carries counters and page paths — never form values.

**Example response:**

```json theme={null}
{
  "object": "proactive_evaluation",
  "intervene": true,
  "message": "Need a hand with your documents?",
  "action": {
    "label": "Pre-fill for me",
    "function_name": "prefill_form",
    "arguments": { "step": "documents" }
  },
  "nudge_id": "a1b2c3d4-5678-90ab-cdef-1234567890ab"
}
```

When `intervene` is `false`, `message` and `action` are `null` and the SDK stays silent. `action` is only ever one of the `client_functions` declared in the request.

Returns `403` (`proactive_mode_disabled`) when the feature is off for the workspace or the agent, and `429` (`rate_limited`) when the per-user evaluation cap is reached — the SDK treats both as "do not intervene".

### Report Nudge Events

```
POST /proactive/events
```

Batched lifecycle tracking for nudges, including static ones that never called the evaluate endpoint. Maximum 50 events per request.

**Request body:**

```json theme={null}
{
  "events": [
    {
      "client_nudge_id": "d4f8a1b2-3c5e-4f6a-8b9c-0d1e2f3a4b5c",
      "trigger_id": "kyc-doc-stuck",
      "source": "agent",
      "type": "shown",
      "message": "Need a hand with your documents?",
      "agent": "support",
      "occurred_at": "2026-07-09T10:30:00Z"
    }
  ]
}
```

`source` is `"static"` or `"agent"`. `type` is one of `shown`, `dismissed`, `accepted`, `converted`. Events are idempotent per nudge and type: the first reported timestamp wins.

**Example response:**

```json theme={null}
{
  "object": "proactive_events",
  "recorded": 1
}
```

***

## Error Format

All errors follow a consistent structure:

```json theme={null}
{
  "error": {
    "type": "invalid_request_error",
    "code": "not_found",
    "message": "The requested resource was not found.",
    "param": null,
    "doc_url": "https://docs.useago.com/api/errors#not_found"
  }
}
```

| Error Type              | Status Codes  | Description                                                   |
| ----------------------- | ------------- | ------------------------------------------------------------- |
| `authentication_error`  | 401           | Invalid or missing user identity                              |
| `permission_error`      | 403           | The authenticated user does not have access to this resource  |
| `invalid_request_error` | 400, 404, 422 | Missing or invalid parameters, or the resource does not exist |
| `api_error`             | 500           | Something went wrong on the server                            |

***

## Related

* [Public API v1](/api/public-api-v1) -- the admin-facing REST API for managing your workspace
* [API Key Authentication](/security/api-key-authentication) -- how to generate and manage API keys
* [SDK Integration](/features/sdk-integration) -- guide to embedding AGO in your application
