API

API Reference

Complete reference for the Chat Completions endpoint

|View as Markdown
1 min read

Endpoint

plaintext
POST https://build.chipp.ai/api/v1/chat/completions

Request

Headers

HeaderRequiredDescription
AuthorizationYesBearer YOUR_API_KEY
Content-TypeYesapplication/json
X-Chat-Session-IDNoAlternative session ID
X-Correlation-IDNoRequest tracking ID

Body

typescript
{
  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 via POST /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:

  1. Upload the file’s raw bytes to POST /api/v1/chat/files (multipart form-data, same Authorization: Bearer API key as /completions).
  2. Take the returned fileId and pass it in the files array on your next /chat/completions call, alongside the fileName you 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

HeaderRequiredDescription
AuthorizationYesBearer YOUR_API_KEY (same key as /chat/completions)
Content-TypeYesmultipart/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):

ExtensionMIME typeDelivered to the model as
.jpg, .jpegimage/jpegMultimodal image part (vision)
.pngimage/pngMultimodal image part (vision)
.pdfapplication/pdfExtracted text, via the readPDF tool
.docxapplication/vnd.openxmlformats-officedocument.wordprocessingml.documentExtracted 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 the files array of /chat/completions to attach more than one file to a single turn (up to 100 references per request).

Response (201)

json
{
  "fileId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "fileName": "invoice.pdf",
  "mimeType": "application/pdf",
  "size": 48213
}

Example (curl)

bash
# 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

CodeMeaning
400Malformed 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)
401Missing/invalid API key
422The 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
429Rate limit exceeded
503Internal 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

json
{
  "model": "myapp-123",
  "messages": [{ "role": "user", "content": "What does this invoice say?" }],
  "files": [{ "fileId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "fileName": "invoice.pdf" }]
}
  • Every referenced fileId must have been uploaded through /chat/files using 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_DISABLED or IMAGE_LIMIT_REACHED).
  • For PDF/DOCX, the model is told a document is attached and calls its readPDF/readDocument tool 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 readPDF tool 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:

json
{
  "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 variables once, on the call that creates the session (no chatSessionId yet, or the first call with a new one) — it stays bound to that session for later chatSessionId continuation calls. You can also send updated variables on 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 variables key that isn’t declared on any connection is simply unused.

Response

Success (200)

json
{
  "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:

json
{
  "error": "Error message describing the issue"
}

Status Codes

CodeDescription
200Success
400Invalid request parameters
401Authentication/authorization failure
402Insufficient credits or usage cap reached
404Unknown model (app), or a referenced files entry is not accessible
422A referenced image was rejected by the app’s image-input settings (see File Attachments)
429Rate limit exceeded (120 requests/minute per API key) - retry after the Retry-After header
500Server error

Common Errors

Invalid Request (400)

json
{
  "error": "`model` is required and must be a string"
}
json
{
  "error": "`messages` must be a non-empty array"
}
json
{
  "error": "variables exceeds the max of 20 entries"
}

Authentication Failed (401)

json
{
  "error": "Missing API key"
}
json
{
  "error": "Invalid API key"
}
json
{
  "error": "This API is only available on a paid plan.  Visit your dashboard to upgrade."
}

Model Not Found (404)

json
{
  "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):

json
{
  "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:

json
{
  "error": "IMAGE_INPUT_DISABLED",
  "message": "Image input is disabled for this chatbot."
}
json
{
  "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:

json
{
  "error": "This PDF is password-protected. Upload an unprotected copy."
}
json
{
  "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)

json
{
  "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)