Skip to content
Documentation/REST API reference
On this page API hosts and authentication
BUILD WITH CTX

REST API reference

The public capture, recall, and upload contract: authentication, request fields, response models, and delivery semantics.

Public API · SDK 0.1.0 contractGet an API key ↗

API hosts and authentication

This reference covers the public routes used by the published 0.1.0 SDKs. Use HTTPS and the x-api-key header on every request. JSON examples are illustrative shapes, not live responses. Account authorization is derived from the key; there is no public user_id override.

Method and routeHostPurpose
GET /verifyhttps://api.contexara.comValidate an active API key.
POST /ingesthttps://api.contexara.comSubmit a complete conversation-turn event.
POST /v1/memory/searchhttps://retrieval.contexara.comRecall relevant memory.
POST /uploadhttps://api.contexara.comUpload a file and consume an SSE response.

Create an API key in the dashboard at /keys. Enable capture permission for writes and recall permission for searches. Keep the key on your server or in your secret manager; never expose it in browser JavaScript, a public repository, or logs. The key determines the authenticated account. A workspace ID selects an authorized destination; it does not grant access to another account.

Plain text
x-api-key: ctx_live_replace_with_your_key

Use Content-Type: application/json for ingest and search. Use multipart/form-data with a generated boundary for upload. Loop chat endpoints require internal authentication and are not part of this public API. There are no SDK-backed public list, delete, or stats operations in this release.

GET /verify

Send no body. A 200 response contains {"ok": true}; an invalid or inactive key returns 401. Successful verification is not a permission or quota preflight.

Plain text
GET /verify HTTP/1.1
Host: api.contexara.com
x-api-key: ctx_live_replace_with_your_key
JSON
{"ok":true}

POST /ingest

Submit one complete conversation turn. The SDK builds this envelope automatically; a custom HTTP client must build and persist it before delivery.

JSON
{
  "event_id": "evt_replace_with_a_new_unique_id",
  "event_type": "conversation_turn",
  "event_version": "1.0",
  "capture_version": "my-app-0.1.0",
  "schema_version": "1.0",
  "turn_id": "turn_000001",
  "tenant_id": "unset",
  "user_id": "unset",
  "session_id": "conversation_replace_with_your_stable_id",
  "turn_number": 1,
  "project_id": null,
  "workspace_id": null,
  "provider": "sdk",
  "created_at": "2026-09-29T12:00:00Z",
  "status": "complete",
  "incomplete_reason": null,
  "conversation": {
    "user": {
      "timestamp": null,
      "content": "The deployment region is Mumbai."
    },
    "assistant": {
      "timestamp": null,
      "content": null
    }
  },
  "metadata": {
    "capture_client_version": "0.1.0",
    "os": null,
    "hook_event_names": []
  }
}
FieldType and contract
event_idString, maximum 512 characters. Unique per logical event; unchanged on retries.
event_type / event_version / schema_versionconversation_turn / 1.0 / 1.0.
capture_versionYour capture implementation version, e.g. my-app-0.1.0.
session_idStable conversation string, maximum 512 characters.
turn_number / turn_idInteger ≥1; derived turn_NNNNNN identifier, padded to at least six digits.
tenant_id / user_idSend unset; the server stamps authenticated identity.
providersdk for this integration.
created_atRFC 3339 timestamp with timezone; naive timestamps are invalid.
status / incomplete_reasonUse complete and null for SDK-style complete turns.
project_id / workspace_idNullable authorized destination UUIDs.
conversation.user / assistantObjects with timestamp and content. Content string or null; maximum 100,000 characters per message. SDK capture requires non-blank user text.
metadatacapture_client_version, os, and hook_event_names as shown.

The shown event ID, session ID, and timestamp must be replaced before first delivery. turn_000001 matches turn_number=1. The cURL guide includes a one-time identity-generation example.

Capture acknowledgement and delivery

HTTP responseMeaning
202 {ok:true, turn_id, status:"accepted"}Queued for processing. Not a search-readiness guarantee.
200 {ok:true, turn_id, status:"processed"}Processed in a synchronous deployment. Evidence availability can still lag.

Persist the original event until delivery is acknowledged. Retry an uncertain capture with the identical event_id and entire payload. Never recreate an event for a retry. A new logical write requires a new event ID. Do not change content under an existing event ID: that misuse is not reliably rejected by the server. This is not an exactly-once guarantee.

A 409 capture conflict can be returned from synchronous processing. In queued deployments, later worker failures cannot change an already returned 202. The capture response has no processing-status handle. Do not treat the absence of an HTTP conflict as proof of eventual processing success.

Search response fields

JSON
{
  "results": [
    {
      "memory_id": "example-memory",
      "text": "The deployment region is Mumbai.",
      "entities": [
        {
          "text": "Mumbai",
          "type": "GPE"
        }
      ],
      "event_time": null,
      "record_time": null,
      "confidence_bucket": null,
      "rrf_score": 0.83,
      "speaker": null,
      "source_type": "sdk",
      "modality": null,
      "source_id": null,
      "content_hash": null,
      "page_number": null,
      "slide_number": null,
      "mime_type": null
    }
  ],
  "timings_ms": {}
}
FieldInterpretation
resultsOrdered array of memories; an empty array is a valid result.
memory_id / textMemory identity and content.
rrf_scoreNullable ranking signal; not a probability. Preserve returned ordering.
entitiesExtractor-dependent objects; name, text, and type may each be absent.
event_time / record_timeNullable timestamps.
confidence_bucketCurrently null; do not require a confidence value.
source_type / source_id / modalityNullable provenance.
content_hash / page_number / slide_number / mime_typeNullable attachment provenance.
timings_msOpen numeric map; tolerate new timing keys.
noteOptional server-provided text.

