Example: the ImprintAI write contract
Write
POST {base}/api/imprint
Content-Type: application/json
Authorization: Bearer <Txpass session JWT>
- Never send
X-API-Key. Imprint checks it first, so it would shadow the Bearer. (@txpass/agentrefuses caller-suppliedX-API-Key,AuthorizationandCookieheaders.) - Same route as API-key callers.
Body
model is the only required field (non-empty string). Optional:
| Field | Type / rule |
|---|---|
model_version | string |
type | string, ≤ 100 chars, default "created" |
digital_source_type | default "ai_generated" |
prompt, negative_prompt | string |
settings | object: seed, steps, cfgScale, width, height (numbers), sampler (string), custom keys |
encryptedPrompts | strict envelope; cannot be mixed with plaintext prompts |
workflow_id | string. Without previous_txid it may auto-chain to the caller's latest record in that workflow, so do not send it in tests. |
previous_txid | 64 hex |
output_hash or sha256 | 64 hex |
canonical_pixel_hash, input_summary_hash | 64 hex |
perceptual_hash | ≤ 256 chars |
custom | object |
async (bool) or mode: "async" | async processing |
Minimal test body (imprintMinimalBody() in @txpass/agent):
{ "model": "txpass-agent-e2e", "type": "created", "async": true,
"input_summary_hash": "<random 64 hex>", "custom": { "txpass_test": "example" } }
Responses
| HTTP | Body | Meaning |
|---|---|---|
| 200 | { txid, success: true, job_id, workflow_id } (maybe auto_chained, previous_txid, mock, warning) | sync success |
| 202 | { success: true, txid: null, job_id, status: "pending", workflow_id, status_url: "/api/status/<job_id>" } | async, or sync still pending after ~10 s |
| 400 | { txid: "", success: false, error: { … } } | validation |
| 401 | { "error": "Invalid Txpass session" }; with no credential at all { "error": "Missing API key" } | bad/expired/revoked-and-introspected token, or no header |
| 402 | { "error": "Buy or renew a Txpass subscription for this product" } | identity has no live entitlement |
| 429 | { "error": "Daily rate limit exceeded", usage, limit, resetsAt } | quota |
| 500 | { txid: "", success: false, job_id, error } | server error |
Poll
GET {base}/api/status/<job_id>
Authorization: Bearer <same Txpass session JWT>
Returns { job_id, status, txid, error, created_at, updated_at }, status ∈ pending | broadcast | confirmed | failed, txid null until available. Polling does not consume quota. 404 { "error": "Job not found" } = missing or not owned by this identity (sub).
An agent writing to Imprint therefore needs scope POST /api/imprint and GET /api/status/:jobId, or no scope (product default, which includes both).
Cost of one real write
One mainnet provenance record, broadcast and paid by Imprint's operator wallet, and one unit of the delegating identity's free quota (50/day, 1000/month on production).