Developer Docs
Sandbox · API v2PlaygroundGet API keys

Run a print device

Everything a device integrator (or the operator supporting one) needs: enrolment, the polling loop, what to send at each state, and how every failure mode resolves without a database console.

1 · Enrol the device, bind its credential

bash
# Mint a key with aidc:write, then enrol the device and bind the key to it
curl -X POST "$BASE/api/v2/devices" \
  -H "Authorization: Bearer $ADMIN_KEY" -H "Content-Type: application/json" \
  -d '{ "label": "PEX-2000-LINE-3", "kind": "label_printer",
        "connectMode": "raw_9100", "model": "TSC PEX-2000",
        "apiKeyId": "key_01H…" }'

The bound key IS the device's identity: claims, heartbeats and results made with it are attributed to this device (actor_kind: "device", D20), and revoking or disabling the device cuts that credential out of the loop within one lease TTL. An unbound aidc:write key can still issue jobs and report as a human operator, it just cannot claim.

2 · The loop a client runs

flow
loop:
  POST /aidc/jobs/claim { "limit": 1, "lease_seconds": 120 }
  ── no jobs? sleep, poll again (an empty claim is a 200, not an error)
  ── got a job:
     1. VERIFY the envelope signature (eddsa-jcs-2022) BEFORE printing
     2. render          → POST …/result { status: RENDERED,        evidence: render_manifest,  attempt_id }
     3. spool           → POST …/result { status: SPOOL_SUBMITTED, evidence: spool_receipt,    attempt_id }
     4. paper came out  → POST …/result { status: PRINTED_ATTESTED,                            attempt_id }
     5. scan the label  → POST …/result { status: SCAN_VERIFIED,   evidence: scan_result,      attempt_id }
     6. seal            → POST …/result { status: SEALED,          evidence: evidence_bundle,  attempt_id }
  long run? POST …/heartbeat { attempt_id, lease_seconds } before the lease expires
  anything broke? POST …/result { status: FAILED, error_message, attempt_id }

Always send Idempotency-Key on results. Retrying after a timeout is then always safe, the server replays the completed transition instead of double-applying it ("replayed": true in the response).

3 · The error catalogue, and what each one means you should do

RefusalMeaningDo
403 DEVICE_NOT_ENROLLEDThe key is not bound to a device.Enrol the device / bind api_key_id (§1).
403 DEVICE_DISABLEDKill switch, an operator disabled or retired this device.Stop the client; resolve with the operator; re-enable via POST /devices/{id}/status.
409 STALE_ATTEMPTThe lease expired and another claim superseded yours.Drop the job locally, the work now belongs to the new attempt. Never re-report.
410 ENVELOPE_EXPIREDThe envelope's TTL passed before the result arrived.Re-claim; a fresh envelope carries a fresh expiry.
409 LEASE_NOT_HELDHeartbeat for a lease you no longer hold.Same as stale attempt, re-claim.
422 MISSING_EVIDENCEThe target state requires its artifact (render_manifest, spool_receipt, scan_result, evidence_bundle).Send the evidence, the state is unreachable without it, by design.
403 ACTOR_NOT_ALLOWEDPRINTED_ATTESTED asserted by something that is not a device or a human.Only an authenticated device (ODV) or operator may claim paper came out.
409 ILLEGAL_TRANSITIONThe FSM forbids that edge (the message lists what is legal).Fix the client's state model.
422 SERIAL_NOT_ALLOCATED / PASSPORT_NOT_READYCreation gates (issuer side).Allocate via carriers/batch; anchor a validation + publish (F6).

4 · Resolving a stuck job

  • Device crashed mid-job? Nothing to do. When the lease expires the job re-enters the claim pool; the next poll picks it up with a fresh attempt_id and the attempt budget increments.
  • Job keeps failing? After max_attempts the reaper parks it in DEAD_LETTER and the serial lands in GET /carriers/export?printState=failed, the re-print file. Query dead-lettered jobs with GET /aidc/jobs?status=DEAD_LETTER; last_error carries the final failure.
  • Need to stop a device NOW? POST /devices/{id}/status { "status": "disabled" }, it cannot claim again, and in-flight work is reclaimable after its lease.
  • Wrong label in the world? A SEALED job is terminal and its serial is printed on the spine. Recovery runs through the void/reissue axis on the serialization record, never by mutating the job.
Reference client. Norruva maintains a reference print agent that is the executable definition of this contract, claim, lease, heartbeat, evidence chain, idempotent reporting. It is reference and test software, not a supported production deployable.
Was this page helpful?
Thanks, noted.Feedback goes to the docs team by email.