Integration guide

Fifteen minutes to a sealed ledger.

Five integration paths, all exercised against a live frontier model before this page was written. Pick the one that matches your stack; they all land in the same tamper-evident chain.

STEP 1

Sign up, create a project

One project per AI system. You get a project id and mint an API key with ingest scope from the dashboard - the key is shown once and stored only as a hash.

STEP 2

Point your traces at us

Pick a path below. The OTLP route is usually two environment variables; the SDK adds the richer compliance events when you want them.

STEP 3

Verify and attest

Watch sessions appear as sealed traces, re-verify the chain any time, and generate evidence packs mapped to EU AI Act articles when a buyer or auditor asks.

OpenTelemetry (any language)

You already emit OTel traces - most agent frameworks do.

# Any OpenTelemetry exporter, any language - two env vars:
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://YOUR_HOST/v1/otlp/<projectId>/v1/traces
OTEL_EXPORTER_OTLP_TRACES_HEADERS=authorization=Bearer atst_YOUR_KEY

# Spans using the GenAI semantic conventions (gen_ai.*) map automatically:
#   gen_ai.operation.name = chat          -> model.call
#   gen_ai.operation.name = execute_tool  -> tool.call
#   gen_ai.operation.name = invoke_agent  -> decision
# Token usage (gen_ai.usage.*) is carried into the sealed payload.

Zero code change: set two environment variables and your existing GenAI spans become sealed ledger events.

Vercel AI SDK

TypeScript agents on the ai package.

import { generateText } from "ai";
import { createAzure } from "@ai-sdk/azure";
// Register any OTel NodeTracerProvider with an OTLP exporter
// pointed at your AttestAI project endpoint (see the env vars tab),
// then switch telemetry on. That is the whole integration:

const result = await generateText({
  model: azure("gpt-5.5"),
  tools: { policyLookup },
  prompt: "Review claim CLM-1003 for approval.",
  experimental_telemetry: { isEnabled: true },
});
// Every step - model calls, tool calls, agent decisions - arrives
// in AttestAI sealed, with token counts.

The SDK's built-in telemetry does all the span work - we tested this against live gpt-5.5 with tools and multi-step loops.

Python

Python agents - OpenAI SDK, LangChain, or hand-rolled.

# pip install opentelemetry-sdk opentelemetry-exporter-otlp-proto-http
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter

provider = TracerProvider()
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter(
    endpoint="https://YOUR_HOST/v1/otlp/<projectId>/v1/traces",
    headers={"authorization": "Bearer atst_YOUR_KEY"},
)))
trace.set_tracer_provider(provider)

tracer = trace.get_tracer("claims-agent")
with tracer.start_as_current_span("chat") as span:
    span.set_attribute("gen_ai.operation.name", "chat")
    span.set_attribute("gen_ai.request.model", "gpt-5.5")
    # ... call your model as usual

Standard OpenTelemetry, no AttestAI-specific package required.

LangChain.js

You want per-callback control instead of spans.

import { AttestClient } from "@attest/sdk";
import { BaseCallbackHandler } from "@langchain/core/callbacks/base";

const attest = new AttestClient({ baseUrl, apiKey, projectId, systemId: "claims-agent" });

class AttestHandler extends BaseCallbackHandler {
  name = "attest";
  async handleLLMEnd(output, runId) {
    attest.log({ type: "model.call", sessionId, payload: { runId, usage: output.llmOutput?.tokenUsage } });
  }
  async handleToolEnd(output, runId) {
    attest.log({ type: "tool.call", sessionId, payload: { runId } });
  }
}
// pass the handler in callbacks: [...] - nothing else changes

A callback handler bridges LangChain events to the SDK - useful when you also want human.approval and incident.flagged events.

Native SDK

Maximum evidence: oversight, disclosures, incidents.

# set once in your agent's environment:
# ATTEST_API_KEY=atst_...  ATTEST_PROJECT_ID=...  ATTEST_BASE_URL=https://YOUR_HOST

import { attestFromEnv } from "@attest/sdk";
const attest = attestFromEnv();   // that's the whole setup

// already on OpenTelemetry? one line instead:
// new NodeSDK({ traceExporter: new AttestSpanExporter() })

const run = attest.session(crypto.randomUUID(), "claims-agent");
run.start({ task: "review claim CLM-1003" });
run.modelCall("gpt-5.5", { usage: { input: 91, output: 24 } });
run.toolCall("policy_lookup", { policy: "P-88341" });
run.decision({ payout: 12400, currency: "EUR" });
run.humanOverride("m.reeves", { action: "approved" });
run.disclosureShown({ channel: "chat-banner" });
run.end({ outcome: "settled" });
await attest.flush();
// batched + serialized + retried; every batch carries an idempotency
// key, so a retry after a lost response can never double-record

The typed taxonomy (17 event types) is where compliance evidence gets richer than debugging traces: disclosure.shown, human.override, incident.flagged.

Verification and evidence

The point of the ledger is that anyone can check it.

# Prove the record whenever you like:
curl -H "authorization: Bearer atst_YOUR_KEY" \
  https://YOUR_HOST/v1/projects/<projectId>/verify
# -> { "valid": true, "checkedEvents": 184209, "headHash": "..." }

# Evidence pack for an audit or questionnaire:
curl -X POST -H "authorization: Bearer atst_YOUR_KEY" \
  -H "content-type: application/json" \
  -d '{"framework":"eu-ai-act-art12-19","periodStart":"...","periodEnd":"..."}' \
  https://YOUR_HOST/v1/projects/<projectId>/packs

# Everything is exportable - stream the full ledger, hash columns included,
# for independent re-verification or your own warehouse:
curl -H "authorization: Bearer atst_YOUR_KEY" \
  "https://YOUR_HOST/v1/projects/<projectId>/export?format=jsonl"   # or csv

Enterprise deployment

Self-serve today, EU-dedicated or self-hosted at scale.

The pilot runs against our hosted EU endpoint with your own org, keys and retention policy. Enterprise plans add dedicated EU infrastructure or a self-hosted build inside your own VPC, DPA included - the ledger design is identical either way.