API Reference
Complete reference for the Chat Completions endpoint
Endpoint
POST https://build.chipp.ai/api/v1/chat/completionsRequest
Headers
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer YOUR_API_KEY |
Content-Type | Yes | application/json |
X-Chat-Session-ID | No | Alternative session ID |
X-Correlation-ID | No | Request tracking ID |
Body
{
model: string; // Your app's appNameId (e.g., "myapp-123")
messages: Array<{
role: "user" | "assistant" | "system";
content: string;
}>;
stream?: boolean; // Default: false
chatSessionId?: string; // Continue conversation
variables?: Record<string, string>; // Session-scoped MCP header variables
files?: Array<{ fileId: string; fileName: string }>; // File attachments (see below)
}Parameters
- model: Your Chipp application’s
appNameId(format:appname-123) - messages: Array of message objects
- stream: Enable streaming (optional)
- chatSessionId: Continue existing session (optional)
- variables: Optional object of string key/value pairs, bound to this session for use by MCP connections that declare
{{session.<name>}}header placeholders (see below) - files: Optional array of
{fileId, fileName}references to files uploaded viaPOST /api/v1/chat/files(see File Attachments below)
File Attachments
The API accepts image and document attachments so a portal client can send a file alongside a chat turn and have Chipp deliver its actual content (not just its filename) to the model.
Transport: upload first, then reference by fileId
There is no multipart upload, base64, or URL-reference support directly on
/chat/completions. Instead:
- Upload the file’s raw bytes to
POST /api/v1/chat/files(multipartform-data, sameAuthorization: BearerAPI key as/completions). - Take the returned
fileIdand pass it in thefilesarray on your next/chat/completionscall, alongside thefileNameyou uploaded it as.
This is the same {fileId, fileName} reference contract Chipp’s first-party
chat surfaces use internally, so attachments go through the exact same
extraction and safety machinery already proven there - no parallel parser.
There is currently no support for passing a remote URL for Chipp to fetch.
If you need that, host the file yourself and download+upload the bytes to
/chat/files first; do not expect Chipp to dereference a URL you pass in the
request body.
POST /api/v1/chat/files
Uploads a single file and returns a fileId for use in a subsequent
/chat/completions call.
Headers
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer YOUR_API_KEY (same key as /chat/completions) |
Content-Type | Yes | multipart/form-data |
Body: multipart form with a single file field containing the raw bytes.
Accepted types (by file extension, verified against the file’s real magic bytes - a mismatch is rejected, not silently accepted):
| Extension | MIME type | Delivered to the model as |
|---|---|---|
.jpg, .jpeg | image/jpeg | Multimodal image part (vision) |
.png | image/png | Multimodal image part (vision) |
.pdf | application/pdf | Extracted text, via the readPDF tool |
.docx | application/vnd.openxmlformats-officedocument.wordprocessingml.document | Extracted text, via the readDocument tool |
No other file type is accepted on this endpoint. (First-party Chipp chat surfaces support additional types such as audio, CSV, TXT, and XLSX - those are not yet available through the public API.)
Limits
- Max file size: 20MB.
- One file per upload call; pass multiple
fileIds in thefilesarray of/chat/completionsto attach more than one file to a single turn (up to 100 references per request).
Response (201)
{
"fileId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"fileName": "invoice.pdf",
"mimeType": "application/pdf",
"size": 48213
}Example (curl)
# 1. Upload the file
curl -X POST https://build.chipp.ai/api/v1/chat/files \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "file=@invoice.pdf"
# 2. Use the returned fileId in your chat request
curl -X POST https://build.chipp.ai/api/v1/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "myapp-123",
"messages": [{"role": "user", "content": "What does this invoice say?"}],
"files": [{"fileId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "fileName": "invoice.pdf"}]
}'Errors
| Code | Meaning |
|---|---|
| 400 | Malformed multipart payload; missing file field; empty file; file over 20MB; unsupported extension; or the file’s actual bytes do not match its declared extension (MIME/extension mismatch) |
| 401 | Missing/invalid API key |
| 422 | The file was identified but cannot be read. Specific cases: a password-protected or corrupt PDF; a corrupt or malformed DOCX; or a .docx file whose bytes are actually a legacy/password-protected Word binary (.doc) rather than modern OOXML - re-save without a password and try again |
| 429 | Rate limit exceeded |
| 503 | Internal storage temporarily unavailable - retry |
A file is never accepted while its contents are unverified - every failure above is a rejection (the upload does not succeed), not a silent drop.
Using files on /chat/completions
{
"model": "myapp-123",
"messages": [{ "role": "user", "content": "What does this invoice say?" }],
"files": [{ "fileId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "fileName": "invoice.pdf" }]
}- Every referenced
fileIdmust have been uploaded through/chat/filesusing the same API key’s application - an id that doesn’t resolve to your app (or the current session’s consumer) is rejected with 404, never silently ignored. - For images, the model receives the actual image as a vision input (subject
to your app’s image-input settings - disabled or over your app’s
per-conversation image limit returns a 422 with
IMAGE_INPUT_DISABLEDorIMAGE_LIMIT_REACHED). - For PDF/DOCX, the model is told a document is attached and calls its
readPDF/readDocumenttool to read the extracted text as part of answering - the same tool-based flow first-party Chipp chat uses.
OCR
- Images: no OCR step - the image is sent directly to the model as a vision input, so a vision-capable model can read text visible in the image itself as part of normal multimodal understanding.
- PDF: text-layer extraction runs first (fast, local). If a PDF has no
extractable text layer (e.g. a scanned page rendered as an image), the
readPDFtool automatically falls back to Chipp’s OCR-capable document parser (LlamaParse) to recover the text. This fallback can take 15-30 seconds for a scanned document. - DOCX: DOCX is a structured text format; there is no OCR path for DOCX (an embedded image inside a DOCX is not OCR’d).
Session Variables
If one of your app’s MCP integrations is configured with a session-scoped
header placeholder (e.g. a builder sets a custom header’s value to
{{session.user_context}}), you can bind a value to that placeholder for
this specific session:
{
"model": "myapp-123",
"messages": [{ "role": "user", "content": "..." }],
"variables": { "user_context": "opaque-routing-value" }
}- Values are opaque strings you control — typically a routing key or tenant/user identifier that lets ONE shared MCP connection serve many end users without a separate connection or OAuth flow per user.
- You only need to pass
variablesonce, on the call that creates the session (nochatSessionIdyet, or the first call with a new one) — it stays bound to that session for laterchatSessionIdcontinuation calls. You can also send updatedvariableson a later call in the same session; new values are merged over previously bound ones. - Limits: up to 20 variables per request, up to 2048 characters per value.
Variable names must match
^[a-zA-Z_][a-zA-Z0-9_-]{0,63}$. A request that exceeds either limit is rejected with a 400 error. - Values are never included in any API response and are not persisted
beyond the life of the session. Only the app’s builder can declare which
variable names an MCP connection accepts (via the Integration Builder) —
a
variableskey that isn’t declared on any connection is simply unused.
Response
Success (200)
{
"chatSessionId": "550e8400-e29b-41d4-a716-446655440000",
"id": "chatcmpl-abc123",
"object": "chat.completion",
"created": 1699451234,
"model": "myapp-123",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "Response text"
},
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": 10,
"completion_tokens": 15,
"total_tokens": 25
}
}Error Format
All errors return a JSON object with an error field:
{
"error": "Error message describing the issue"
}Status Codes
| Code | Description |
|---|---|
| 200 | Success |
| 400 | Invalid request parameters |
| 401 | Authentication/authorization failure |
| 402 | Insufficient credits or usage cap reached |
| 404 | Unknown model (app), or a referenced files entry is not accessible |
| 422 | A referenced image was rejected by the app’s image-input settings (see File Attachments) |
| 429 | Rate limit exceeded (120 requests/minute per API key) - retry after the Retry-After header |
| 500 | Server error |
Common Errors
Invalid Request (400)
{
"error": "`model` is required and must be a string"
}{
"error": "`messages` must be a non-empty array"
}{
"error": "variables exceeds the max of 20 entries"
}Authentication Failed (401)
{
"error": "Missing API key"
}{
"error": "Invalid API key"
}{
"error": "This API is only available on a paid plan. Visit your dashboard to upgrade."
}Model Not Found (404)
{
"error": "Unknown model \"invalidapp-999\""
}File Not Accessible (404)
Returned by /chat/completions when a referenced fileId does not belong to the calling API key’s application (or the current session’s consumer):
{
"error": "One or more referenced `files` could not be found: 3fa85f64-5717-4562-b3fc-2c963f66afa6"
}Image Input Rejected (422)
Returned by /chat/completions when the app’s image-input settings block the attached image. The error field is a machine-readable code; message is a human-readable explanation:
{
"error": "IMAGE_INPUT_DISABLED",
"message": "Image input is disabled for this chatbot."
}{
"error": "IMAGE_LIMIT_REACHED",
"message": "Image limit reached for this conversation."
}File Upload Unreadable (422)
Returned by /api/v1/chat/files when a file’s bytes are accepted but its content cannot be parsed:
{
"error": "This PDF is password-protected. Upload an unprotected copy."
}{
"error": "This .docx file looks like a legacy/password-protected Word document, not a modern OOXML .docx. Re-save it as .docx without a password and try again."
}Server Errors (500)
{
"error": "Internal Server Error"
}Sessions
New Session
Omit chatSessionId to start fresh.
Continue Session
Include chatSessionId from previous response. Previous messages are loaded automatically.
Requirements
- Builder plan or higher (Free accounts cannot access the API)
- Valid API key from your application’s Access tab (Builder API Keys section)