/docs/credits-api
Credits API reference
The IICP credit system tracks token-based compute spend across the mesh. Coordinators use the quote pre-flight to estimate cost before dispatching CIP tasks. Workers earn credits via the award endpoint after completing a sub-task. All amounts are denominated in credit units — 1 credit ≈ 1 000 inference tokens at the base rate.
GET/api/v1/credits/balance
Returns the credit balance for the authenticated node. The quickest way is the CLI: iicp-node credits (auto-selects your node; v0.7.40+). The API endpoint below is useful for scripts and custom dashboards.
Auth
Authorization: Bearer <node_token>
Request
curl -sf https://iicp.network/api/v1/credits/balance \ -H "Authorization: Bearer <node_token>"
Response 200
{
"node_id": "550e8400-...",
"balance": 38.5,
"unit": "credit",
"tokens_per_credit": 1000
}GET/api/v1/credits/summary
Lifetime income / spending / balance for the authenticated node — earned, spent, and what's left, in one call. reconciles is an integrity check: it is true only when balance == total_earned − total_spent. A tampered or inconsistent ledger surfaces as false — so the numbers are self-checking, not taken on trust.
Operator wallet. When the node is delegation-bound to an operator identity, the response also carries an operator_wallet object that rolls up balance, earned, spent, transaction count and reconcile status across allof the operator's non-archived nodes — one wallet keyed by your identity, backed by per-node audit rows. It is nullwhen the node is not yet operator-bound; the operator's raw public key is never returned.
Auth
Authorization: Bearer <node_token>
Request
curl -sf https://iicp.network/api/v1/credits/summary \ -H "Authorization: Bearer <node_token>"
Response 200
{
"node_id": "550e8400-...",
"total_earned": 142.5,
"total_spent": 38.25,
"balance": 104.25,
"tx_count": 27,
"reconciles": true,
"unit": "credit",
"tokens_per_credit": 1000,
"operator_wallet": { // null when the node is not operator-bound
"total_balance": 263.75, // SUM across all the operator's non-archived nodes
"total_earned": 302.0,
"total_spent": 38.25,
"tx_count": 82,
"node_count": 3,
"reconciles": true,
"operator_fingerprint": "4f93aa10b2c7"
}
}GET/api/v1/credits/quote
CIP pre-flight — estimates the credit cost for a task before dispatch (S.12 §8). The coordinator calls this before dispatching to check if the consumer has sufficient balance. Quote is valid for 60 seconds.
Auth
Authorization: Bearer <node_token> (coordinator node token)
Query parameters
| Parameter | Description |
|---|---|
| intent | Required. Intent URN for the task (e.g. urn:iicp:intent:llm:chat:v1) |
| max_tokens | Required. Positive integer — the maximum token budget for the task; used to compute the credit estimate. Missing or non-positive values return 422. |
| nodes | Optional. Comma-separated node IDs to quote against. Omit to quote against all eligible nodes |
| min_reputation | Optional. Float 0–1. Excludes candidate nodes below this reputation score before quoting. |
Request
curl -sf 'https://iicp.network/api/v1/credits/quote?intent=urn:iicp:intent:llm:chat:v1&max_tokens=500' \ -H "Authorization: Bearer <node_token>"
Response 200
{
"quote_id": "q_AbC123xyz789",
"estimated_credits": 0.5,
"min_credits": 0.5,
"max_credits": 0.5,
"price_per_1000_tokens": 1.0,
"nodes_quoted": 7,
"quote_expires_at": "2026-05-22T15:01:00Z",
"currency": "iicp_credits",
"consumer_balance": 38.5,
"effective_balance": 263.75,
"balance_scope": "operator_wallet",
"operator_wallet_balance": 263.75,
"balance_sufficient": true
}If balance_sufficient: false, the consumer identity does not have enough effective credits to cover the estimated cost. Operator-bound nodes use operator_wallet; unbound nodes use their node-local balance. The coordinator should not dispatch. min_credits and max_credits bracket the per-node price spread (they collapse to one value when a single rate applies).
POST/api/v1/credits/award
Submits a signed CIPWorkerReceipt to credit tokens to a worker node. The coordinator calls this after receiving a CIP RESPONSE from a worker. The receipt HMAC signature is verified before crediting.
Auth
Authorization: Bearer <coordinator_node_token>
Request body
| Field | Description |
|---|---|
| node_id | UUID of the worker node to credit |
| task_id | Task ID from the CIP CALL |
| tokens_used | Integer token count from the worker result |
| nonce | 32+ char random hex — prevents replay attacks |
| expires_at | ISO-8601 timestamp — receipt must be submitted before this time (5 min from issue) |
| response_hash | Required. 64-char lowercase hex SHA-256 of the worker response — binds the receipt to the result it credits |
| signature | 64-char HMAC-SHA256 hex of the canonical message (see below) |
| amount | Credits to award — must not exceed ceil(tokens_used / 1000) × credit_cost_multiplier × 1.1 |
| cip_parent_task_id | Optional. UUID of the coordinator's original task |
| cip_session_key | Optional. Session key from the CIP CALL envelope |
| reason | Optional. Audit string persisted with the ledger entry |
Response 200
{
"node_id": "550e8400-...",
"awarded": 0.5,
"balance": 39.0,
"spent": 0.5,
"spend_scope": "operator_wallet",
"debit_count": 1,
"spend_reason": null
}balance is the new post-award balance. spent is the amount debited from the querying identity. Operator-bound consumers spend from their pooled wallet; unbound consumers spend from the node-local balance.spend_reason is null on success or an insufficient-balance reason if the debit failed (award still succeeds — debit is SHOULD, not MUST per S.12 v0.6.11). All receipt-validation failures return HTTP 422 with error code IICP-E027.
Nonce lifecycle
- Worker generates a 32+ char random hex nonce when building the receipt.
- Nonce is included in the HMAC canonical message and in the receipt body.
- Directory rejects any nonce already seen within a 24-hour window (atomic set-if-not-exists) — this prevents replay attacks where a receipt is submitted twice.
- Receipt must be submitted before
expires_at(5 minutes from issue time).
HMAC canonical message
The signature covers this deterministically-ordered string, encoded as UTF-8:
"{task_id}:{tokens_used}:{cip_parent_task_id}:{cip_session_key}:{nonce}:{response_hash}"
# Extended form (CIP v0.6.11+): append querying_node_id when present:
# "{task_id}:...:{response_hash}:{querying_node_id}"
# Use empty string for optional fields (cip_parent_task_id, cip_session_key) when absent:
# e.g. "550e8400-...:142:::a3f2b8c9...:e3b0c44298fc1c149afbf4c8996fb924..."Signed with HMAC-SHA256 using the worker's node HMAC key — provisioned by the directory at registration, distinct from the bearer token.
GET/api/v1/credits/transactions
Returns the ledger transaction history for the authenticated node.
curl -sf https://iicp.network/api/v1/credits/transactions \ -H "Authorization: Bearer <node_token>"
Error codes
| Code | HTTP | When it occurs |
|---|---|---|
| IICP-E036 | 402 | Proxy pre-dispatch credit check failed — consumer S-Credit balance is below the computed routing cost. The proxy aborts before dispatching. Check balance with iicp-node credits or GET /api/v1/credits/balance. |
| IICP-E027 | 422 | CIPWorkerReceipt rejected at /credits/award: HMAC signature mismatch, HMAC key not provisioned, receipt expired, nonce replayed, amount exceeds ceiling, or rate limit exceeded (1 000 credits/hr per node) |
| validation_error | 422 | /credits/quote: intent or max_tokens missing, or max_tokens not a positive integer |
Rate limits
| Limit | Value |
|---|---|
| Max credits awarded per hour per node | 1 000 |
| Receipt nonce validity window | 300 s (5 min) |
| Nonce replay dedup window | 24 h |