Ai chat

Send a message and get the AI's reply

POST/ai/chats/{ref}/messages

The primary endpoint. Sends message to the AI in the context of chat {ref} and returns the assistant's response when complete.

Tools

Tools listed in tools are made available to the AI. Names come from GET /ai/tools. Omit tools to use the default set (search + document reading). Send tools: [] to disable all tools.

Images attached by the caller

Pass base64-encoded images in attachedImages. Vision-capable models (GPT 5.x, Claude Sonnet/Opus, Gemini Pro) read them. With tools: ["image_generation"] they're also used as edit/composition inputs ("change the background", "combine these two", etc.).

Images generated by the AI

Generated images are returned in the images array as {path, url} pairs. The url is a 1-hour signed URL that any browser <img src> can fetch — no api-key header needed.

Streaming

For long responses you can pre-create a stream via POST /ai/streams/init, pass streamId here, and poll GET /ai/streams/{streamId} from a separate connection while this POST blocks.

Resource grounding

Pass resourceRefs: [123, 456] to attach catalogue resources as chat documents. Combined with tools: ["document_reading"] (auto-on when documents are present) the AI can read them via the document_read tool.

Idempotency

Pass an Idempotency-Key header (a unique random string per logical send, e.g. a UUID) to make retries safe. The first successful response with a given key is cached for 24 hours; replays return the same body byte-for-byte with Idempotent-Replayed: true. Reusing the key with a different request body returns 422 IDEMPOTENCY_KEY_CONFLICT.

X-Api-Key<token>

Issued to you when your integration is provisioned. Determines which catalogue resources are visible and which AI tools are available.

In: header

Path Parameters

ref*integer

Header Parameters

Idempotency-Key?string

Optional client-supplied retry key. 1–255 printable-ASCII characters. Use a UUID or other high-entropy random string.

Match^[\x21-\x7E]+$
Lengthlength <= 255

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/ai/chats/0/messages" \  -H "Content-Type: application/json" \  -d '{    "message": "Summarise the latest releases in our catalogue.",    "tools": []  }'
{  "data": {    "chatRef": 0,    "chatName": "string",    "messageIndex": 0,    "streamId": "string",    "model": "string",    "chatResponse": "string",    "results": [      {        "title": "string",        "preview": "string",        "resourceId": 0,        "score": 0,        "rawScore": 0,        "matchSource": "metadata",        "hits": 0      }    ],    "reasoning": "string",    "images": [      {        "path": "/chat_images/1024/gpt_307_stream_xxx.png",        "url": "https://example.veristage.com/api/external/ai/images?path=%2Fchat_images%2F1024%2Fgpt_307_stream_xxx.png&exp=1777565000&sig=<signature>"      }    ]  }}
{  "success": false,  "status": "fail",  "message": "string",  "error": {    "message": "API key is required",    "code": "NO_API_KEY"  }}
{  "success": false,  "status": "fail",  "message": "string",  "error": {    "message": "API key is required",    "code": "NO_API_KEY"  }}
{  "success": false,  "status": "fail",  "message": "string",  "error": {    "message": "API key is required",    "code": "NO_API_KEY"  }}
{  "success": false,  "status": "fail",  "message": "Hourly rate limit exceeded.",  "error": {    "code": "RATE_LIMITED",    "message": "Hourly rate limit exceeded."  }}
Empty