AttachKit API
REST over HTTPS, JSON in / JSON out, bearer-token auth. Same per-user rate limits as the browser flow.
Authentication
Generate a key at /account/api-keys. Keys look like attk_live_xxxxxxxxxxxxxxxx and are shown once at generation; we store only a SHA-256 hash.
Pass the key as a bearer token on every request:
Authorization: Bearer attk_live_xxxxxxxxxxxxxxxxRate limits
Per user (bearer or session): 200/hr for /api/autofill, 60/hr for /api/clause-review, 400/hr for /api/field-help. 429 with Retry-After header when exceeded.
Endpoints
POST /api/autofill
Map a profile to a list of form fields. AI returns suggested values per field.
curl -X POST https://attachkit.com/api/autofill \
-H "Authorization: Bearer attk_live_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"profile": { "name": "Ada Lovelace", "email": "ada@example.com" },
"fields": [
{ "name": "fullName", "type": "text" },
{ "name": "email", "type": "text" }
]
}'
# Response:
# { "mappings": { "fullName": "Ada Lovelace", "email": "ada@example.com" },
# "mode": "ai" }POST /api/clause-review
Flag risky contract clauses in a document's text. Returns a category + severity + snippet + plain-English explanation per finding.
curl -X POST https://attachkit.com/api/clause-review \
-H "Authorization: Bearer attk_live_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{ "text": "This agreement automatically renews for successive twelve-month terms..." }'
# Response:
# { "findings": [
# { "category": "auto_renewal", "severity": "medium",
# "snippet": "...automatically renews for successive twelve-month terms...",
# "explanation": "The contract rolls over for another year unless you cancel before the term ends."
# }
# ],
# "mode": "ai" }POST /api/field-help
Plain-English explanation of a single form field, given its machine name and (optional) context.
curl -X POST https://attachkit.com/api/field-help \
-H "Authorization: Bearer attk_live_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{ "fieldName": "ssn", "fieldType": "text" }'
# Response:
# { "explanation": "Your 9-digit Social Security Number (xxx-xx-xxxx).",
# "source": "ai" }Local-AI mode (Max)
Add X-Use-Local-Ai: 1 to any AI endpoint to request routing through a self-hosted Ollama instead of the cloud AI provider. Only honored if the deployment has OLLAMA_BASE_URL set.
POST /api/verify-timestamp
Re-run the HMAC-SHA256 check that /api/timestamp produces at signing time. The interactive verifier at /verify calls this; it's also useful for scripted audits. No authentication required — the secret never leaves the server.
curl -X POST https://attachkit.com/api/verify-timestamp \
-H "Content-Type: application/json" \
-d '{
"timestamp": "2026-05-24T19:24:52.897Z",
"documentHash": "<64-char hex SHA-256>",
"signature": "<hex HMAC>"
}'
# Response:
# { "valid": true, "reason": null }
# or:
# { "valid": false, "reason": "signature_mismatch" | "missing_signature" | "server_secret_unset" }Audit-page proof format
Signed PDFs from the hardware-key flow embed an attachkit-proof:-prefixed, base64-JSON blob in the PDF Keywords field (the same data is also rendered on the audit page for humans). Format tag is attachkit-proof/v1; payload:
{
"format": "attachkit-proof/v1",
"filename": "lease.pdf",
"signedAt": "2026-05-24T19:24:52.897Z",
"timezone": "America/New_York",
"placementCount": 3,
"hardwareKeyProof": {
"documentHash": "<sha256 hex>",
"credentialId": "<base64url>",
"signature": "<base64url WebAuthn sig>",
"clientDataJSON": "<base64url>",
"authenticatorData": "<base64url>",
"timestamp": "<ISO-8601 UTC>",
"timestampSignature": "<hex HMAC over timestamp + \n + hash>",
"tsaReplyBase64": "<base64 RFC 3161 TimeStampResp>" | null,
"tsaUrl": "<TSA URL>" | null
} | null
}Full WebAuthn signature verification requires the registered passkey's public key (not currently embedded — the sign flow accepts any passkey on the device). For end-to-end verification the auditor pairs the credentialId in the proof block with their own registered-passkey list and re-runs the WebAuthn signature check using the standard W3C spec procedure.
RFC 3161 timestamp verification (when present)
Deployments that set RFC3161_TSA_URL additionally store a TSA-signed token in the proof block (the tsaReplyBase64field). To verify it offline against the TSA's published cert chain:
# decode the token from the proof JSON
echo "<tsaReplyBase64>" | base64 -d > reply.tsr
# fetch the TSA's CA cert (varies by provider — example for freetsa.org)
curl -O https://freetsa.org/files/cacert.pem
# verify against the original (pre-audit-page) document bytes
openssl ts -verify -in reply.tsr -data original.pdf -CAfile cacert.pemWithout RFC3161_TSA_URLset, only the HMAC timestamp is present and verification requires trusting AttachKit's server secret (which means trusting AttachKit).
Content Credentials (C2PA-shaped)
Every signed PDF carries a second tag in the Keywords field — c2pa-manifest:<base64-json> — with spec-aligned C2PA assertion shapes: c2pa.actions.v2, c2pa.hash.data.v1, and stds.schema-org.CreativeWork. The hash binding matches the document hash signed by the user's WebAuthn key, so verifying the WebAuthn signature transitively binds the manifest to the document content.
{
"format": "attachkit-content-credential/v1",
"claim_generator": "AttachKit/0.1.0",
"title": "lease.pdf",
"format_type": "application/pdf",
"instance_id": "urn:uuid:...",
"assertions": [
{ "label": "c2pa.actions.v2", "data": { "actions": [...] } },
{ "label": "c2pa.hash.data.v1", "data": { "alg": "sha256", "hash": "..." } },
{ "label": "stds.schema-org.CreativeWork", "data": { ... } }
],
"signature": {
"alg": "WebAuthn-ES256",
"publicKey": "<base64 SPKI>",
"publicKeyAlgorithm": -7,
"credentialId": "<base64url>",
"signedAt": "<ISO-8601>"
} | null
}Status: assertion shapes + field names follow the C2PA spec, but the signature is currently the same WebAuthn ECDSA signature carried in the audit proof block — not a strict-spec COSE_Sign1 wrapped in JUMBF with an X.509 cert chain. Strict-spec validators (e.g. Adobe Verify) won't recognize the signature container; aware tools that parse JSON manifest fields for human display will.
Why not strict-spec yet: c2patool's official format matrix marks application/pdfas read-only — no open-source C2PA library can currently write a JUMBF blob into a PDF (PDF's incremental-update + xref + existing signature dictionaries make this non-trivial; Adobe hasn't shipped support). We'll revisit when the ecosystem catches up, or ship a sidecar .c2pamanifest if there's demand.
SDKs and beyond
No official SDK yet — the surface is small enough that any HTTP client works.