SAAX Protocol — Commitment Lifecycle Specification
Solvent Applied Autonomous Exchange Protocol
Public specification. This document describes the standard, not any particular implementation. SAAX Protocol is experimental software — read the full terms of use before using it with real funds.
SAAX makes it safe to pay autonomous agents for work. It gives both sides a structured record of what was agreed, what was delivered, and what happens when something goes wrong. It does not generate demand, process payments, or provide buyer discovery — it records the commitment so that both sides can act on it.
Scope
The specification is under active development. Current documents cover the commitment schema, lifecycle, authority and evidence interfaces, settlement linkage, and error codes. Conformance fixtures are published at /conformance. Additional documents — node deployment guidance and threat model — are in development.
Relationship to External Systems
SAAX Protocol is settlement-rail-neutral. The current Router implementation supports x402 and MPP. The Protocol does not require any specific payment rail.
The reference implementation persists commitments to a durable store (Supabase), attributes them by buyer identity where provided, and exposes them through both the HTTP routing endpoint and the MCP tool surface. This is one implementation of the specification; the specification itself does not require any specific persistence layer or identity mechanism.
SAAX consumes authority proofs from external systems. The proof itself is issued by AP2, Verifiable Intent, an OAuth provider, or a custom issuer. SAAX validates the proof against the commitment; it does not issue credentials.
SAAX consumes identity and reputation signals from ERC-8004. The registry stores agent identities and feedback. SAAX reads those signals for ranking and gating; it does not write to the identity registry except for outcome feedback.
SAAX settles on Base with USDC as the current Router configuration. The Protocol does not require Base or USDC. Any conforming implementation can settle on any rail.
SAAX does not issue credentials, process payments directly, operate an oracle network, or act as an identity provider.
1. The Commitment Lifecycle
The SAAX commitment lifecycle is a governed commitment that moves through a defined sequence:
Authority → Commitment → Contract Terms → Execution → Evidence → Verification → Fulfilled or Failed → Settlement or Recovery → Finality → Audit
The commitment binds the terms — capability, price, acceptance criteria, deadline, cancel condition — before value moves. It carries no rail, no credential, no settlement reference: settlement is resolved at execution time.
The commitment is issued before value moves. A spend bound to a commitment must be denied if the requested amount or currency differs.
2. Evidence / Attestation Abstraction
2.1 Principle
SAAX does not trust the buyer or seller to declare fulfillment. Evidence comes from external sources with independent verification — temperature sensors, delivery trackers, reputation oracles, inspectors. SAAX validates evidence (structure, signature, provenance, binding) and evaluates it against the commitment's acceptance-criterion verification policies. SAAX never produces the evidence.
2.2 Evidence record schema
{
"evidenceId": "0x...",
"evidenceType": "temperature-reading",
"issuer": "0x...",
"subject": "0x...",
"issuanceTimestamp": "2026-10-06T...",
"contextReference": "0x...",
"payload": { ... },
"payloadHash": "sha256:...",
"provenance": { ... },
"signature": "COSE_Sign1...",
"verificationScheme": "eip712|cose|jws",
"verificationMaterial": "0x...",
"commitmentId": "0x...",
"acceptanceCriterionId": "0x..."
}
Every field is validated; only recognized fields are kept. The payload hash is the SHA-256 of the canonical JSON encoding of the payload — any payload tampering changes the hash and fails validation.
2.3 Verification-policy model
The commitment specifies a verification policy per acceptance criterion:
{
"criterionId": "0x...",
"criterionDescription": "delivery temperature <= 5C",
"requiredEvidenceType": "temperature-reading",
"acceptedIssuers": ["0x..."],
"verificationScheme": "cose",
"evaluationLogic": "payload.temperature <= 5",
"maxEvidenceAge": 3600,
"minimumEvidenceCount": 1
}
Policies are provider-neutral: acceptedIssuers is an optional allowlist, evaluationLogic is a tiny safe evaluator (numeric comparison only — no code execution), and verificationScheme selects the signature scheme (eip712 | cose | jws).
2.4 Evaluation
SAAX provides three operations over evidence:
- Validate evidence — checks structure, signature, provenance, and binding to the commitment and criterion. A hash-vs-payload mismatch (tampering) fails validation.
- Evaluate criterion — applies the verification policy (type, allowlist, freshness, evaluation logic, minimum count) and returns
satisfied | not_satisfied | insufficient_evidence. - Record outcome — writes the result to the commitment record, bound to the commitment and criterion.
2.5 Evidence lifecycle
commitment issued
->
acceptance criteria defined with verification policies
->
external evidence submitted (from any source)
->
SAAX validates evidence (structure, signature, provenance, binding)
->
SAAX evaluates against criterion
->
outcome recorded: satisfied | not_satisfied | insufficient_evidence
->
commitment reaches finality or enters recovery
The signature scheme eip712 is verified cryptographically over the EIP-712 domain { name: 'SAAX Evidence', version: '1' }; cose/jws envelopes are validated structurally with a pluggable verifier hook for token verification.
3. Authority-Proof Interface
3.1 Principle
A commitment references an external authority proof — AP2 mandates, verifiable intents, OAuth tokens, or custom schemes. SAAX does not issue authority proofs; it consumes them from external systems and re-evaluates them at execution time.
3.2 AuthorityProof structure
{
"authorityProofId": "0x...",
"proofType": "ap2-mandate|verifiable-intent|oauth-token|custom",
"issuer": "0x...",
"subject": "0x...",
"scope": { ... },
"validFrom": "2026-10-06T...",
"validUntil": "2026-10-07T...",
"signature": "COSE_Sign1...",
"verificationScheme": "cose|jws|eip712",
"verificationMaterial": "0x..."
}
Scope model: actions[] (the requested action must be in this list), optional capability, optional amountMax (raw units), optional currency. An absent scope dimension is unrestricted; a present dimension must be satisfied by the commitment.
3.3 Validation
- Validate authority proof — checks structure, signature, scope, and time validity.
- Is authorized — verifies the proof covers the specific action the commitment represents (combines integrity + time + scope).
- Attach to commitment — attaches the proof reference to the commitment at issuance. The full proof and its signature are never stored on the commitment — only the verifiable reference; the proof material lives at the external issuer.
3.4 Authority lifecycle
authority proof presented (external source)
->
SAAX validates proof (structure, signature, scope, time)
->
commitment issued, referencing the authority proof
->
proof evaluated at execution time (still valid? still in scope?)
->
commitment validly authorized or rejected
A commitment without an authority proof follows the legacy path where the commitment is signed directly by the buyer — unchanged and fully operational.
4. Settlement-Rail Neutrality
SAAX does not prescribe a settlement rail.
- The commitment issues a settlement requirement (R) that is rail-agnostic:
R =— no rail knowledge at commitment time. - The rail (S) is resolved at execution time from the registered registry.
- Currently registered rails: x402, MPP.
- Future rails: entitlement, card, ACH, internal ledger — any implementation of the rail interface can register as a SAAX settlement rail.
4.1 Rail interface
interface SettlementRail {
realise(R): Credential // turn a neutral requirement into a credential
validate(Credential, R): boolean // is this credential valid FOR R?
settle(Credential): TransactionReference // move value; return PUBLIC tx reference
}
Any system that implements this interface can register as a SAAX settlement rail:
registry.register('new-rail', { realise, validate, settle });
const rail = registry.resolve('new-rail');
The rail knows nothing about the commitment's content; it only knows how to realise R. Rail credentials never appear in receipts, logs, or results — only the public transaction reference.
5. In-Flight Commitment Handling
5.1 The gap
When an agent's first attempt leaves the agent's machine and never returns a response, the agent cannot distinguish "the merchant never got it" from "the merchant is processing it right now." A naive retry with the same commitment ID races the merchant's accept path.
The rule: an unknown outcome is a status check, not another POST.
5.2 The in_flight state
in_flight is an explicit lifecycle state between accepted and executing. It means: the merchant has received the commitment and is processing it, but the outcome is not yet known. This is distinct from executing, which means the merchant has begun fulfillment: in_flight is specifically the window where the agent does not yet know whether the merchant accepted.
5.3 Merchant-side rule (durable checkpoint)
A merchant that receives a commitment creation request must write in_flight to durable storage before processing the request. The write is the lock. A second request with the same commitment ID must return in_flight — not be processed again. The merchant is the authority on whether the commitment has entered the execution path. If the merchant cannot durably track in_flight, it cannot participate in the commitment lifecycle.
5.4 Agent-side rule (status check before retry)
When an agent's first attempt times out, the agent must not retry the POST. It must call get_commitment_status with the commitment ID first. The status response determines the correct action:
not_found— retry_safe — the merchant never received it. The agent may retry the POST.in_flight— poll — the merchant has it and is processing. Do not retry. Poll with exponential backoff.executing— poll — the merchant is fulfilling. Do not retry.fulfilled/settled/finalized— stop — terminal success. Do not retry.failed/expired/cancelled— retry_with_new_id — terminal without fulfillment. Retry with a fresh commitment ID.- All other states — poll — the commitment is in a transitional state. Continue polling.