Skip to content

Chat completions

POST /api/v1/chat/completions is the OpenAI-compatible chat completions endpoint. It works with the existing OpenAI SDKs (set base_url=https://api.cloakapi.io/api/v1) and supports streaming (Server-Sent Events) and safe-to-retry Idempotency-Key semantics.

Idempotency-Key

A flaky connection that triggers a client-side retry must not double-bill the user or duplicate the receipt-chain entry. CloakAPI implements the IETF-draft Idempotency-Key header (draft-ietf-httpapi-idempotency-key-header).

Terminal window
curl https://api.cloakapi.io/api/v1/chat/completions \
-H "Authorization: Bearer $CLOAKAPI_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"model": "claude-haiku-4-5-20251001",
"messages": [{"role":"user","content":"Hello"}]
}'

Contract

AspectBehaviour
Header nameIdempotency-Key
Recommended formatUUID v4
Max length128 chars
ScopePer API key (different keys may reuse the same value)
TTL24 hours; an expired key is treated as fresh
What gets cachedOnly 2xx responses (errors are not memoised so a transient outage can be retried)
Replay headerX-CloakAPI-Idempotent-Replay: true (legacy alias: Idempotency-Replayed: true)
Conflict response409 Conflict when the same key is reused with a different request body

Concurrent retries — if the original call is still in flight when a duplicate arrives, the duplicate blocks for up to 3 seconds on the in-flight slot and then returns the cached response. There is no race window in which two upstream calls can fire for the same key.

Receipt / chain semantics — a replayed call returns the original receipt (same JTI, same chain_seq). The chain sequence does not advance and the user’s balance is not debited a second time. Verify this for yourself by chaining receipts:

Terminal window
curl -sk -X POST https://api.cloakapi.io/api/v1/receipts/verify \
-H 'Content-Type: application/json' \
-d '{"receipt":"<x-cloakapi-receipt-v2 header from the replayed call>"}'

Streaming (SSE)

Pass "stream": true to receive an OpenAI-style Server-Sent Events stream.

Terminal window
curl -N https://api.cloakapi.io/api/v1/chat/completions \
-H "Authorization: Bearer $CLOAKAPI_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-haiku-4-5-20251001",
"messages": [{"role":"user","content":"Count to three"}],
"stream": true
}'

Response is Content-Type: text/event-stream; charset=utf-8 with frames of the shape:

data: {"id":"...","object":"chat.completion.chunk","choices":[{"delta":{"content":"1"}}]}
data: {"id":"...","object":"chat.completion.chunk","choices":[{"delta":{"content":" 2"}}]}
data: [DONE]
event: receipt-v2
data: {"alg":"ES256","jti":"...","hash_upstream_response":"...","input_tokens":...,"output_tokens":...,...}

The terminator is data: [DONE]\n\n. After it, the gateway emits a single event: receipt-v2 frame carrying the same signed receipt envelope you would receive in the X-CloakAPI-Receipt-V2 header for a non-streamed call. Pass the envelope’s data: payload to /api/v1/receipts/verify to confirm the signature, the upstream-response hash, and the chain position — the verifier endpoint does not care whether the receipt originated from a streamed or non-streamed call.

Streaming + Idempotency-Key

Streamed calls honour Idempotency-Key too. On the first call, the gateway records the verbatim wire transcript (every SSE frame, in order, terminator and receipt-v2 trailer included). On a retry with the same key + same body, the gateway replays the cached transcript byte-for-byte without touching the upstream provider:

Terminal window
KEY=$(uuidgen)
curl -N -H "Idempotency-Key: $KEY" ... # first call: real upstream stream
curl -N -H "Idempotency-Key: $KEY" ... # retry: cached transcript, no debit

The retry response carries X-CloakAPI-Idempotent-Replay: true and X-CloakAPI-Streamed: true. A different request body with the same key returns 409, exactly like the non-streamed path.

Edge buffering

api.cloakapi.io advertises Cache-Control: no-cache, no-store, must-revalidate and X-Accel-Buffering: no on streamed responses, and the front nginx is configured with proxy_buffering off for the chat-completions location. This means individual chunks reach the client as soon as they arrive from the upstream provider — there is no edge-layer buffer to drain.

If you are running CloakAPI behind your own reverse proxy (Cloudflare, AWS ALB, etc.), make sure that proxy also passes SSE through unbuffered. For Cloudflare you typically need a Page Rule with Cache Level: Bypass for /api/v1/chat/completions.

Reference matrix

BehaviourNon-streamStream
Idempotency-Key honouredyesyes
Replay headerX-CloakAPI-Idempotent-Replay: truesame
Conflict (different body)409409
Receipt deliveryX-CloakAPI-Receipt-V2 headerevent: receipt-v2 SSE frame
Verifier endpoint/api/v1/receipts/verify/api/v1/receipts/verify
Chain seq advances on replaynono
Balance debited on replaynono

Last updated: