Antimatter

Docs

Requests

Streaming, compression, redaction, stored prompts and the Anthropic API.

Streaming

"stream": true gives server sent events in the OpenAI chunk format, ending with data: [DONE]. The last chunk carries usage, with usage.cost the dollars this request was billed. Send x-antimatter-resumable: 1 with a key and a dropped connection picks up at GET /v1/streams/{id}, the id in x-antimatter-stream-id.

curl -N https://useantimatter.com/v1/chat/completions \
  -H "Authorization: Bearer $ANTIMATTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "meta-llama/llama-3.1-8b-instruct",
    "stream": true,
    "messages": [{"role": "user", "content": "Count to five"}]
  }'

Compression

This is off unless you ask for it. Send x-antimatter-compress: safe (or set compress on the key's policy) and four things happen. A document or tool result repeated later in the thread is sent once, and each later copy becomes a short reference to the first. Trailing spaces and runs of blank lines in long pasted blocks are tidied, never inside a code fence and never in the model's own words. A long system prompt goes before short ones in the system block. On a model that reads cache_control, breakpoints mark the end of the stable prefix so cached input rates apply. A text counts as a document from 256 characters.

aggressive is lossy: it also replaces the turns before the last 6 messages with a summary written by the cheapest paid model your key can use, or the one you name with ; model=<id> (; keep=<n> moves the cut). The summary is its own request, metered and billed whatever happens next. A thread under 12 messages is not summarized. The last user turn and any tool call still waiting on its result are never summarized. On the answer, x-antimatter-compress says what was done, the tokens before and after and the saving at the serving model's price. Tokens are counted by the model's own tokenizer where Antimatter has it and marked approximate otherwise.

curl https://useantimatter.com/v1/chat/completions \
  -H "Authorization: Bearer $ANTIMATTER_API_KEY" \
  -H "Content-Type: application/json" \
  -H "x-antimatter-compress: safe" \
  -d @long-thread.json -D - | grep x-antimatter-compress

x-antimatter-compress: safe; before=48210; after=19044; tokens=exact;
  saved_micros=72915; actions=whitespace:2,dedupe:3

Redaction

This is off unless a key asks for it. Set piiRedact on the key's policy (the dashboard's key card, or PATCH /api/keys/{id}/policy) and every message's text and tool call arguments are scanned before anything else reads them. Email addresses, phone numbers, card numbers that pass the Luhn check and carry a known issuer, IBANs that pass their mod 97 check, US social security numbers and UK national insurance numbers each become a typed placeholder such as [EMAIL_1]. One value is one placeholder however often it appears. The model, the cache, the flight recorder's capture and the hold all see the placeholders and never the values. The scan is linear in the text.

redact returns the answer as the model wrote it, placeholders included. restore puts the values back into the answer, in a JSON answer and in a stream chunk by chunk, so the caller reads its own data and the provider never sees it. Every answer carries x-antimatter-pii-redacted with the count and x-antimatter-pii-kinds with the kinds. The values live in the request's memory only and are never written or logged. Pictures, files and audio are not read, and embeddings are not redacted. Names and street addresses are not detected, because no pattern finds them reliably. A prompt that holds them is sent as it is.

curl https://useantimatter.com/v1/chat/completions \
  -H "Authorization: Bearer $ANTIMATTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"inclusionai/ling-3.0-tiny","messages":[{"role":"user","content":"Draft a reply to ada@example.com"}]}' \
  -D - | grep x-antimatter-pii

x-antimatter-pii-redacted: 1
x-antimatter-pii-kinds: email=1

Prompts

Keep a prompt on the dashboard's Keys tab and call it by id instead of sending its text. A prompt has versions that never change once saved, each a list of messages whose text may hold {{variables}}, and labels such as production and staging that point at one. Name it with the prompt field on chat completions or Responses, or the x-antimatter-prompt header, with a version number, a label, or neither for the production label when it is set, else the newest version.

The gateway renders it before anything else. The version's messages come first, then the request's own, and a request that names no model takes the version's. A value the version needs and the request leaves out is a 400 with code prompt_variable_missing, and a value it never names is prompt_variable_unknown. The hold, the policy and the bill are those of the rendered request. Every answer names the version in x-antimatter-prompt-version, and the request log records it. Only keys of the account that holds a prompt can find it.

curl https://useantimatter.com/v1/chat/completions \
  -H "Authorization: Bearer $ANTIMATTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt":{"id":"pmpt_...","version":"production","variables":{"customer":"Ada"}},
       "messages":[{"role":"user","content":"Where is my order?"}]}' \
  -D - | grep x-antimatter-prompt

x-antimatter-prompt-version: pmpt_...@3

Anthropic APIPOST/v1/messages

The Anthropic messages format over the same catalog, keys and credits. Authenticate with x-api-key or a bearer token. max_tokens is required. The Anthropic SDK works with its base URL set to https://useantimatter.com. OpenAI's Responses API is at POST /v1/responses, stateless.

curl https://useantimatter.com/v1/messages \
  -H "x-api-key: $ANTIMATTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "meta-llama/llama-3.1-8b-instruct",
    "max_tokens": 512,
    "messages": [{"role": "user", "content": "Hello"}]
  }'