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-agent to 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

EndpointMethodWhat it does
/api/modelsGETAvailable models and aliases, with family, display name, labels, description, byte limits and features
/api/msg/send/syncPOSTSend a message and get the answer back synchronously, with the exchange returned as chat history
/api/file/limits/getGETMax upload file size, total storage limit and max attachments per message
/api/file/upload/startPOSTRequest an upload URL. Returns operation_id and a signed sas_url
/api/file/upload/checkPOSTFinalise the upload after the content has been sent to sas_url
/api/file/download/startPOSTBegin a download for a file_id
/api/file/download/checkPOSTComplete the download operation
/api/files/getPOSTList stored files, paged with cursor and page_size
/api/file/getPOSTMetadata for one file
/api/file/deletePOSTDelete one or more files by file_ids
/health.htmlGETService health

Send a message

POST /api/msg/send/sync

FieldRequiredTypeDescription
textYesstringThe message text
modelYesstringR2 model name, from /api/models
instructionYesstringSystem role for the assistant
max_bytes_outputYesuint64Output size cap in bytes
img_modelNostringR2 image model
use_web_searchNobooleanEnable the web search plugin
metaNoobjectAny JSON you want echoed back, not used for generation
environmentNoobjecttime ISO 8601 with offset, locale BCP 47, ip
attachmentsNoarraySelection or file attachments, see below
chat_historyNoarrayPrior 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

TypeMeaningFields
1Selectionmime_type, name, data as plain text
2Filemime_type, name, file_id, file_size; no data
0Image, in responsesmime_type, name, data
-1Unknown, see mime_type

Result codes

ValueMeaning
0Success
-3Access denied
-4Service temporarily not valid
-5Invalid parameters
-6Service maintenance
-7Insufficient balance
-8File size exceeded
-9File storage limit reached

Working with files

Uploads are a three-step handshake, so large files go straight to storage rather than through the API.

  1. Call /api/file/upload/start with file_name, mime_type and file_size. You get back an operation_id and a temporary sas_url.
  2. Upload the file content directly to sas_url.
  3. Call /api/file/upload/check with the operation_id to 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.