Why Use E2EE?
With E2EE enabled, your messages are encrypted client-side using the model’s public key, which is cryptographically bound to its TEE attestation. This provides:- Defense in depth — Multiple independent encryption layers on top of TLS
- Model-specific encryption — Only model environments holding the attested model key can decrypt your messages
- Cryptographic binding — Messages are tied to a verified TEE through attestation
- Forward secrecy — Each request uses ephemeral keys
Via Gateway
Encryption Protocol
E2EE uses Ed25519 keys with the v2 encryption protocol:
Wire format for all encrypted fields:
[ephemeral_pubkey (32 bytes)][nonce (24 bytes)][ciphertext + tag]
Quick Start
A Python script that demonstrates the E2EE encryption flow after you have obtained a verified model public key: generate a client key pair, encrypt, send, and decrypt. For a gateway report, verify every returned model-attestation candidate before applying your acceptance policy to select a key; the endpoint-specific attestation guides describe those checks. Requirements:pip install requests PyNaCl cryptography
- PyNaCl — Ed25519-to-X25519 key conversion and XChaCha20-Poly1305 AEAD
- cryptography — X25519 ECDH key exchange and HKDF-SHA256 key derivation
Step-by-Step Guide
Step 1: Get the Model’s Public Key
Fetch the model’s Ed25519 public key from its TEE attestation report. The public key is generated inside the Model TEE and cryptographically bound to its hardware attestation. Reject a missing or emptymodel_attestations[], verify every returned candidate and its fresh nonce, then choose one verified report under your application’s acceptance policy. Use that report’s signing_public_key as the X-Model-Pub-Key routing pin. See NEAR model attestations.
The gateway endpoint requires an API key (Authorization: Bearer <api-key>); report retrieval is free and never counts against your usage.
- curl (Gateway)
- Python
- JavaScript
provider=near with a canonical model ID and x-no-aliasing: true. Reject a missing or empty model_attestations[], verify every returned model-report candidate with the nonce you generated, and retain only reports your application accepts. Select a key only from that verified set, then send its signing_public_key in X-Model-Pub-Key.
Step 2: Generate Client Key Pair
Generate an Ed25519 key pair for your client. The model will use your public key to encrypt the response.- Python
- JavaScript
Step 3: Encrypt Your Messages
Encrypt message content using the model’s public key. The protocol uses X25519 ECDH key exchange, HKDF-SHA256 key derivation, and XChaCha20-Poly1305 symmetric encryption.- Python
- JavaScript
Step 4: Make the Encrypted Request
Send your encrypted messages with the required headers. The model will decrypt your message, process it, and encrypt the response using your public key.- curl (Gateway)
- Python
- JavaScript
Required Headers
Step 5: Decrypt the Response
The responsecontent, reasoning_content, and reasoning fields can contain hex-encoded encrypted data. Decrypt each field that is present using your private key.
- Python
- JavaScript
Encrypting All Fields (Tool Calling)
By default, E2EE covers the message fieldscontent, reasoning_content, reasoning, and audio.data. If you use tool calling, the tool definitions and the model’s tool calls also contain sensitive data. Send X-Encrypt-All-Fields: true to extend encryption to:
With the flag set, encrypt each of these fields client-side with the model’s public key exactly like message content (the
parameters JSON schema is serialized to a string and encrypted whole), and decrypt the corresponding response fields with your private key:
tool_calls you echo back on the assistant message and the tool result content on the tool role message the same way.
When using the server-side web search tool with E2EE, the injected
nearai_tool_result.output chunks are always encrypted to your key, regardless of X-Encrypt-All-Fields.Important Notes
Supported Endpoints
E2EE is supported on the Chat Completions API (/v1/chat/completions), Completions API (/v1/completions), Embeddings API (/v1/embeddings), and Images API (/v1/images/generations). The Responses API (/v1/responses) does not support encrypted input messages.
Message Format
- Encrypted message content must be hex-encoded
- The
content,reasoning_content, andreasoningfields in responses can be hex-encoded encrypted data - Each streaming chunk’s content is independently encrypted
Verification
Before using a model public key for encryption, verify the attestation report and its fresh client nonce against hardware attestation. For a gateway response, verify every returned model-attestation candidate and choose a key only from reports accepted by your policy. See Verification for the Gateway verification flow.Legacy: ECDSA Encryption
ECDSA encryption uses SECP256K1 ECDH + HKDF-SHA256 + AES-256-GCM with 64-byte (128 hex) public keys.
ECDSA encryption uses SECP256K1 ECDH + HKDF-SHA256 + AES-256-GCM with 64-byte (128 hex) public keys.
Get the Model’s ECDSA Public Key
Verify every returned model-attestation candidate and its fresh nonce before applying your acceptance policy and using a selected public key, as described in NEAR model attestations.Generate ECDSA Client Key Pair
Encrypt with ECDSA
Send ECDSA Encrypted Request
Decrypt ECDSA Response
See Also
- Private Inference — How TEE isolation protects your data
- Verification — Verify NEAR AI Cloud Gateway requests
- Verification Policy — Define the evidence your application requires