Status & Polling
Records move through a defined lifecycle. Since Certyo doesn't yet support webhooks, clients poll to check status. This guide covers the lifecycle states and how to poll efficiently.
The record lifecycle
- Ingested — the record arrived at the API and was accepted (the state right after
202 Accepted) - PendingAnchor — the record is in the accumulator buffer, waiting for the batch to close
- Batched — the accumulator flushed; a batch document was created; Merkle root computed
- Anchored — the batch's Merkle root was submitted to Polygon and confirmed. This is terminal for the happy path.
- Failed — something went wrong (blockchain timeout, IPFS pin failure, etc.). Certyo retries automatically.
Polling the snapshot status
curl "https://www.certyos.com/api/v1/snapshots?tenantId=acme-corp&recordId=order-12345" \
-H "X-API-Key: $CERTYO_API_KEY"Response (still pending)json
{
"items": [
{
"snapshotId": "snap_xyz789...",
"recordId": "order-12345",
"status": "Batched",
"onChainConfirmed": false,
"onChainMerkleRoot": null,
"ingestedAt": "2026-04-12T15:30:45Z",
"updatedAt": "2026-04-12T15:31:15Z"
}
]
}Response (anchored)json
{
"items": [
{
"snapshotId": "snap_xyz789...",
"recordId": "order-12345",
"status": "Anchored",
"onChainConfirmed": true,
"onChainMerkleRoot": "0x7e2d9a1b3c5f7e...",
"ingestedAt": "2026-04-12T15:30:45Z",
"updatedAt": "2026-04-12T15:32:30Z"
}
]
}Recommended polling pattern
Exponential backoff with a cap
Node.js examplejavascript
async function waitForAnchor(recordId, tenantId, apiKey, maxWaitMs = 120000) {
const start = Date.now();
let delay = 5000; // start at 5s
const maxDelay = 15000; // cap at 15s
while (Date.now() - start < maxWaitMs) {
const res = await fetch(
`https://www.certyos.com/api/v1/snapshots?tenantId=${tenantId}&recordId=${recordId}`,
{ headers: { "X-API-Key": apiKey } }
);
const data = await res.json();
const snapshot = data.items[0];
if (snapshot?.status === "Anchored" && snapshot.onChainConfirmed) {
return snapshot; // Done
}
if (snapshot?.status === "Failed") {
throw new Error("Anchoring failed. Check the lifecycle endpoint for details.");
}
await new Promise((r) => setTimeout(r, delay));
delay = Math.min(delay * 1.5, maxDelay); // backoff
}
throw new Error(`Timed out after ${maxWaitMs}ms waiting for anchor.`);
}Bulk polling
If you're ingesting many records, don't poll one at a time. Query a time range instead:
curl "https://www.certyos.com/api/v1/snapshots?\
tenantId=acme-corp&\
fromTimestamp=2026-04-12T15:00:00Z&\
toTimestamp=2026-04-12T16:00:00Z&\
status=Anchored" \
-H "X-API-Key: $CERTYO_API_KEY"Lifecycle endpoint
For detailed state transition history (useful for debugging), use the lifecycle endpoint:
curl "https://www.certyos.com/api/v1/snapshots/{snapshotId}/lifecycle" \
-H "X-API-Key: $CERTYO_API_KEY"Responsejson
{
"snapshotId": "snap_xyz789...",
"currentStatus": "Anchored",
"transitions": [
{ "status": "Ingested", "at": "2026-04-12T15:30:45Z" },
{ "status": "PendingAnchor", "at": "2026-04-12T15:30:46Z" },
{ "status": "Batched", "at": "2026-04-12T15:31:15Z", "batchId": "batch_abc..." },
{ "status": "Anchored", "at": "2026-04-12T15:32:30Z", "txHash": "0x9a8f7e..." }
]
}Retrying failed anchoring
If a snapshot is stuck in Failed, Certyo's background worker will retry automatically. If you need to force an immediate retry:
curl -X POST "https://www.certyos.com/api/v1/snapshots/{snapshotId}/retry" \
-H "X-API-Key: $CERTYO_API_KEY"