Developer Guide

If you use the OpenAI SDK, you are 3 lines away. Every call gets a signed, verifiable receipt.

1. Get a key

Sign up at /signup, then mint an API key at /api-keys. Keys start with atk_.

2. Python (OpenAI SDK)

python
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-id

3. 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.

python
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-id

Short-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.

bash
# 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_token

Want 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.

bash + python
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 inclusion
bash + javascript
npm 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 inclusion

4. Verify a receipt offline

Every call returns x-attestic-receipt-id. Fetch the bundle and verify the Ed25519 signature + Merkle proof, no Attestic access required.

python, offline verification
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 offline

Models

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.