API reference · endpoints, fields, result codes
API reference
The R2 Chat Service API. One key, every model, the same governed path as the add-ins. Keys are created in the web app under Settings, against a subscription you hold.
Base URL and authentication
Request basics
- Base URL
https://api-chat.r2copilot.ai - Content type
application/json - Auth header
x-api-key: <your key> - Optional
x-hs-user-agentto identify the calling client
Both protocols use the same key
The R2 Custom API documented on this page, and the OpenAI Responses-compatible protocol for existing tooling, share one base URL and are both authenticated with a key created in Settings. Pick the subscription the key draws against when you create it.
Which protocol to use →Endpoints
| Endpoint | Method | What it does |
|---|---|---|
/api/models | GET | Available models and aliases, with family, display name, labels, description, byte limits and features |
/api/msg/send/sync | POST | Send a message and get the answer back synchronously, with the exchange returned as chat history |
/api/file/limits/get | GET | Max upload file size, total storage limit and max attachments per message |
/api/file/upload/start | POST | Request an upload URL. Returns operation_id and a signed sas_url |
/api/file/upload/check | POST | Finalise the upload after the content has been sent to sas_url |
/api/file/download/start | POST | Begin a download for a file_id |
/api/file/download/check | POST | Complete the download operation |
/api/files/get | POST | List stored files, paged with cursor and page_size |
/api/file/get | POST | Metadata for one file |
/api/file/delete | POST | Delete one or more files by file_ids |
/health.html | GET | Service health |
Send a message
POST /api/msg/send/sync
| Field | Required | Type | Description |
|---|---|---|---|
text | Yes | string | The message text |
model | Yes | string | R2 model name, from /api/models |
instruction | Yes | string | System role for the assistant |
max_bytes_output | Yes | uint64 | Output size cap in bytes |
img_model | No | string | R2 image model |
use_web_search | No | boolean | Enable the web search plugin |
meta | No | object | Any JSON you want echoed back, not used for generation |
environment | No | object | time ISO 8601 with offset, locale BCP 47, ip |
attachments | No | array | Selection or file attachments, see below |
chat_history | No | array | Prior turns, each with role USER or ASSISTANT, content.text, meta, attachments, dt |
The response carries result and chat_history, where the last item is the assistant turn, with msg_id and a unix dt. Pass that history back on the next request to continue the conversation.
Attachments
| Type | Meaning | Fields |
|---|---|---|
1 | Selection | mime_type, name, data as plain text |
2 | File | mime_type, name, file_id, file_size; no data |
0 | Image, in responses | mime_type, name, data |
-1 | Unknown, see mime_type | — |
Result codes
| Value | Meaning |
|---|---|
0 | Success |
-3 | Access denied |
-4 | Service temporarily not valid |
-5 | Invalid parameters |
-6 | Service maintenance |
-7 | Insufficient balance |
-8 | File size exceeded |
-9 | File storage limit reached |
Working with files
Uploads are a three-step handshake, so large files go straight to storage rather than through the API.
- Call
/api/file/upload/startwithfile_name,mime_typeandfile_size. You get back anoperation_idand a temporarysas_url. - Upload the file content directly to
sas_url. - Call
/api/file/upload/checkwith theoperation_idto finalise and trigger processing.
Do not call upload/check before the upload to sas_url has finished. Once finalised, attach the file to a message with attachment type 2 and its file_id and file_size.
// 1. ask for an upload URL
POST /api/file/limits/get -> upload_file_size_max
upload_storage_files_size_max
attachments_count_max
POST /api/file/upload/start
{ "file_name": "claim.pdf",
"mime_type": "application/pdf",
"file_size": 204800 }
-> { "result": 0, "operation_id": 42,
"sas_url": "https://storage.../upload" }
// 2. PUT the bytes to sas_url
// 3. finalise
POST /api/file/upload/check
{ "operation_id": 42 }Listing models
GET /api/models returns aliases and the model catalogue. Read limits from here rather than hardcoding them: each model reports maxInputBytes, maxOutputBytes and maxTotalBytes, plus the labels and description shown in the app.
{
"aliases": [ { "alias": "GPT-5", "apiName": "GPT_52" } ],
"models": [
{
"family": "GPT",
"displayName": "GPT-5.2",
"apiName": "GPT_52",
"labels": ["Analytical", "Cost-efficient", "Older"],
"description": "Strong analysis at a better cost than GPT_54 ...",
"limits": { "maxInputBytes": 4000,
"maxOutputBytes": 8000,
"maxTotalBytes": 8000 },
"features": ["CHAT"],
"isChoosableOnUI": true
}
]
}Usage draws on the token allowance of the subscription the key was created against.
Create a key and send the first request
Create a key, choose a model and send your first governed request.