Docs
Use the official Node/TypeScript SDK, Python SDK, CLI, or raw HTTP API to capture provenance for AI generations, verify outputs, and move from local to production without changing your evidence contract.
Use @authenchain/node for Node.js/TypeScript backends and authenchain from sdks/python for Python AI services, data pipelines, and model-serving workloads.
Use API keys in Authorization: Bearer ac_test_example_... or x-api-key. Keep keys server-side only.
Never expose AuthenChain keys in browser bundles, screenshots, support tickets, or chat transcripts.
Production examples use https://authenchain.com. Local development may use http://localhost:3000. Set AUTHENCHAIN_BASE_URL explicitly so environment intent is clear.
https://authenchain.com/verify. No backend refactor is required.What AuthenChain is for
- Sign AI outputs at generation time.
- Verify origin and integrity later in your pipeline.
- Attach review-ready provenance to agents, orchestrators, and regulated workflows.
AuthenChain verifies origin and integrity properties when content was signed at creation time. It does not judge truthfulness or detect AI on its own.
Official SDKs
Choose the SDK that matches the customer server runtime. All official SDKs preserve the same AuthenChain evidence contract: server-side API key, final output boundary, signed metadata, trace ID, signature, public key ID, verification, Evidence Pack export, and customer-owned legal interpretation.
| Runtime | Package / path | Use for | Main methods |
|---|---|---|---|
| Node.js / TypeScript | @authenchain/node, sdks/node/ | Next.js, Express, workers, LLM orchestration, agent backends. | sign, verify, captureGeneration, wrapGeneration, captureRegulatedOutput, verifyRegulatoryEvidence, exportEvidencePack, verifyEvidencePack. |
| Python | authenchain, sdks/python/ | FastAPI, Flask, Celery, notebooks, model-serving, data science pipelines. | sign, verify, capture_regulated_output, verify_regulatory_evidence, export_evidence_pack, verify_evidence_pack, validate_regulatory_metadata. |
| Any backend runtime | Raw HTTPS API | Java, Go, Ruby, PHP, .NET, or private runtimes without an official SDK. | POST /api/provenance/sign, POST /api/provenance/verify, GET /api/provenance/evidence-pack, POST /api/public/evidence/verify. |
There is no official Java, Go, Ruby, PHP, or .NET SDK in this repository today. Those runtimes should use the HTTP API contract shown below until an official SDK is shipped.
Customer server implementation
A production integration should live entirely in the customer backend. The customer stores raw prompts, inputs, outputs, and workflow records locally, while AuthenChain signs hashes and minimized metadata for later technical verification.
- 1. Create a server-side API key with least-privilege scopes.
- 2. Add AuthenChain environment variables to the customer backend.
- 3. Choose the final output boundary after guardrails and formatting.
- 4. Store raw input and output in the customer system, preferably encrypted.
- 5. Calculate input/output hashes with
authenchain.content.v1. - 6. Send
content_hash,contentEvidence, and regulatory metadata to/api/provenance/sign. - 7. Store
trace_id,signature,public_key_id,signed_at, andcontentEvidence. - 8. Recalculate hashes during disputes, audits, or export to detect any changed input/output.
- 9. Export an Evidence Pack by trace ID or time window when review evidence is needed.
- 10. Verify the Evidence Pack through the dashboard, API, or public verifier.
AUTHENCHAIN_ENABLED=1 AUTHENCHAIN_BASE_URL=https://authenchain.com AUTHENCHAIN_API_KEY=ac_live_... AUTHENCHAIN_TIMEOUT_SEC=8 AUTHENCHAIN_SIGN_MODE=best_effort AUTHENCHAIN_POLICY_VERSION=customer-ai-output-policy-v1
Recommended scopes for a production AI backend are provenance:sign, provenance:verify, provenance:events, and audit:export. Add webhooks:read and webhooks:write only for automation keys that manage webhooks.
CREATE TABLE ai_regulatory_evidence (
id TEXT PRIMARY KEY,
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
request_id TEXT,
user_ref TEXT,
action TEXT NOT NULL,
model_provider TEXT,
model_name TEXT,
risk_context TEXT,
input_hash TEXT NOT NULL,
output_hash TEXT NOT NULL,
content_canonicalization TEXT NOT NULL DEFAULT 'authenchain.content.v1',
evidence_hash TEXT NOT NULL UNIQUE,
input_payload JSONB NOT NULL DEFAULT '{}'::jsonb,
output_payload JSONB NOT NULL DEFAULT '{}'::jsonb,
regulatory_payload JSONB NOT NULL DEFAULT '{}'::jsonb,
authenchain_trace_id TEXT,
authenchain_content_hash TEXT,
authenchain_signature TEXT,
authenchain_public_key_id TEXT,
authenchain_signed_at TEXT,
authenchain_status TEXT NOT NULL DEFAULT 'pending',
authenchain_payload JSONB NOT NULL DEFAULT '{}'::jsonb
);curl -X POST "$AUTHENCHAIN_BASE_URL/api/provenance/sign" \
-H "Authorization: Bearer $AUTHENCHAIN_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: req_123:evidence_hash" \
-H "X-Request-Id: req_123" \
-d '{
"content_hash": "64_hex_chars_for_regulatory_evidence_envelope",
"contentEvidence": {
"captureMode": "hash_only",
"input": {
"content_hash": "64_hex_chars_from_authenchain_content_v1",
"rawContentStored": false
},
"output": {
"content_hash": "64_hex_chars_from_authenchain_content_v1",
"rawContentStored": false
}
},
"metadata": {
"issuer": "customer-ai-backend",
"content_type": "text",
"created_at": "2026-05-28T16:00:00.000Z",
"nonce": "nonce-1234567890abcd",
"trace_id": "00000000-0000-4000-8000-000000000000",
"model": "gpt-5.1",
"regulatory": {
"schema_version": "regulatory.v1",
"ai_generated": true,
"jurisdiction": "BR",
"risk_context": "high",
"human_reviewed": false,
"human_oversight_required": true,
"disclosure_required": true,
"disclosure_applied": true,
"policy_version": "customer-ai-output-policy-v1"
}
}
}'The full repository guide is docs/customer-server-implementation-guide.md. It includes Node.js, Python, Evidence Pack, public verifier, webhook, anchor/publication, retry, and acceptance-test examples.
10-minute Quickstart
- 1. Create an API key in the dashboard.
- 2. Install the SDK for the customer backend runtime.
- 3. Capture provenance when your model or agent produces an output.
- 4. Persist the returned signature, trace ID, and public key ID with the generated artifact.
- 5. Verify the output later anywhere in your backend pipeline.
npm install @authenchain/node
cd sdks/python python -m pip install -e .
import { AuthenChain } from '@authenchain/node'
const ac = new AuthenChain({
apiKey: process.env.AUTHENCHAIN_API_KEY!,
baseUrl: process.env.AUTHENCHAIN_BASE_URL,
timeoutMs: 10_000,
})
const captured = await ac.captureGeneration({
output: 'final answer generated by the agent',
issuer: 'customer-support-agent',
model: 'gpt-5.1',
generateMetadataDefaults: true,
extra: {
source: 'support-orchestrator',
prompt_id: 'prompt_123',
},
})
const verification = await ac.verify({
content: captured.output,
provenance: captured.provenance,
})import os
from authenchain import AuthenChain
client = AuthenChain(
api_key=os.environ["AUTHENCHAIN_API_KEY"],
base_url=os.getenv("AUTHENCHAIN_BASE_URL", "https://authenchain.com"),
timeout=10.0,
)
signed = client.sign(
content="final answer generated by the agent",
metadata={
"issuer": "customer-support-agent",
"content_type": "text",
"model": "gpt-5.1",
},
generate_metadata_defaults=True,
)
verification = client.verify(
content="final answer generated by the agent",
provenance=signed,
)Capture generation
Use captureGeneration when your application already has the final output and you want AuthenChain to sign it immediately with generation metadata.
const captured = await ac.captureGeneration({
output: completion.text,
issuer: 'research-agent',
model: completion.model,
user_ref: 'user_42',
trace_id: workflowTraceId,
generateMetadataDefaults: true,
extra: {
source: 'batch-evaluator',
model_version: '2026-03-01',
pipeline: 'claims-review-v2',
},
})
console.log(captured.provenance.traceId)
console.log(captured.provenance.signature)
console.log(captured.provenance.publicKeyId)const captured = await ac.captureGeneration({
output: {
verdict: 'approved',
confidence: 0.98,
},
issuer: 'underwriting-agent',
model: 'gpt-5.1-mini',
generateMetadataDefaults: true,
serializeOutput: (value) => JSON.stringify(value),
})Wrap generation
Use wrapGeneration when you want the SDK to run your generation function and return the result plus its provenance in one step.
const run = await ac.wrapGeneration({
issuer: 'ops-agent',
model: 'gpt-5.1',
run: async () => {
const response = await llm.responses.create({
model: 'gpt-5.1',
input: 'Summarize incident INC-204',
})
return {
raw: response,
text: response.output_text,
}
},
mapOutput: (result) => result.text,
})
console.log(run.result.raw.id)
console.log(run.output)
console.log(run.provenance.traceId)Python SDK
Use the Python SDK for AI services written in Python, model-serving APIs, batch jobs, notebooks, and data science pipelines. Python method names use snake_case; JSON wire fields returned by AuthenChain keep the same API keys used by the HTTP API and Evidence Packs.
import os
from authenchain import AuthenChain
client = AuthenChain(
api_key=os.environ["AUTHENCHAIN_API_KEY"],
base_url=os.getenv("AUTHENCHAIN_BASE_URL", "https://authenchain.com"),
timeout=10.0,
max_retries=2,
)
regulatory = {
"schema_version": "regulatory.v1",
"ai_generated": True,
"jurisdiction": "BR",
"regulatory_context": ["customer_regulated_output"],
"content_type": "text",
"model_provider": "openai",
"model_name": "gpt-5.1",
"system_purpose": "customer_support_response",
"risk_context": "limited",
"human_reviewed": False,
"disclosure_required": True,
"disclosure_applied": True,
"label_type": "human_visible",
"policy_version": "ai-disclosure-policy-v1",
}
captured = client.capture_regulated_output(
output="Final AI answer shown to the user.",
issuer="support-answer-service",
content_type="text",
model="gpt-5.1",
user_ref="ticket_123",
regulatory=regulatory,
extra={"source": "python-backend"},
generate_metadata_defaults=True,
idempotency_key="ticket_123:final_answer_v1",
request_id="req_123",
correlation_id="req_123",
)
print(captured["provenance"]["traceId"])
print(captured["regulatory"]["legalCompliance"])verification = client.verify_regulatory_evidence(
content="Final AI answer shown to the user.",
provenance=captured["provenance"],
)
pack = client.export_evidence_pack(
trace_id=captured["provenance"]["traceId"],
)
pack_verification = client.verify_evidence_pack(evidence_pack=pack)
combined = client.verify_regulatory_evidence(
content="Final AI answer shown to the user.",
provenance=captured["provenance"],
evidence_pack=pack,
verification_scope="combined",
)
print(verification["provenanceVerified"])
print(pack_verification["trustedStatus"])
print(combined["regulatoryEvidenceStatus"])
print(combined["legalCompliance"])from authenchain import AuthenChain
client = AuthenChain(mock=True)
signed = client.sign(
content="local test output",
metadata={
"issuer": "local-test",
"content_type": "text",
},
generate_metadata_defaults=True,
)
verification = client.verify(content="local test output", provenance=signed)
print(verification["environment"])Python mock mode is useful for examples, tests, local CI, and sales engineering demos. It must not be presented as externally trustworthy evidence. For production, use a live API key and server-side environment variables.
Official examples
Use the official examples in sdks/node/examples/ and sdks/python/examples/ when you need a partner-ready starting point for a real provider, agent runtime, backend route, or Python AI service.
openai-basic: OpenAI Responses API withwrapGenerationand immediate verification.langchain-basic: LangChain chat integration with AuthenChain provenance attached to the final output.agent-runtime-basic: multi-step orchestration example showing where AuthenChain fits in agent flows.next-route-example: Next.js route handler pattern for server-side generation plus provenance.sign-basicandverify-basic: low-level reference flows for direct signing and validation.sdks/python/examples/regulated-text-output: minimal Python regulated output capture and verification.sdks/python/examples/credit-decision-auditandsdks/python/examples/medical-ai-traceability: Python regulated workflow examples with tamper checks.sdks/python/examples/evidence-pack-export-verify: Python Evidence Pack export and public verification flow.
Partner PoC kit
The repository also includes a partner-ready PoC kit in poc/. These flows are designed for solution demos, buyer conversations, and governance reviews where you need to show business risk and evidence, not just API usage.
For partner architecture, integration, and commercial positioning guidance, see docs/partners.md.
clinical-ai-assistant: clinically relevant summary, later altered, with original verification and tampered failure.claim-analysis-ai: insurance claim rationale changed after generation, then independently audited.credit-decision-ai: risk-support recommendation challenged after generation in a fintech-style workflow.
Low-level sign / verify
Use these methods when you want explicit control over content vs. pre-computed hashes, or when you are integrating AuthenChain below your generation layer.
const provenance = await ac.sign({
content: 'hello world',
metadata: {
issuer: 'agent-router',
content_type: 'text',
created_at: new Date().toISOString(),
nonce: 'nonce-1234567890abcd',
trace_id: '00000000-0000-4000-8000-000000000000',
},
})const verification = await ac.verify({
content: 'hello world',
provenance,
})Regulated content evidence
Regulated integrations can keep raw prompts, inputs, and outputs inside the customer system while sending AuthenChain hash-only evidence. When you send pre-computed input/output hashes, calculate them with the authenchain.content.v1 canonicalization contract shown below. Do not send a plain sha256(raw_text) value and label it as AuthenChain content evidence.
import { createHash } from 'node:crypto'
function canonicalJson(value: unknown): string {
if (value === null) return 'null'
if (typeof value === 'string') return JSON.stringify(value)
if (typeof value === 'boolean') return value ? 'true' : 'false'
if (typeof value === 'number') {
if (!Number.isFinite(value)) throw new Error('non_finite_number')
return JSON.stringify(value)
}
if (Array.isArray(value)) return '[' + value.map(canonicalJson).join(',') + ']'
if (typeof value === 'object' && value) {
const row = value as Record<string, unknown>
return '{' + Object.keys(row)
.sort()
.map((key) => JSON.stringify(key) + ':' + canonicalJson(row[key]))
.join(',') + '}'
}
throw new Error('unsupported_json_value')
}
function authenchainContentHash(content: string) {
const canonicalBody = canonicalJson({
canonicalization: 'authenchain.content.v1',
content,
encoding: 'utf8',
})
return createHash('sha256').update(canonicalBody, 'utf8').digest('hex')
}
const canonicalInputJson = canonicalJson({ messages: [{ role: 'user', content: 'Question' }] })
const inputHash = authenchainContentHash(canonicalInputJson)
const outputHash = authenchainContentHash(finalAiOutputText)For structured input, first create a deterministic JSON string for the official input boundary, then pass that string as content. For output, use the exact final text or artifact body delivered to the user after guardrails and formatting.
curl -X POST https://authenchain.com/api/provenance/sign \
-H "Authorization: Bearer ac_test_example_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: regulated-output-0001" \
-d '{
"content_hash": "64_hex_chars_for_regulatory_envelope",
"contentEvidence": {
"captureMode": "hash_only",
"input": {
"content_hash": "64_hex_chars_from_authenchain_content_v1",
"rawContentStored": false
},
"output": {
"content_hash": "64_hex_chars_from_authenchain_content_v1",
"rawContentStored": false
}
},
"metadata": {
"issuer": "customer-ai-backend",
"content_type": "text",
"created_at": "2026-05-28T00:00:00.000Z",
"nonce": "nonce-1234567890abcd",
"trace_id": "00000000-0000-4000-8000-000000000000",
"regulatory": {
"schema_version": "regulatory.v1",
"ai_generated": true,
"jurisdiction": "BR",
"risk_context": "high",
"policy_version": "customer-ai-output-policy-v1"
}
}
}'The signed provenance payload stores these hashes as contentEvidence.input.contentHash and contentEvidence.output.contentHash, both with canonicalization: authenchain.content.v1. Any later one-character change in the official input or output produces a different hash during verification.
HTTP API reference
These endpoints are what the SDK calls under the hood. They remain stable and compatible with the current backend.
curl -X POST https://authenchain.com/api/provenance/sign \
-H "Authorization: Bearer ac_test_example_..." \
-H "Content-Type: application/json" \
-d '{
"content": "hello world",
"metadata": {
"issuer": "acme-inc",
"content_type": "text",
"created_at": "2026-03-06T00:00:00.000Z",
"nonce": "nonce-1234567890abcd",
"trace_id": "00000000-0000-4000-8000-000000000000"
}
}'{
"trace_id": "...",
"content_hash": "...",
"metadata": { ... },
"signature": "...",
"public_key_id": "...",
"kid": "...",
"algorithm": "Ed25519",
"signed_at": "..."
}curl -X POST https://authenchain.com/api/provenance/verify \
-H "Authorization: Bearer ac_test_example_..." \
-H "Content-Type: application/json" \
-d '{
"content": "hello world",
"metadata": {
"issuer": "acme-inc",
"content_type": "text",
"created_at": "2026-03-06T00:00:00.000Z",
"nonce": "nonce-1234567890abcd",
"trace_id": "00000000-0000-4000-8000-000000000000",
"schema_version": "1.0"
},
"signature": "...",
"public_key_id": "..."
}'{
"trace_id": "...",
"verified": true,
"reason": null,
"content_hash": "...",
"origin_verified": true,
"integrity": "intact",
"issuer_verified": true,
"reason_codes": [],
"verified_at": "..."
}Events API
Retrieve review-ready provenance events by trace ID or paginate recent events for the current API key.
GET /api/provenance/events?trace_id=TRACE_ID GET /api/provenance/events?limit=50&cursor=EVENT_ID
Webhooks
Receive provenance.signed and provenance.verified events in downstream systems.
POST /api/webhooks
Request body:
{ "url": "https://example.com/webhooks" }
Runtime headers today:
X-AITL-Signature: v1=<hex_hmac>
X-AITL-Timestamp: <unix_ms>
X-AITL-Event-Id: <event_id>
Preferred header names:
X-AuthenChain-Signature: v1=<hex_hmac>
X-AuthenChain-Timestamp: <unix_ms>
X-AuthenChain-Event-Id: <event_id>function verifySignature(secret, headers, rawBody) {
const signatureHeader =
headers["x-authenchain-signature"] || headers["x-aitl-signature"];
const timestamp =
headers["x-authenchain-timestamp"] || headers["x-aitl-timestamp"];
if (!signatureHeader || !timestamp) return false;
const [version, received] = String(signatureHeader).split("=");
if (version !== "v1" || !received) return false;
const base = "v1." + timestamp + "." + rawBody;
const expected = require("crypto")
.createHmac("sha256", secret)
.update(base, "utf8")
.digest("hex");
return expected === received;
}Rate limits & errors
Verification mismatches are not transport errors. The API returns 200 with verified: false and reason codes for content or signature mismatches. Malformed requests still return 4xx.
401: INVALID_API_KEY | KEY_REVOKED | KEY_EXPIRED 403: INVALID_KEY_OWNERSHIP 402: BILLING_INACTIVE 429: RATE_LIMITED | MONTHLY_QUOTA_EXCEEDED 413: PAYLOAD_TOO_LARGE 400: INVALID_JSON | INVALID_PAYLOAD 503: RATE_LIMIT_BACKEND_UNAVAILABLE
Protected responses may include x-trace-id, x-quota-limit, x-quota-remaining, x-quota-reset-at, and Retry-After.
Operational notes
- Sign at generation time whenever possible. Provenance added later proves handling, not original creation.
- Store
trace_id,signature, andpublic_key_idwith every signed artifact. - Use stable nonces and workflow trace IDs to correlate retries, jobs, and downstream verification.
- Handle
429with backoff and respectRetry-After.
Security notes
AuthenChain stores hashes and signed metadata, not raw text or media, unless your deployment adds that separately.
Do not place PII or secrets in metadata. If you must associate sensitive data, tokenize or encrypt it before submission.
For regulated workflows, keep raw prompts, raw outputs, and protected records in the customer system when possible, then send contentEvidence hashes and minimized regulatory metadata to AuthenChain.