Do not require the legacy type, confidence, or salience fields. Tolerate additive response fields while validating required structure and known field types. Python models retain snake_case; Node models expose camelCase.

Deep Recall response semantics

When synthesis runs, the response includes synthesis (string or null) and grounded_in_source_windows (boolean), alongside results and timings_ms. These fields can be absent when a deep request falls back to Fast Recall. Presence and non-null synthesis are separate checks.

JSON
{"synthesis":null,"grounded_in_source_windows":false,"results":[],"timings_ms":{}}

grounded_in_source_windows states whether a summoned source window materially informed synthesis; it is not a citation array. Internal counters such as summoned_count and sub_query_count are not public response fields. The final result count need not respect limit. Deep Recall can incur model cost before an uncertain timeout, so retry conservatively.

POST /upload multipart fields

FieldRequired / defaultMeaning
fileRequiredBinary file with filename and allowed MIME type.
captionOptionalText accompanying the upload.
explainHTTP default true; SDK default falseNon-image false skips explanation; images still explain.
session_idOptionalConversation association.
project_idOptionalActive authorized project UUID.
explicit_workspace_idOptionalWorkspace UUID. Do not send workspace_id as the multipart name.
group_idOptionalBatch grouping for images.

Let your HTTP library generate the multipart boundary. Validate the actual file format and byte size before sending. Unsupported MIME types return 415; oversized uploads return 413. Limits below use decimal bytes, not MiB.

File typeAccepted MIME typeMaximum bytes
PNG / JPEG / WebPimage/png, image/jpeg, image/webp20,000,000
PDFapplication/pdf50,000,000
DOCXapplication/vnd.openxmlformats-officedocument.wordprocessingml.document20,000,000
PPTXapplication/vnd.openxmlformats-officedocument.presentationml.presentation50,000,000
TXT / Markdowntext/plain, text/markdown5,000,000

Implement Server-Sent Events parsing

Plain text
data: {"content_hash":"example-hash","duplicate":false,"attachment_id":"example-attachment"}

data: [DONE]

Decode UTF-8 incrementally: a network read can split a multibyte character or a frame. Accumulate lines until an empty line terminates an event; support LF and CRLF, and join multiple data: lines with newline characters. Ignore SSE comments. Parse each complete data payload as JSON, except the literal [DONE] sentinel.

PayloadHandling
content_hash, duplicate, attachment_idPersist the received metadata for later diagnostics.
chunkAppend explanation text; zero chunks is valid.
errorMark the operation failed, even if [DONE] follows.
[DONE]Normal stream terminator, successful only if no error preceded it.
EOF without [DONE]Incomplete stream; surface an error and retain partial metadata.

HTTP success is insufficient for an upload. Storage can precede later errors, including errors before the first event. An SSE failure does not imply that no file was stored. Do not regenerate an upload request automatically after a timeout.

Errors and retry behavior

HTTP statusMeaningRecovery
400Blank query or invalid limit.Correct the request.
401Missing, invalid, or inactive API key.Replace or activate the key.
402Personal or team hard quota lock.Review usage and allowance.
403Permission, preference, or workspace access denied.Check key scope, preferences, and membership.
409Capture turn conflict in synchronous processing.Investigate identity/payload; do not invent a retry ID.
413Request or upload too large.Reduce the payload or use an allowed file size.
415Unsupported upload MIME type.Use an allowed MIME type and file format.
422Invalid fields, scope, project, or multipart data.Inspect the error response and correct the payload.
429Rate limit or upload allowance exhausted.Honor Retry-After when present; otherwise inspect allowance.
5xxServer or upstream failure.Bound retries according to operation and delivery certainty.

Error bodies are endpoint-specific and can contain a string or structured detail; do not assume one universal error-envelope shape. Log status and safe diagnostic details while redacting keys and sensitive message bodies. Retry-After can be seconds or an HTTP date. Set both connection and response budgets and cap attempts.

OperationRetry policy for a custom client
Verify / Fast RecallBounded retry on transient network or server failures.
Deep RecallConservative retry because generation may already have run.
CaptureOnly replay the exact persisted event after an uncertain result.
UploadNo automatic retries; inspect partial storage evidence.

For 401, 402, 403, and validation failures, fix the underlying cause. For a 429 without Retry-After, do not assume a short backoff restores an exhausted allowance. Cancellation is local: it cannot undo work already accepted by the service.

Implementation checklist

Keep credentials server-side. Choose capture and recall destinations explicitly. Persist event identity and allocate turn numbers durably. Validate response shapes without rejecting additive fields. Preserve result order and source metadata. Handle empty recall normally. Parse SSE across arbitrary read boundaries. Distinguish acknowledged capture from searchable memory and stored attachments from successful explanation streams.

For existing application code, the Python and Node guides provide supported clients with these mechanics built in. Use the cURL guide to inspect individual requests during integration.

← All documentation
SUGGESTED STARTING POINTS