API Spec

OpenAI-compatible chat completions with signed receipts and hardware-attestation evidence at api.confidential.ai.

The Confidential Inference API provides OpenAI-compatible chat completions at https://api.confidential.ai. The gateway validates the caller key at the public boundary. It does not forward that key to the inference node.

New here? Overview explains the attested inference flow before you make a request.

All endpoints use HTTPS. Every response contains an x-request-id header. Save this value when a completion receipt is needed.

Quickstart

Set an API key and read the available model list. Use a listed model ID in a completion request.

export CONFIDENTIAL_API_KEY='<API_KEY>'
export CONFIDENTIAL_API_BASE='https://api.confidential.ai'

curl --fail --silent "$CONFIDENTIAL_API_BASE/v1/models" | jq .
curl --fail --silent "$CONFIDENTIAL_API_BASE/v1/chat/completions" \
  -H "Authorization: Bearer $CONFIDENTIAL_API_KEY" \
  -H 'Content-Type: application/json' \
  --data '{
    "model": "<MODEL_ID_FROM_V1_MODELS>",
    "messages": [{"role": "user", "content": "Reply with one word: ready."}],
    "stream": false
  }' | jq .

Attestation

Attestation lets you verify the confidential path before you send a prompt. The public attestation endpoint needs no API key. It returns fresh evidence from both the gateway and the inference worker. It does not contain your API key, prompt, or completion.

Use this sequence for a verified request:

  1. Generate a new 32-byte nonce and call GET /v1/aci/attestation.
  2. Verify the gateway and worker evidence, the nonce bindings, and the advertised receipt-signing key.
  3. Use an API key provisioned for your application to call POST /v1/chat/completions.
  4. Save the completion response x-request-id and fetch its receipt.
  5. Verify the receipt signature against the receipt-signing key in the attestation response.
  6. Request fresh attestation when you need new proof. If you revoke an API key, the gateway rejects later use of that key with 401 invalid_api_key.

What the evidence proves

The response contains two linked hardware evidence records.

  • Gateway evidence. The public gateway uses native Intel TDX evidence with profile tdx-direct/v1. Its quote binds the caller nonce, the live gateway TLS identity, and the public key that verifies completion receipts. Verify the quote signature, the expected gateway measurement and TCB policy, and every report-data binding before you trust this claim.
  • Worker evidence. The gateway obtains fresh c8s Intel TDX evidence from the inference worker. The worker evidence binds the caller nonce to the worker TLS public key for the verified private worker channel. API clients do not connect to that channel directly. Verify the quote signature, expected worker measurement and TCB policy, and its TLS-key binding.
  • Receipt evidence. A completed request has an Ed25519-signed receipt. The receipt contains request and response hashes, safe request metadata, and the signature. Verify it with the receipt public key that the gateway attestation advertises.

This proof does not prove that the model output is correct, that the service is available, or that an API key belongs to a particular person. It does not prevent denial of service. It proves only the verified software and TLS identities represented by the evidence, for the nonce and policy values you verify.

Call the API

Use these calls in order when you need an attested completion. Set the base URL once. Replace placeholders with values from your account and model catalog.

export CONFIDENTIAL_API_BASE='https://api.confidential.ai'
export CONFIDENTIAL_API_KEY='<API_KEY>'

1. Get fresh attestation before you send a prompt

Generate a new 32-byte nonce. This endpoint is public. Do not send an API key or prompt with this request.

NONCE="$(openssl rand -base64 32 | tr '+/' '-_' | tr -d '=')"

curl --fail --silent \
  "$CONFIDENTIAL_API_BASE/v1/aci/attestation?nonce=$NONCE" | jq .

Verify the returned gateway and worker evidence before you send sensitive input. Check the nonce bindings, the expected measurements and TCB policies, the TLS-key bindings, and the advertised receipt-signing key. See Request and verify attestation for the full checks.

2. Send a non-streaming completion

Use a model ID returned by GET /v1/models. The completion endpoint requires an API key. Save the x-request-id response header; you use it to read the receipt.

curl --fail --silent --show-error \
  --dump-header response-headers.txt \
  "$CONFIDENTIAL_API_BASE/v1/chat/completions" \
  -H "Authorization: Bearer $CONFIDENTIAL_API_KEY" \
  -H 'Content-Type: application/json' \
  --data '{
    "model": "<MODEL_ID_FROM_V1_MODELS>",
    "messages": [
      {"role": "user", "content": "Explain why the sky appears blue in two sentences."}
    ],
    "stream": false
  }' | jq .

REQUEST_ID="$(awk 'BEGIN { IGNORECASE = 1 } /^x-request-id:/ { gsub("\\r", ""); print $2 }' response-headers.txt)"

3. Read the signed receipt

Receipts are public and do not require an API key. They contain request and response hashes, safe metadata, and a signature. They do not contain the prompt or completion.

