Issuance
Create and deliver verifiable digital documents. This page covers the issuance request, required inputs, lifecycle states, and error handling.
Overview
Issuance creates a new document under your tenant. The document is signed, stored, and optionally anchored for tamper-evidence. You can deliver the document to a recipient via email or retrieve it programmatically.
Issuance request
Send a POST request to /v1/trust/issuances with a JSON body. The SDK wraps this as client.trust.documents.issue().
const doc = await client.trust.documents.issue({
templateId: "tmpl-uuid",
recipientName: "Jane Doe",
recipientEmail: "jane@example.com",
documentTitle: "Certificate of Completion",
fields: [
{ key: "certNumber", value: "C-2026-001" },
{ key: "course", value: "Platform Engineering" },
{ key: "grade", value: "Distinction" },
],
});curl -X POST https://api.anankelabs.net/v1/trust/issuances \
-H "x-api-key: ak_live_..." \
-H "Content-Type: application/json" \
-d '{
"templateId": "tmpl-uuid",
"recipientName": "Jane Doe",
"recipientEmail": "jane@example.com",
"documentTitle": "Certificate of Completion",
"fields": [
{ "key": "certNumber", "value": "C-2026-001" },
{ "key": "course", "value": "Platform Engineering" }
]
}'Required fields
| Field | Type | Description |
|---|---|---|
templateId | string | ID of the template to use for this issuance. |
recipientName | string | Full name of the document recipient. |
fields | array | Key–value pairs matching the template's field schema. |
Optional fields
| Field | Type | Description |
|---|---|---|
recipientEmail | string | Recipient email address. If provided, Ananke Labs may deliver the document via email. |
documentTitle | string | Custom title for this specific document. |
externalId | string | Your system's ID for correlation and duplicate detection. |
pdf | Buffer | Blob | string | PDF file to attach (see PDF attachment section below). |
expiresAt | string (ISO 8601) | Optional expiration date for the document. |
PDF attachment
You can attach a PDF to an issuance. The SDK normalises multiple input formats:
Buffer— Node.js Buffer (most common server-side)Uint8Array/ArrayBuffer— Raw bytesBlob/File— Browser typesstring— Base64-encoded content
import { readFileSync } from "node:fs";
const doc = await client.trust.documents.issue({
templateId: "tmpl-uuid",
recipientName: "Jane Doe",
fields: [{ key: "certNumber", value: "C-2026-001" }],
pdf: readFileSync("./certificate.pdf"),
});Response
A successful issuance returns the created document object:
{
"data": {
"id": "uuid",
"reference": "TRF-ABCD1234",
"status": "Active",
"recipientName": "Jane Doe",
"recipientEmail": "jane@example.com",
"documentTitle": "Certificate of Completion",
"templateId": "tmpl-uuid",
"fields": [
{ "key": "certNumber", "value": "C-2026-001" }
],
"createdAt": "2026-03-18T10:00:00Z"
}
}Lifecycle states
| Status | Description | Verification verdict |
|---|---|---|
Active | Document is valid and verifiable. | valid |
Suspended | Temporarily disabled. Can be reactivated. | suspended |
Revoked | Permanently invalidated. Terminal state. | revoked |
Expired | Past the expiration date. Cannot be reactivated. | expired |
Lifecycle transitions
After issuance, you can change a document's status using the lifecycle endpoint:
await client.trust.documents.lifecycle(doc.id, {
action: "suspend",
reason: "Under review",
});Valid transitions:
Active → SuspendedActive → RevokedSuspended → Active(reinstate)Suspended → Revoked
Revoked and Expired are terminal — no further transitions are possible.
Replacement
Replacement creates a new document version linked to the original. The original is automatically revoked. Use this when the document content has changed but the credential should remain traceable.
const replacement = await client.trust.documents.replace(doc.id, {
recipientName: "Jane Doe",
fields: [
{ key: "certNumber", value: "C-2026-002" },
{ key: "course", value: "Platform Engineering — Updated" },
],
});Duplicate detection
Before issuing, you can check for duplicates using the externalId or field values:
POST /v1/trust/issuances/duplicate-check
{
"templateId": "tmpl-uuid",
"externalId": "your-system-id-123"
}Returns 409 Conflict if a matching document already exists, or 200 OK if clear.
Errors
| Status | Reason |
|---|---|
400 | Missing or invalid fields. Check the validation error details. |
404 | Template not found under this tenant. |
409 | Duplicate detection fired — a matching document already exists. |
422 | Template is archived or field schema mismatch. |
Next steps
- Verification — Verify issued documents.
- Templates — Configure reusable document schemas.
- Guide: Issue a document — Step-by-step tutorial.
- Ananke Trust API Reference — Full endpoint docs.