Developer Guide
If you use the OpenAI SDK, you are 3 lines away. Every call gets a signed, verifiable receipt.
2. Python (OpenAI SDK)
from openai import OpenAI
client = OpenAI(
base_url="https://api.attestic.ai/v1",
api_key="atk_your_key_here",
)
response = client.chat.completions.create(
model="gpt-5.5", # or claude-opus-4-8, gemini-3.1-pro-preview,
messages=[ # meta/llama-3.3-70b-instruct, ...
{"role": "user", "content": "Explain provenance in one sentence."}
],
)
print(response.choices[0].message.content)
# Signed receipt in response headers: x-attestic-receipt-id3. Anthropic / Claude SDK
Wrote your app against the Anthropic SDK? Point its base URL here. Same key, same gateway, same signed receipts. Routes any model, not only Claude.
from anthropic import Anthropic
client = Anthropic(
base_url="https://api.attestic.ai",
api_key="atk_your_key_here",
)
msg = client.messages.create(
model="claude-fable-5", max_tokens=512,
messages=[{"role": "user", "content": "Explain provenance in one sentence."}],
)
print(msg.content[0].text)
# Streaming works too: client.messages.stream(...). Receipt: x-attestic-receipt-idShort-lived tokens (recommended for production)
Keep your atk_ key in a vault. Exchange it for a 1-hour access token (OAuth client-credentials) and use that for calls, so a leaked request credential expires within the hour.
# exchange the long-lived key for a short-lived token
curl -s https://api.attestic.ai/v1/oauth/token \
-H "content-type: application/json" \
-d '{"api_key":"atk_your_key_here"}'
# -> { "access_token": "...", "token_type": "Bearer", "expires_in": 3600 }
# then call /v1/chat/completions or /v1/messages with that access_tokenWant to force this pattern? Mint an exchange-only key. It is rejected on direct API calls (401) and can only be traded for a short-lived token, so the long-lived secret never rides on a request.
Optional: the attestic SDK
A thin convenience layer for Python and JavaScript: pre-configured clients, automatic short-lived-token refresh, and one-call offline receipt verification.
pip install attestic[all]
from attestic import Attestic
at = Attestic(api_key="atk_your_key_here") # exchanges + refreshes 1h tokens for you
r = at.openai.chat.completions.create(model="gpt-5.5",
messages=[{"role": "user", "content": "hi"}])
# Verify the call's signed receipt offline, no trust in Attestic required:
assert at.verify(r.id) # Ed25519 signature + Merkle inclusionnpm install attestic openai
import OpenAI from "openai";
import { Attestic } from "attestic";
const at = new Attestic("atk_your_key_here"); // 1h token, auto-refreshed
const client = new OpenAI(await at.openaiConfig());
const r = await client.chat.completions.create({ model: "gpt-5.5",
messages: [{ role: "user", content: "hi" }] });
// Verify the call's signed receipt offline, no trust in Attestic required:
await at.verify(r._request_id); // Ed25519 signature + Merkle inclusion4. Public hash verification (no account)
Every response includes x-attestic-entry-hash in the headers. Anyone — auditors, customers, regulators — can confirm the receipt is real at attestic.ai/verify without seeing model, cost, or tenant details.
# From any API response headers:
ENTRY_HASH="<x-attestic-entry-hash>"
curl -s "https://api.attestic.ai/v1/receipts/check?hash=$ENTRY_HASH"
# -> { "verified": true, "signed_at_ms": ..., "chain_index": ..., "checks": { ... } }
# Or open in a browser:
# https://attestic.ai/verify?hash=$ENTRY_HASH5. Full offline verification (developers)
Authenticated fetch returns the full bundle for your tenant. Verify Ed25519 + Merkle offline with the SDK or manually.
import hashlib, urllib.request, json
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
GW = "https://api.attestic.ai"
bundle = json.load(urllib.request.urlopen(urllib.request.Request(
f"{GW}/v1/receipts/YOUR_RECEIPT_ID",
headers={"Authorization": "Bearer atk_your_key"}
)))
# Verify Ed25519 signature
pk = Ed25519PublicKey.from_public_bytes(bytes.fromhex(bundle["public_key"]))
pk.verify(bytes.fromhex(bundle["signature"]), bytes.fromhex(bundle["signed_bytes"]))
# Verify Merkle inclusion
h = bytes.fromhex(bundle["merkle"]["leaf_hash"])
for step in bundle["merkle"]["proof"]:
sib = bytes.fromhex(step["sibling"])
h = hashlib.sha256((sib + h) if step["side"] == "left" else (h + sib)).digest()
assert h.hex() == bundle["merkle"]["root"] # ✓ verified offlineModels
Route by model id: gpt-5.5, claude-opus-4-8, gemini-3.1-pro-preview, meta/llama-3.3-70b-instruct. GET /v1/models?live=1 returns the real current list from each provider.
Streaming
stream:true works across all providers. The final SSE chunk includes attestic_provenance (receipt_id, entry_hash, signature, cost_usd) inline.
Tools & JSON mode
OpenAI-format tools translate to each provider's native schema. response_format:json_schema works on OpenAI and Gemini natively; best-effort on Anthropic.
Embeddings
POST /v1/embeddings routes text-embedding-3-* to OpenAI and gemini-embedding-* to Gemini. Same auth, same receipts, real token metering.
6. API reference
Base URL https://api.attestic.ai. Authenticate with Authorization: Bearer atk_… or a short-lived token. Account and key management require your JWT; inference and provenance accept either.
Auth & keys
/v1/auth/signupCreate an account; returns a JWT.
/v1/auth/loginExchange email + password for a JWT.
/v1/oauth/tokenTrade an atk_ key for a 1-hour Bearer token.
/v1/keysList your API keys.
/v1/keysMint an atk_ key — the secret is shown once.
/v1/keys/{id}Revoke a key.
Inference (OpenAI / Anthropic-compatible)
/v1/chat/completionsOpenAI-compatible chat. stream:true supported.
/v1/messagesAnthropic-compatible messages.
/v1/embeddingsText embeddings (OpenAI / Gemini).
/v1/modelsRoutable models. ?live=1 queries each provider.
Provenance & verification
/v1/receipts/{id}Full signed receipt + Merkle proof (own tenant).
/v1/receipts/public/{id}Redacted public receipt — no model, cost, or tenant.
/v1/receipts/checkVerify by ?hash= entry hash — public, no account.
/v1/receipts/verifyVerify a receipt bundle server-side.
/v1/provenance/pubkeyThe Ed25519 public key for offline verification.
/v1/transparencyPublic Merkle-chain checkpoint.
/v1/audit/{tenant}Your tenant's signed audit log.
Usage & billing
/v1/usageToken + cost attribution, last 30 days.
/v1/billing/plansAvailable plans.
/v1/billing/portalA Stripe customer-portal link.
7. Errors
Every error returns the same JSON shape and a standard status code. On an upstream provider failure the gateway never synthesizes a completion — it surfaces the error, so a 429 or 5xx can never masquerade as a real (signed) answer.
{ "error": { "type": "invalid_request", "message": "human-readable detail" } }