curl --fail --silent \
  "$CONFIDENTIAL_API_BASE/v1/aci/receipts/$REQUEST_ID" | jq .

Verify the Ed25519 signature with the receipt-signing key in the attestation response from step 1. See Read and verify a receipt.

4. Check health and list models

These public endpoints are useful before normal application traffic. Health is a readiness check, not hardware evidence. The model catalog is the allowed model list for completion requests.

curl --fail --silent "$CONFIDENTIAL_API_BASE/health" | jq .
curl --fail --silent "$CONFIDENTIAL_API_BASE/v1/models" | jq .

Stream a completion

Use the same API key and model ID. The response is server-sent events and ends with data: [DONE].

curl --no-buffer --fail --silent --show-error \
  "$CONFIDENTIAL_API_BASE/v1/chat/completions" \
  -H "Authorization: Bearer $CONFIDENTIAL_API_KEY" \
  -H 'Content-Type: application/json' \
  --data '{
    "model": "<MODEL_ID_FROM_V1_MODELS>",
    "messages": [
      {"role": "user", "content": "Give three short facts about oceans."}
    ],
    "stream": true
  }'

Optional compatibility and supporting routes

GET /v1/attestation/report is a compatibility representation of the same attestation evidence. GET /v1/aci/sessions/{session_id} returns supporting worker-attestation session data linked by the canonical attestation response. Use the canonical GET /v1/aci/attestation response for new integrations.

Authentication

POST /v1/chat/completions requires this header:

Authorization: Bearer <API_KEY>

The health, model, receipt, and attestation endpoints do not require a caller API key. Do not put an API key in an attestation request or browser code.

All JSON errors use this shape:

{"error":{"code":"machine_readable_code"}}

Create a chat completion

POST /v1/chat/completions

Accepts an OpenAI-compatible chat-completions request. model is required and must exactly match an ID from GET /v1/models. The gateway relays the remaining valid request fields to the configured OpenAI-compatible inference service.

FieldTypeRequiredDescription
modelstringyesAn exact model ID from GET /v1/models.
messagesarraypassed throughOpenAI-compatible messages. The gateway forwards this field unchanged.
streambooleannofalse or omitted returns JSON. true returns server-sent events.

A non-streaming success is an OpenAI-compatible completion object with HTTP 200 OK.

{
  "id": "chatcmpl-example",
  "object": "chat.completion",
  "model": "model-id",
  "choices": [{
    "index": 0,
    "message": {"role": "assistant", "content": "ready"},
    "finish_reason": "stop"
  }]
}

For "stream": true, the response content type is text/event-stream. The stream contains OpenAI-compatible chunks and ends with data: [DONE].

data: {"object":"chat.completion.chunk","choices":[{"delta":{"content":"ready"}}]}

data: [DONE]

List models

GET /v1/models

Returns the public model catalog. This endpoint does not query an inference worker.

{
  "object": "list",
  "data": [
    {"id": "model-id", "object": "model"}
  ]
}

Request and verify attestation

GET /v1/aci/attestation?nonce={base64url}

Returns the canonical attestation document. It does not require an API key. nonce must be unpadded base64url and decode to exactly 32 random bytes. Each nonce is single use.

NONCE="$(openssl rand -base64 32 | tr '+/' '-_' | tr -d '=')"

curl --fail --silent \
  "$CONFIDENTIAL_API_BASE/v1/aci/attestation?nonce=$NONCE" | jq .

The response has this shape. Evidence values are abbreviated. Use exact returned values during verification.

{
  "api_version": "aci/1",
  "workload_id": "gateway-workload-id",
  "workload_keyset_digest": "sha256:...",
  "attestation": {
    "vendor": "intel",
    "tee_type": "tdx",
    "workload_keyset": {"receipt_signing_keys": [{"algo": "ed25519", "public_key": "..."}]},
    "report_data": "128-hex-character-value",
    "aci_statement_digest": "64-hex-character-value",
    "evidence": {
      "gateway": {
        "profile": "tdx-direct/v1",
        "attestation_api": {"platform": "tdx", "evidence": {"quote": "..."}}
      },
      "upstream_session_id": "as_...",
      "node": {"node_nonce": "...", "node_spki_sha256": "sha256:...", "c8s_evidence": {}}
    }
  }
}

HTTP 200 does not prove attestation. Verify all bindings:

  1. Decode attestation.report_data as 64 bytes. Its final 32 bytes must equal the nonce. Its first 32 bytes must equal SHA-256(signing_address || tls_certificate_fingerprint).
  2. Read the live TLS certificate and compute its fingerprint. The signing_address is the raw public key of the Ed25519 receipt-signing key published in attestation.workload_keyset.receipt_signing_keys.
  3. Decode the Intel TDX quote in attestation.evidence.gateway.attestation_api. Verify its signature and collateral, then evaluate it against your expected gateway measurement and TCB policy. Its 64-byte report-data field must equal the value from step 1.
  4. Verify attestation.evidence.node.c8s_evidence with the expected TDX measurement and TCB policy. Its report data must bind the node TLS SPKI and nonce. Compare the verified node SPKI hash with node_spki_sha256.
  5. Fetch the linked session and verify its evidence digest and TLS channel binding.

