SDK — Ananke TCode usage
Stamp PDFs, manage TDoc and placement templates, verify DataMatrix payloads, and run bulk stamping jobs with the @ananke/sdk.
TDoc templates
TDoc templates define the DataMatrix payload schema — which fields are encoded inside the barcode. Access them via client.tcode.templates.
// List all TDoc templates (returns flat array, not paged)
const templates = await client.tcode.templates.list();
console.log(templates[0].name);
// Get a single template
const tmpl = await client.tcode.templates.get("tdoc-uuid");
// Create a new TDoc template
const newTmpl = await client.tcode.templates.create({
name: "Invoice Stamp",
fields: [
{ key: "documentId", label: "Document ID", required: true },
{ key: "issuedAt", label: "Issue Date", required: true },
{ key: "amount", label: "Amount", required: false },
],
});
// Get CSV field metadata for bulk stamping
const csvFields = await client.tcode.templates.getCsvFields("tdoc-uuid");| Method | Description |
|---|---|
list(opts?) | All TDoc templates (flat array) |
get(id) | Single template by ID |
create(body) | Create template |
update(id, body) | Full update |
delete(id) | Permanently delete |
archive(id, reason?) | Soft-archive |
unarchive(id) | Restore archived |
getCsvFields(id) | CSV column metadata for bulk uploads |
Placement templates
Placement templates control where the DataMatrix barcode is rendered on the PDF: position (x/y), size, page number, and optional label text. Access them via client.tcode.placement.
// List all placement templates
const placements = await client.tcode.placement.list();
// Create a placement template
const placement = await client.tcode.placement.create({
name: "Bottom-right corner",
pageNumber: 1,
x: 450,
y: 50,
size: 80,
labelText: "Scan to verify",
});
// Duplicate an existing placement
const copy = await client.tcode.placement.duplicate("placement-id", "Copy of bottom-right");| Method | Description |
|---|---|
list(opts?) | All placement templates |
get(id) | Single placement template |
create(body) | Create placement template |
update(id, body) | Full update |
delete(id) | Delete |
duplicate(id, name) | Copy with a new name |
Stamp a PDF
Use client.tcode.documents.stamp() to embed a DataMatrix barcode into a PDF. Each stamp gets a unique reference and is cryptographically anchored.
import { readFileSync } from "node:fs";
const stamp = await client.tcode.documents.stamp({
name: "Invoice #1234",
tdocTemplateId: "tdoc-uuid",
placementTemplateId: "placement-uuid", // optional: uses default if omitted
dataMatrixFields: {
documentId: "INV-1234",
issuedAt: "2026-01-15",
amount: "1500.00",
},
pdf: readFileSync("./invoice.pdf"),
pdfFileName: "invoice-1234.pdf",
});
console.log(stamp.reference); // "TCR-XXXX"
console.log(stamp.status); // "Active"Request fields
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Human-readable document name |
tdocTemplateId | string | Yes | TDoc template defining the payload schema |
placementTemplateId | string | No | Where to render the barcode on the PDF |
dataMatrixFields | object | Yes | Key/value pairs matching the TDoc template fields |
pdf | PdfInput | No | Source PDF (Buffer, base64, Blob, File) |
pdfFileName | string | No | Original filename |
recipientEmail | string | No | Optional delivery email |
List & manage stamps
// Paged listing
const page = await client.tcode.documents.list({
tdocTemplateId: "tdoc-uuid",
status: "Active",
page: 1,
pageSize: 25,
});
// Auto-paginate all stamps
for await (const stamp of client.tcode.documents.listAll()) {
console.log(stamp.reference);
}
// Get full details
const detail = await client.tcode.documents.get("TCR-XXXX");
// Download the stamped PDF
const blob = await client.tcode.documents.download("TCR-XXXX");Lifecycle management
// Suspend a stamp (temporary)
await client.tcode.documents.suspend("TCR-XXXX");
// Revoke permanently
await client.tcode.documents.revoke("TCR-XXXX");
// Reactivate a suspended stamp
await client.tcode.documents.reactivate("TCR-XXXX");
// Replace with updated data / PDF
const replaced = await client.tcode.documents.replace("TCR-XXXX", {
dataMatrixFields: { documentId: "INV-1234-v2", issuedAt: "2026-03-01" },
pdf: readFileSync("./invoice-v2.pdf"),
});
// Duplicate check before stamping
const check = await client.tcode.documents.duplicateCheck({
tdocTemplateId: "tdoc-uuid",
dataMatrixFields: { documentId: "INV-1234" },
});
if (check.isDuplicate) {
console.log("Already exists:", check.existingReference);
}Verification
Verify Ananke TCode stamps by reference, hash, or raw DataMatrix payload. Query scan history and digital twin records.
// Verify by stamp reference
const result = await client.tcode.verify.byReference("TCR-XXXX");
console.log(result.verdict); // "valid" | "revoked" | "suspended" | "not_found"
// Verify a raw decoded DataMatrix payload
const rawPayload = "v1:TCR-XXXX:sig:..."; // from camera scan
const scanResult = await client.tcode.verify.verify(rawPayload);
// Lookup by hash
const lookup = await client.tcode.verify.lookupByHash("sha256:abcd...");
// Verification history
const history = await client.tcode.verify.history("TCR-XXXX");
// Scan events for a stamp
const scans = await client.tcode.verify.documentScans("TCR-XXXX");
// Digital twin record
const twin = await client.tcode.verify.digitalTwin("TCR-XXXX");
// Get the active signing public key
const key = await client.tcode.verify.getPublicKey();Mobile offline sync
Mobile scanners can pre-fetch stamp data for offline verification using syncScans:
const sync = await client.tcode.verify.syncScans({
since: "2026-01-01T00:00:00Z",
templateIds: ["tdoc-uuid"],
});
// sync.records — compact verification data for offline use
// sync.syncedAt — use as "since" for next incremental syncPayload verifier (offline)
The payload verifier performs client-side ECDSA signature verification against raw DataMatrix payloads — no network roundtrip after the initial key cache fetch. Ideal for high-throughput scan pipelines (warehouse scanners, event gate readers).
// Via the client instance (shares key cache)
const verifier = client.tcode.payloadVerifier;
// Or standalone (useful in workers / edge functions)
import { TCodePayloadVerifier } from "@ananke/sdk";
const verifier = new TCodePayloadVerifier({
baseUrl: "https://api.anankelabs.io",
apiKey: process.env.ANANKE_API_KEY!,
});
// Verify a raw DataMatrix payload
const result = await verifier.verify("v1:TCR-XXXX:sig:...");
console.log(result.verdict); // "valid" | "invalid_signature" | "revoked" | "suspended" | "not_found" | "error"
console.log(result.reference); // "TCR-XXXX"
console.log(result.fields); // decoded payload fields
// Parse without verifying (useful for UI display before verification completes)
const parsed = verifier.parse("v1:TCR-XXXX:sig:...");
console.log(parsed.reference, parsed.fields);
// Force key cache refresh (e.g. after key rotation)
await verifier.refreshCache();Verdicts
| Verdict | Meaning |
|---|---|
valid | Signature verified, stamp is active |
invalid_signature | ECDSA check failed — payload may be forged or corrupted |
revoked | Signature valid but stamp has been permanently revoked |
suspended | Signature valid but stamp is temporarily suspended |
not_found | Reference not found in this tenant |
error | Verification could not be completed (network or key fetch failure) |
Bulk jobs
Bulk stamping lets you stamp hundreds of PDFs from a CSV plus an optional ZIP of source documents.
import { readFileSync } from "node:fs";
// 1. Get CSV field schema
const fields = await client.tcode.templates.getCsvFields("tdoc-uuid");
// 2. Submit the bulk job
const csv = readFileSync("./batch.csv");
const zip = readFileSync("./pdfs.zip");
const job = await client.tcode.bulkJobs.create({
tdocTemplateId: "tdoc-uuid",
placementTemplateId: "placement-uuid",
csvFileBase64: csv.toString("base64"),
zipFileBase64: zip.toString("base64"),
});
console.log(job.id, job.status); // "Queued"
// 3. Poll for completion
let progress;
do {
progress = await client.tcode.bulkJobs.getProgress(job.id);
console.log(`${progress.status}: ${progress.successCount}/${progress.totalCount}`);
if (progress.status !== "Completed" && progress.status !== "Failed") {
await new Promise(r => setTimeout(r, 2000));
}
} while (progress.status !== "Completed" && progress.status !== "Failed");
// 4. Get full details (includes all rows in response body)
const detail = await client.tcode.bulkJobs.get(job.id);
const failed = detail.rows.filter(r => r.status === "Failed");
// 5. Retry failed rows
if (failed.length) await client.tcode.bulkJobs.retry(job.id);| Method | Description |
|---|---|
create(body) | Submit a new bulk stamping job |
list(opts?) | Paged list of jobs |
listAll(opts?) | Async generator — all jobs |
get(jobId) | Job detail including all rows |
getProgress(jobId) | Lightweight status poll |
retry(jobId) | Retry failed rows |
cancel(jobId) | Cancel queued/running job |
Note: tcode.bulkJobs.get() returns all rows embedded in the response. For large jobs this can be a sizable payload. Use getProgress() for lightweight status polling.