The credit system is the core of Shielded x402’s fast multi-chain payment execution. Instead of waiting for on-chain confirmations, agents receive instant authorizations from a trusted sequencer, which enforces strict balance and nonce invariants.
Each agent is identified by a unique agentId (typically derived from their public key). The sequencer maintains:
Balance - Current available credit in micros (1 micro = 0.000001 units)
Nonce - Strictly increasing counter for replay protection
Public key - For signature verification
Signature scheme - e.g., ed25519-sha256-v1
Database schema (simplified):
CREATE TABLE agents ( agent_id TEXT PRIMARY KEY, agent_pub_key TEXT NOT NULL, signature_scheme TEXT NOT NULL, balance_micros BIGINT NOT NULL DEFAULT 0, nonce BIGINT NOT NULL DEFAULT 0, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW());
An authorization represents a commitment by the sequencer to allow a specific payment:
interface AuthorizationV1 { authId: string; // Unique ID for this authorization intent: IntentV1; // Original agent intent issuedAt: string; // Unix timestamp sequencerKeyId: string; // Which sequencer key signed this sequencerSig: string; // Ed25519 signature over canonical bytes}
Status progression:
ISSUED - Sequencer has authorized but relayer has not executed
EXECUTED - Relayer has executed and reported success
RECLAIMED - Authorization expired and amount was refunded
Rule: Accepted authorizations must have strictly increasing agentNonce values.For example, if the current nonce is 5, the next authorization must use nonce 6. Nonce 7 or nonce 5 (replay) will be rejected.
This provides:
Replay protection - Old authorizations cannot be reused
Ordering - Clear sequence of agent actions
Concurrency control - Prevents race conditions in multi-client scenarios
Implementation:
// Sequencer validation logicif (intent.agentNonce !== currentNonce + 1) { throw new Error( `Invalid nonce: expected ${currentNonce + 1}, got ${intent.agentNonce}` );}// After successful authorizationawait db.query( 'UPDATE agents SET nonce = nonce + 1 WHERE agent_id = $1', [intent.agentId]);
Rule: Cumulative accepted debits must never exceed cumulative credited balance.Each authorization reserves funds. The sequencer checks that balance >= amountMicros before issuing the authorization.
Implementation:
// Sequencer validation logicif (currentBalance < intent.amountMicros) { throw new Error( `Insufficient balance: have ${currentBalance}, need ${intent.amountMicros}` );}// Reserve funds (deduct from balance)await db.query( 'UPDATE agents SET balance_micros = balance_micros - $1 WHERE agent_id = $2', [intent.amountMicros, intent.agentId]);
When an authorization is issued, funds are immediately deducted from the balance. If the authorization expires without execution, the reclaim process refunds the amount.
The state object in the response shows the agent’s updated balance and nonce after this authorization. Agents should use this to construct the next intent.
Relayer signature - Verify reportSig against registered relayer public key
Chain matching - Ensure (chainRef, relayerKeyId) exists in relayer_keys table
Authorization exists - Check authId corresponds to an ISSUED authorization
Idempotency - Reject duplicate reports for the same authId
State update:
-- Update authorization statusUPDATE authorizationsSET status = 'EXECUTED', executed_at = NOW()WHERE auth_id = $1 AND status = 'ISSUED';-- Insert execution recordINSERT INTO executions (auth_id, execution_tx_hash, reported_at, relayer_key_id)VALUES ($1, $2, $3, $4);
Important: Funds are NOT refunded on execution. The amount was deducted when the authorization was issued. Execution simply marks the authorization as complete.
-- Refund balanceUPDATE agentsSET balance_micros = balance_micros + ( SELECT amount_micros FROM authorizations WHERE auth_id = $1)WHERE agent_id = ( SELECT agent_id FROM authorizations WHERE auth_id = $1);-- Mark as reclaimedUPDATE authorizationsSET status = 'RECLAIMED', reclaimed_at = NOW()WHERE auth_id = $1 AND status = 'ISSUED';
Caller types:
agent - The original agent reclaims their own funds
Development/testing only: The POST /v1/admin/credit endpoint allows direct balance crediting without shielded settlement. This should NEVER be exposed in production.
Relayers must register their public keys with the sequencer to report executions:Database schema:
CREATE TABLE relayer_keys ( chain_ref TEXT NOT NULL, relayer_key_id TEXT NOT NULL, public_key_hex TEXT NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), PRIMARY KEY (chain_ref, relayer_key_id));