POST /v1/chat/completions. The gateway relays what you send and checks its shape. The cryptography runs on your device and inside the sealed hardware.
Variants
The attestation you fetch before the call selects the variant. Read itsproof_format. The same marker may also appear inside the raw evidence.
Keys
The model’s public key comes from the attestation asmodel_public_key, with signing_algo naming its type: ed25519 (32 bytes) or ecdsa on secp256k1 (64 bytes, or 65 with the 04 prefix). Verify the evidence before using it. See Verify It Yourself.
Your key pair matches the model key’s type and lives for the conversation:
ed25519: generate an ed25519 key pair. The header carries the 32-byte public key as hex. For key agreement, convert your secret key and the model’s public key to their X25519 forms.ecdsa: generate a secp256k1 key pair. The header carries the uncompressed 65-byte public key as hex. A 64-byte model key is prefixed with04before use.
Encrypting a Message
For eachmessages[].content string:
- Agree a shared secret between the ephemeral secret key and the model’s public key.
ed25519: X25519 over the converted keys.ecdsa: the x coordinate (32 bytes) of the secp256k1 ECDH point. - Derive the symmetric key with HKDF-SHA256: input the shared secret, no salt, 32 bytes out, with the info string
ed25519_encryptionfor ed25519 orecdsa_encryptionfor ecdsa. - Encrypt the UTF-8 plaintext. Standard and Legacy with an ed25519 key: XChaCha20-Poly1305 with a random 24-byte nonce. Every other case: AES-256-GCM with a random 12-byte nonce. On the Authenticated variant, pass the request’s additional authenticated data (below).
- Build the envelope: the ephemeral public key, the nonce, then the ciphertext with its authentication tag, concatenated and hex encoded. Replace the content string with it.
Content must be a nonblank string. Content arrays are rejected.
Additional Authenticated Data (Authenticated variant)
Generate one request nonce of 24 random bytes as hex, as the Browser App does (the gateway requires at least 16 characters), and a timestamp of the current Unix time in seconds, which the backend may reject when stale. Send both in the headers and bind them into every envelope:m is the zero-based position of the message in messages, and c is - for a string content. For model, bind the attestation’s provider_model_id with any privacy suffix removed and, where it carries a backend prefix, rewritten to the model maker’s prefix (for example z-ai/glm-5.3). That is what the Browser App binds.
Headers
Older spellings of these headers are accepted during migration. If the same header is sent under two names with different values, the request is rejected.
Decrypting the Reply
choices[].message.content comes back as an envelope of the same shape. Split off the ephemeral public key and the nonce by the lengths above, agree the shared secret between your conversation secret key and that ephemeral public key, derive the symmetric key with the same HKDF parameters, and decrypt. A reasoning summary, where the model returns one, is an envelope too.
On the Authenticated variant the reply’s additional authenticated data is:
id taken from the response body. The backend’s model value is not fixed, so try candidates in this order until one authenticates: the response body’s model, the value you bound on the request, the attestation’s provider_model_id, and the public model ID, each with any privacy suffix removed and, where it carries a backend prefix, its model-maker alias. Try the response id and an empty id. For an ecdsa reply the Browser App accepts a key derived with either the ecdsa_encryption info string or secp256k1-aes-256-gcm-hkdf-sha256, and the algorithm spellings ecdsa, ecdsa-secp256k1, or secp256k1-aes-256-gcm-hkdf-sha256. Mirroring that candidate search is the conservative choice for a new client.
With stream: true on the Standard variant, each delta’s content is an envelope. Reassemble the stream and decrypt. On the Authenticated variant use the non-streaming path, as the Browser App does.
Response Signature Evidence
On supported backends,nito-encrypted-response-evidence: 1 with stream: false returns the original upstream request and response bytes plus signature proof. Your client verifies the signature and its binding to fresh attestation before consuming a reply that requires this assurance. See Response Evidence for fields, verification steps, and limits.
The Encrypted Tool Loop
Withnito-encrypted-encrypt-all-fields: 1 on the Standard variant, function tools work with every field encrypted. Encrypt, as separate envelopes, each tool’s function.name, function.description, and function.parameters (the JSON schema, serialized to a string), any tool_choice function name, and, on later turns, each assistant tool_calls[].function.name and .arguments and each tool message’s content. The reply’s tool calls arrive with the id in plaintext and the name and arguments as envelopes. Decrypt them, run the tool on your side, encrypt the result, and send the next request. Only function tools are accepted in this mode.
What the Gateway Rejects
All return400 invalid_request before any provider call.
- Any Encrypted header without
nito-encrypted: 1. - The headers with a model that is not an
:encryptedentry, or an:encryptedmodel without the headers. - A signing algorithm other than
ed25519orecdsa. - A version other than
2, or a version on the Legacy variant. - A nonce or timestamp on the Legacy variant.
- A missing nonce, a nonce shorter than 16 characters, or a missing timestamp on the Authenticated variant.
nito-encrypted-encrypt-all-fieldsoff the Standard variant, or with a value other than1.- Content arrays, a content string that is not nonblank even-length hex, and raw image, file, or document parts.
web_searchorweb_fetchon the request, prompt caching, anduncensored=true.- Encrypted headers on
/v1/responses,/v1/messages,/v1/messages/count_tokens, or MCP.
Libraries
The Browser App uses the@noble/curves, @noble/ciphers, and @noble/hashes packages for the operations above.
Related
Encrypted on the API
The reference page.
Get Attestation
Where the key comes from.
How It Works
The call, step by step.