This gateway uses the tdx-direct/v1 profile. Its Intel TDX quote binds the full 64-byte report-data value directly.

Invalid nonce input returns 400 invalid_attestation_request. Reusing a nonce returns 409 attestation_nonce_replayed. A full nonce guard returns 429 attestation_nonce_store_full. If the gateway or node cannot produce fresh evidence, the endpoint returns 503 attestation_unavailable. Treat 503 as a failed attestation result.

GET /v1/attestation/report?version=2&signing_algo=ecdsa&nonce={base64url}

Returns a compatibility representation of the same gateway and node evidence. The parameters must be exactly version=2, signing_algo=ecdsa, and a new 32-byte base64url nonce. Do not reuse a nonce from the canonical endpoint.

NONCE="$(openssl rand -base64 32 | tr '+/' '-_' | tr -d '=')"

curl --fail --silent \
  "$CONFIDENTIAL_API_BASE/v1/attestation/report?version=2&signing_algo=ecdsa&nonce=$NONCE" \
  | jq .

It contains signing_address, a base64-encoded 64-byte report_data, gateway_attestation, and node_attestation. Apply the same TDX gateway and node verification checks as for the canonical representation. This representation does not include api_version: "aci/1" or aci_statement_digest.

GET /v1/aci/sessions/{session_id}

Returns the short-lived node-attestation session linked by upstream_session_id in an attestation response.

{
  "api_version": "aci/1",
  "session_id": "as_...",
  "channel_binding": [{"type": "tls_spki_sha256", "spki_sha256": "sha256:..."}],
  "claims": {},
  "evidence": {
    "digest": "sha256:...",
    "data": "data:application/json;base64,..."
  }
}

Decode the evidence data URL and verify its SHA-256 digest before parsing it. Compare the session TLS SPKI binding with the node binding in the attestation response. The session is supporting evidence. It does not replace gateway or node attestation verification. Unknown or expired sessions return 404 session_not_found.

Read and verify a receipt

GET /v1/aci/receipts/{request_id}

Returns a signed receipt for a recent completed request. Use the x-request-id response header from POST /v1/chat/completions as {request_id}.

curl --fail --silent \
  "$CONFIDENTIAL_API_BASE/v1/aci/receipts/$REQUEST_ID" | jq .
{
  "draft": {
    "request_id": "request-id",
    "status": 200,
    "request_sha256": "sha256:...",
    "response_sha256": "sha256:...",
    "streaming": false
  },
  "created_at_unix_ms": 0,
  "algorithm": "ed25519",
  "signing_address": "base64url-ed25519-public-key",
  "signature": "base64url-ed25519-signature"
}

The receipt contains hashes and safe request metadata only. It does not contain the prompt, completion, API key, or receipt private key. Receipts expire after 15 minutes. An unknown, expired, or unavailable receipt returns 404 with receipt_not_found.

Verify the Ed25519 signature with signing_address. The signed payload has these exact fields:

{
  "api_version": "aci/1",
  "purpose": "inference.receipt.v1",
  "request_id": "...",
  "request_sha256": "sha256:...",
  "response_sha256": "sha256:...",
  "status": 200,
  "streaming": false
}

Use a verifier that serializes this receipt payload exactly as the API defines. Then verify that the receipt key is bound by attestation evidence that you trust.

Health

GET /health

Returns gateway readiness. It is not attestation evidence.

curl --fail --silent "$CONFIDENTIAL_API_BASE/health" | jq .
{"status":"ok"}

When the gateway cannot use its verified inference-node channel, it returns 503 Service Unavailable, Retry-After: 1, and:

{"status":"unavailable"}

Errors and retry rules

HTTPCode or bodyMeaningClient action
400invalid_requestCompletion JSON is invalid or model is missing.Correct the request.
400invalid_attestation_requestAttestation parameters are invalid.Generate a valid new nonce.
401invalid_api_keyThe caller key is missing or invalid.Obtain a valid key. Do not retry unchanged.
404model_not_foundThe model is not in the catalog.Use GET /v1/models.
404receipt_not_foundThe receipt is unavailable or expired.Use the correct recent request ID.
404session_not_foundThe attestation session is unavailable or expired.Request new attestation with a new nonce.
409attestation_nonce_replayedThe attestation nonce was already used.Generate a new nonce.
429upstream_unavailableThe verified node path is temporarily unavailable.Honor Retry-After and retry safely.
429attestation_nonce_store_fullThe nonce guard is full.Back off and retry with a new nonce.
503attestation_unavailableFresh gateway or node evidence is unavailable.Fail closed. Do not accept cached or partial evidence.
503{"status":"unavailable"}The gateway is not ready.Honor Retry-After and retry.