# AURA Protocol AURA is a market protocol for agentic commerce. Buyer agents and seller agents transact through a neutral broker that interprets intent, mediates the exchange, and records the outcome. Agentic commerce needs a broker because two agents that both have a stake in the price cannot safely tell each other the truth. Each probes the other and conceals its own position, and the market decays into a market for lemons with cheap, unenforceable quotes. A party with no stake can hold both sides' private information at once and resolve the asymmetry. That party is Core. Every function here follows from that. A Scout declares intent. Core interprets it and presents sealed offers from Beacons. The buyer commits to one, Core binds the commitment and signs the chain of custody from the human signal to the outcome, and a clearing record carries the transaction to settlement. Each operation is the smallest mechanism that preserves a market invariant, and the invariants are stated in `x-aura-invariants`. This document is the canonical AURA protocol, written for humans and for agents. The paths and schemas are the wire contract; the `x-aura-*` extensions carry the protocol's law, ontology, and economics in machine-readable form. The published JSON Schemas, the SDKs, and the interactive reference derive from it. ## How to read this specification **Precedence (what wins in a conflict, highest first):** - OpenAPI paths, operations and schemas - x-aura-* normative extensions - descriptions - implementation metadata **Status vocabulary:** normative, implemented, reserved, roadmap, explanatory, deprecated. **Normative language:** RFC2119. ## Design principles Why the protocol has this shape. Each principle justifies a family of invariants. The principles explain; the invariants govern. ### Principles #### Privacy by design **Statement:** Counterparty identity and constraints are disclosed only when the protocol phase requires them. **Supports:** - Identity abstraction until commitment - Monotonic disclosure #### Business rules as gates **Statement:** Binary eligibility rules are enforced before any scoring or settlement economics. **Supports:** - Business rules as hard gates #### Atomicity over partial state **Statement:** A transaction commits in full or leaves no residue. **Supports:** - Atomic commitment #### Verifiable provenance **Statement:** Every consequential step is signed and can be reconstructed after the fact. **Supports:** - Recorded intent and chain of custody - Verifiable settlement #### Neutrality of the broker **Statement:** Core mediates the trade without holding a position in it. **Supports:** - Neutral brokerage - Financial neutrality of the clearinghouse #### Explicit authority **Statement:** An agent acts only within authority a principal has delegated and recorded. **Supports:** - Constraints as bounds - Persistent identity and qualification - Least-privilege delegated authority ## Invariants The rules every conforming market upholds. Each operation manifests one or more of them. ### Neutral brokerage Core MUST mediate every Scout and Beacon interaction. A conforming Core MUST NOT expose an unmediated bilateral channel for protocol offers. Two agents that both have a stake in the price cannot safely exchange information. Direct trade collapses into a market for lemons with cheap, unenforceable quotes. Only a party with no stake can hold both sides’ private information without abusing it. ### Identity abstraction until commitment Core MUST withhold each party’s identity from the other until commitment. A Beacon MUST NOT receive the Scout’s identity before the transaction commits. An agent that knows who it faces prices the counterparty instead of the goods. Hidden identity forces competition on the offer and produces genuine price discovery. ### Monotonic disclosure Information disclosed to a party MUST only increase as commitment deepens. No phase MAY reveal less than a prior phase. If disclosure can retract, a party hoards information defensively and the market goes opaque. A one-way ratchet lets each side reveal exactly enough, exactly when the commitment justifies it. ### Constraints as bounds Hard constraints define the authorised negotiation space. A conforming Scout, Core, or Beacon MUST NOT treat a hard constraint as a ranking preference, and Core MUST reject a commitment that exceeds one. A hard constraint is the principal’s delegated authority boundary. A commitment beyond it exceeds the mandate the principal granted. Treating constraints as bounds keeps agents inside that mandate. ### Offer expiry Every offer MUST carry an expiry. Core MUST refuse to commit an expired offer. Free, open-ended options let an agent reserve everywhere and commit nowhere. An expiry turns the negotiation into discrete rounds and ends the speed race. ### Atomic commitment Commitment MUST be atomic. Committing to one offer MUST reject its siblings in the same transaction, with no observable intermediate state. If commitment is not atomic, a concurrent reader sees capacity reserved twice and the same offer taken by two parties. One indivisible step makes a commitment mean exactly one thing. ### Persistent identity and qualification Agents MUST hold a persistent Ed25519 identity established by proof of possession. A new identity MUST start below the participation threshold. Cooperation needs the shadow of the future. If identities are free and disposable, a defector simply re-registers. A non-trivial identity with a cost of entry gives every participant something to lose. ### Recorded intent and chain of custody Core MUST record the original intent and assemble a signed chain of custody from the human signal to the outcome. The chain MUST be immutable once written. A commitment with no record of how it was reached cannot be adjudicated. A signed chain makes every step attributable, so the market enforces commitments rather than relitigating them. ### Verifiable settlement Clearing MUST advance to settled only on a verifiable, non-repudiable proof of settlement correlated to the original instruction. Settlement taken on trust fails the first dishonest counterparty. A signed proof from the rail makes finality a fact the protocol can check rather than a claim it must accept. ### Rail-conditional reserve Core MUST size a reserve conditioned on the rail. A rail with native repudiation MUST NOT carry a duplicative AURA hold; a rail without it MUST. Where the rail can reverse a charge, a second hold is waste. Where it cannot, an unreserved loss is unrecoverable. Sizing the reserve to the rail puts protection exactly where the infrastructure leaves a gap. ### Financial neutrality of the clearinghouse The clearinghouse MUST hold no commercial position. It MUST NOT rank offers, select beacons, or negotiate terms. A clearer that takes a side prices its own book into every settlement. Neutrality at the financial layer is the same law as neutral brokerage, carried into the money. ### Bilateral risk transparency Risk MUST be assessed for both parties, and each party MUST see only the assessment that applies to it. Risk priced in secret is risk a party cannot contest. Showing each side its own assessment makes the price legible without leaking the counterparty’s position. ### Business rules as hard gates Binary business rules MUST be enforced as pass or fail gates, separate from continuous risk scoring. A perfect risk score MUST NOT satisfy a failed gate. If a hard rule can be bought down by a good score, it is no longer a rule. Keeping gates separate from scoring stops a margin adjustment from eroding a compliance requirement. ### Repudiability within a bounded window A committed transaction MUST be repudiable for a declared, pre-committed window, adjudicated against the recorded intent chain with participant-filtered evidence. A market MUST NOT set no window. A commitment that cannot be challenged is a commitment a bad actor keeps. A bounded, pre-declared dispute window makes repudiation orderly and finite, which is what lets the other side trust the commit in the first place. ### Least-privilege delegated authority An agent MUST act only within an explicit, signed authority claim that chains to a durable principal in at most three tiers, and a delegation MUST NOT grant more authority than the granter holds. Authority an agent assumes by membership is authority no principal granted. A claim that names what the agent may do, on which resources, and what it may see, chained to a durable principal and narrowing at every hop, holds the agent inside its mandate and keeps one agent blind to another's work. Core verifies the claim and trusts the action without governing the counterparty. ## Authority and claim model How a principal grants and bounds an agent's authority, and how Core verifies a presented authority claim without governing the counterparty's interior. A commitment is valid only within the authority the principal delegated; a hard constraint is an authority boundary (Constraints as bounds). Authority is least-privilege and narrows down a signed delegation chain to a durable principal (Least-privilege delegated authority). **Boundary:** Core verifies a presented, signed claim against a root of trust. It does not model or govern the counterparty's internal agent hierarchy. Authentication proves the agent holds its key; the claim authorises the specific action and visibility. These are separate steps. **Agent As Marker:** An agent's key is a marker, an index into a durable record. Trust reads the chain, the principal, and the evidence (Recorded intent and chain of custody), so an agent may be ephemeral. ### Capacity **Definition:** How an agent declares who it acts for. One value per agent, machine-readable, presented with every claim. The vocabulary aligns with the Janus reference architecture for interoperability. #### Values ##### agent_for_principal **Definition:** The agent acts on a named principal's authority and inherits the bounds the principal granted. ##### principal_direct **Definition:** The agent acts on its own authority. A non-human root of authority lives here. ##### platform_delegated **Definition:** The agent acts on a platform's authority while interacting with principals. ### Developer Plane **Definition:** The build-plane identity, distinct from every commerce capacity above under separation of duty. A developer, human or agent, builds Scout or Beacon software and operates the sandbox under a developer credential. It is never a Scout or Beacon: it holds no agent_for_principal, principal_direct, or platform_delegated authority, signs no market flow, and its identity and credential live separate from Core. The bench-only sandbox context, the X-AURA-Sandbox-Context header, is a developer-plane attribution selector for run recording, not a commerce authority. **Separation Of Duty:** A developer credential can never operate as, nor be the anchor of, a Scout or Beacon; a Scout or Beacon protocol identity is neither the same key as, nor derived from, a developer credential. ### Claim **Definition:** What a Scout or Beacon presents so Core can authorise an action. Core verifies it as a relying party. **Parts:** - capacity - envelope - delegationChain ### Dials **Definition:** What a grant fixes. Least-privilege is the default: an agent with no grant can do and see nothing. **Actions:** The operations the agent may perform. **Resources:** The resources the agent may touch. **Visibility:** What the agent may read, a separate dial, so observe-only and act-without-sight are both expressible. **Bounds:** The signed envelope: amount, category, counterparty, geography, time, escalation threshold. ### Delegation Chain **Definition:** How authority passes from a principal to an agent and onward to the sub-agents it spawns. **Max Tiers:** 3 **Tiers:** - principal - agent - sub-agents **Attenuation:** A delegation grants no more than the granter holds. Authority only narrows down the chain. **Carries:** - scope - validity_window - revocation_path **Verification:** Signed end to end and verifiable back to the named principal. ### Consent Tiers #### explicit **Definition:** The principal signs the specific action. #### policy **Definition:** The action is permitted by a principal-defined policy the agent cites. #### delegated **Definition:** The action falls within a standing delegation scope the principal granted. ### Delegation Scope **Definition:** The bounded authority an agent holds for a principal. **Bounded By:** - hard_constraints - consent_tier - principal_approval - market_profile - resource_scope - visibility_scope **Governs:** - commitSession - counterOffer ### Authority Attestation **Definition:** Proof presented at commit that the action is within authority. **Required At:** commitSession **Carries:** - consent_tier - scope_reference - principal_signature_or_policy_citation ### Principal Approval **Definition:** An explicit principal decision captured for an action that exceeds standing authority. **Required When:** the action exceeds the delegation scope or a market-profile approval threshold ### External Credential Interop **Definition:** Delegation may be expressed with an external verifiable-credential format, carried as a signed claim. **Manifests:** - Constraints as bounds - Least-privilege delegated authority ## Market model Why the protocol has this shape. The market model explains; the invariants govern. **Ontological Claim:** Software agents are not subject to bounded rationality. A market whose participants can follow the rules can be designed to produce the outcomes economic theory predicts for rational agents, as a structural property rather than a tendency. **Market Not Shop:** AURA models a market, not a shop: intent, discovery, negotiation, commitment, settlement. Agents negotiate; they do not browse. ### Foundations #### Repeated-game cooperation **Author:** Axelrod **Claim:** Cooperation emerges among self-interested agents when interactions repeat, behaviour is observable, and retaliation is cheap. #### The market for lemons **Author:** Akerlof **Claim:** Asymmetric quality information drives good sellers out unless credible quality signals exist. #### Mechanism design **Author:** Hurwicz, Myerson, Maskin **Claim:** Rules can be designed so that rational, self-interested behaviour produces desirable outcomes. ### Microstructure Problems #### adverse_selection **Resolved By:** - Neutral brokerage - Persistent identity and qualification #### information_probing **Resolved By:** - Identity abstraction until commitment - Monotonic disclosure - Constraints as bounds #### strategic_non_commitment **Resolved By:** - Offer expiry - Atomic commitment - Repudiability within a bounded window ### Algorithmic Price Dynamics #### collusive_equilibrium **Resolution:** The neutral broker removes the bilateral channel two pricing algorithms would converge through. **Resolved By:** - Neutral brokerage #### oscillation **Resolution:** Offer expiry makes negotiation discrete, ending the continuous feedback loop. **Resolved By:** - Offer expiry #### asymmetric_exploitation **Resolution:** Neither algorithm observes the other's response function; Core mediates. **Resolved By:** - Neutral brokerage **Fix Analogy:** Like FIX, the protocol standardises the negotiation layer and leaves settlement and clearing to specialised systems. Invariant mechanics carry market-specific parameters set per market. **Computable Market Conditions:** - Participants are rational within their delegated scope. - The rules are enforced structurally, not behaviourally. - A neutral intermediary holds canonical state and breaks bilateral dynamics. ## Market parameters The dials a market sets within the law. Each parameter is bounded by an invariant; a market chooses a value within that bound. These map to the market-profile primitive. ### Parameters #### disclosure_schedule **Definition:** Per-field, per-phase disclosure tiers. **Bounded By:** - Identity abstraction until commitment - Monotonic disclosure #### offer_validity_window **Definition:** How long an offer remains committable. **Bounded By:** - Offer expiry #### qualification_threshold **Definition:** Minimum reputation to participate. **Bounded By:** - Persistent identity and qualification #### dispute_window_days **Definition:** How long a committed transaction is repudiable. A market may not set zero. **Bounded By:** - Repudiability within a bounded window #### settlement_method **Definition:** The rail used to settle. **Bounded By:** - Verifiable settlement #### reserve_strategy **Definition:** How the reserve margin is sized. **Bounded By:** - Rail-conditional reserve #### risk_model **Definition:** How bilateral risk is scored. **Bounded By:** - Bilateral risk transparency #### business_rule_set **Definition:** The hard gates a beacon defines. **Bounded By:** - Business rules as hard gates ## Reputation Reputation is the credible quality signal that keeps good sellers in the market. The dimensions and the transparency model are public; the scoring is proprietary and excluded from the contract. **Rationale:** A single score is gameable, collapses dimensions, and ossifies into an incumbency moat. Multi-dimensional signals computed from protocol events resist gaming and let a counterparty judge fit rather than a number. ### Public #### Dimensions ##### fulfilment_reliability **Definition:** Share of commitments honoured, weighted by recency. ##### offer_accuracy **Definition:** Gap between what was offered and what was delivered. ##### constraint_fidelity **Definition:** How often a Beacon's declared capabilities match the constraints it satisfies. ##### negotiation_integrity **Definition:** Rate of offer withdrawal, price change after commitment, and reneged terms. ##### response_relevance **Definition:** Match between Scout intent and Beacon offer. **Transparency Model:** Each dimension is independently queryable and computed from protocol events, not self-reported. **Attaches To:** - Principal - Beacon ### Proprietary **Scoring Formula:** excluded **Weighting Model:** excluded **Operational Parameters:** excluded **Supports:** - Persistent identity and qualification ## Conformance How a conforming implementation is verified. Each profile lists the invariants a role must honour; the testable assertions live on those invariants (their conformance[]). A third party runs the assertions to certify a Core. ### Profiles #### core-minimal **Description:** The session, offer, commitment, identity, and intent-chain laws every Core must honour. **Requires Invariants:** - Neutral brokerage - Identity abstraction until commitment - Monotonic disclosure - Constraints as bounds - Offer expiry - Atomic commitment - Persistent identity and qualification - Recorded intent and chain of custody - Least-privilege delegated authority #### core-clearing **Description:** The clearing, settlement, reserve, neutrality, risk, business-rule, and repudiability laws a clearing Core must honour. **Requires Invariants:** - Verifiable settlement - Rail-conditional reserve - Financial neutrality of the clearinghouse - Bilateral risk transparency - Business rules as hard gates - Repudiability within a bounded window #### beacon-minimal **Description:** What a conforming Beacon must honour: signed, time-bound offers, with its identity withheld until commitment. **Requires Invariants:** - Identity abstraction until commitment - Offer expiry **Requires Signature Profiles:** - beacon_offer #### scout-minimal **Description:** What a conforming Scout must honour: stay within delegated authority and commit atomically. **Requires Invariants:** - Constraints as bounds - Atomic commitment #### scout-admission **Layers Over:** scout-minimal **Description:** What a Scout proves to be admitted: everything scout-minimal requires, made executable across seeded golden and failure flows, plus redaction handling, expiry refusal, and delegated-authority boundaries. Signing correctness is proven against the published test vectors and exercised on every authenticated request. **Requires Invariants:** - Identity abstraction until commitment - Monotonic disclosure - Constraints as bounds - Offer expiry - Atomic commitment - Least-privilege delegated authority **Requires Signature Profiles:** - authenticated_request #### beacon-admission **Layers Over:** beacon-minimal **Description:** What a Beacon proves to be admitted: everything beacon-minimal requires, made executable across seeded golden and failure flows, plus constraint-bounded offering (a hard constraint is a boundary, never a ranking preference), monotonic disclosure handling, expiry semantics on its own offers, and atomic commitment behaviour. **Requires Invariants:** - Identity abstraction until commitment - Monotonic disclosure - Constraints as bounds - Offer expiry - Atomic commitment **Requires Signature Profiles:** - beacon_offer - authenticated_request **Assertion Source:** x-aura-invariants[].conformance ### Assertion Types **Positive:** A valid flow that must succeed. **Negative:** A forbidden input that must be rejected. **Property:** An invariant that must hold across states. **Sequence:** An ordering or atomicity that must hold across steps. ## State machines ### Session **Description:** Session lifecycle. Terminal states are absorbing. The clearing lifecycle is a separate machine and never changes the session status. #### Read Semantics **Description:** Some transitions are materialised lazily. Their condition becomes true on its own (an offer exists, an expiry elapses), and the next read or write that observes the session persists the change. A read can therefore materialise a pending transition today. The protocol event is the condition, not the request that observes it. Making safe-method reads free of side effects is a roadmap item. **Lazy Transitions:** - T4 - T12 **Initial:** collecting_offers #### States ##### collecting_offers **Category:** active ##### offers_available **Category:** active ##### committed **Category:** active ##### fulfilled **Category:** active ##### completed **Category:** active **Absorbing:** false **Note:** Disputable within the dispute window; otherwise the clearing record advances to cleared. ##### disputed **Category:** active ##### resolved **Category:** terminal ##### cancelled **Category:** terminal ##### expired **Category:** terminal ##### failed **Category:** terminal **Reserved:** true **Reserved States:** - created - interpreting - discovering #### Transitions ##### T1 **Event:** POST /v1/sessions **Guard:** Valid intent string; authenticated agent ##### collecting_offers → offers_available **Event:** POST /v1/sessions/{session_id}/offers (first offer) **Guard:** Session not expired; Beacon active ##### offers_available → offers_available **Event:** POST /v1/sessions/{session_id}/offers (subsequent) **Guard:** Session not expired; Beacon active ##### collecting_offers → offers_available **Event:** First valid offer observed **Guard:** Pending offers found **Materialisation:** lazy_allowed **Observed By:** - GET /v1/sessions/{session_id} ##### collecting_offers → cancelled **Event:** POST /v1/sessions/{session_id}/cancel **Guard:** Owner; status NOT IN (committed, completed) ##### offers_available → cancelled **Event:** POST /v1/sessions/{session_id}/cancel **Guard:** Owner; status NOT IN (committed, completed) ##### offers_available → committed **Event:** POST /v1/sessions/{session_id}/commit **Guard:** Owner; not expired; offer belongs to session; unique idempotency key ##### committed → fulfilled **Event:** PUT /v1/transactions/{transaction_id}/fulfillment (delivered, payment pending) **Guard:** Participant; fulfillment_status=delivered; payment_status != charged ##### committed → completed **Event:** PUT /v1/transactions/{transaction_id}/fulfillment (delivered, payment charged) **Guard:** Participant; fulfillment_status=delivered; payment_status=charged ##### committed → completed **Event:** PUT /v1/transactions/{transaction_id}/payment (charged, fulfillment delivered) **Guard:** Participant; payment_status=charged; fulfillment_status=delivered ##### fulfilled → completed **Event:** PUT /v1/transactions/{transaction_id}/payment (charged) **Guard:** Participant; payment_status=charged; fulfillment_status=delivered ##### collecting_offers,offers_available → expired **Event:** Session expiry elapsed **Guard:** expires_at < NOW(); status NOT IN (completed, cancelled, expired) **Materialisation:** lazy_allowed **Observed By:** - GET /v1/sessions/{session_id} - POST /v1/sessions/{session_id}/commit ##### committed → disputed **Event:** POST /v1/transactions/{transaction_id}/disputes **Guard:** Participant; reason provided; not already disputed ##### fulfilled → disputed **Event:** POST /v1/transactions/{transaction_id}/disputes **Guard:** As T13 ##### completed → disputed **Event:** POST /v1/transactions/{transaction_id}/disputes **Guard:** As T13; within dispute window (completed_at + dispute_window > NOW()) ##### disputed → resolved **Event:** POST /v1/disputes/{dispute_id}/resolve (resolution applied) **Guard:** Adjudication authority; outcome + remedial actions ##### disputed → previous_state **Event:** POST /v1/disputes/{dispute_id}/resolve (withdrawn) **Dynamic:** true **Guard:** Initiator withdraws; no counterparty evidence; restores pre-dispute state #### Affordances **Description:** HATEOAS _links available per state. Integrators follow _links to discover valid actions; an absent link means the action is not valid in that state. ##### Session Links By State **Collecting offers:** - self - cancel - offers - commit **Offers available:** - self - offers - commit - cancel **Committed:** - self - transaction **Fulfilled:** - self - transaction **Completed:** - self - transaction **Disputed:** - self - transaction **Resolved:** - self - transaction **Cancelled:** - self **Expired:** - self ##### Session Link Notes **Collecting offers:** offers and commit appear only once pending offers exist; self and cancel always. ##### Transaction Links **Self:** Always **Session:** Always **Fulfillment:** Status NOT IN (disputed, resolved) **Payment:** Status NOT IN (disputed, resolved) **Dispute:** Status IN (committed, fulfilled, completed) **Dispute details:** Status IN (disputed, resolved) **Evidence:** Status = disputed and requester is a participant **Resolve:** Status = disputed and requester has adjudication authority **Clearing status:** Clearing record clearing_status IN (risk_assessed, authorized, settling, settled, dispute_term_active, cleared) **Settlement status:** Clearing record clearing_status IN (settling, settled, cleared) ### Clearing **Description:** Clearing lifecycle for a committed transaction, a separate machine from the session lifecycle. It never changes the session status. The cleared and failed states are terminal. Advanced by the system-only clearing-status operation. **Initial:** pending #### States ##### pending ##### risk_assessed ##### authorized ##### settling ##### settled ##### dispute_term_active ##### disputed ##### resolved ##### cleared **Category:** terminal ##### failed **Category:** terminal #### Transitions **Pending:** - risk_assessed - failed **Risk assessed:** - authorized - disputed - failed **Authorized:** - settling - disputed - failed **Settling:** - settled - disputed - failed **Settled:** - dispute_term_active - cleared - disputed **Dispute term active:** - cleared - disputed **Disputed:** - resolved **Resolved:** - cleared - settled **Cleared:** **Failed:** ## Signature profiles Every signature in the protocol follows one of these named profiles. Each profile names what is signed, how the payload is assembled, and which operations it applies to. **Algorithm:** Ed25519 ### Profiles #### authenticated_request **Description:** Proof that an authenticated request was issued by the holder of the agent key. ##### Applies To **Operations:** - all agent-authenticated operations **Signed Material:** - method - path - timestamp - nonce - body_hash **Required Headers:** - X-Agent-Id - X-Agent-Timestamp - X-Agent-Nonce - X-Agent-Signature **Optional Signed Material:** - @authority **Optional Headers:** - X-Agent-Host **Freshness Window Seconds:** 300 ##### Notes **Freshness:** The request timestamp must fall within 300 seconds of Core receipt, either side. A stale timestamp fails verification and surfaces as invalid_signature. **Replay:** Each request carries a unique nonce in X-Agent-Nonce, an opaque token matching ^[A-Za-z0-9._~-]{16,128}$, folded into the signed bytes between timestamp and body_hash. Core records accepted nonces for the freshness window and rejects a reused nonce as replayed_request, so a captured signed request is single-use. **Host:** Additive host binding (GAP-05): a client MAY send X-Agent-Host, an opaque host or host:port matching ^[A-Za-z0-9.-]+(:[0-9]+)?$, and append it as @authority (the last line of the signed bytes). When present Core verifies it equals this Core's canonical host, rejecting host_mismatch, so a request signed for one Core cannot be relayed to another. Absent is backward-compatible (no host binding). Becomes required once more than one market Core serves the same agent identities. #### principal_registration **Description:** Proof of possession of the principal key at registration. ##### Applies To **Operations:** - registerPrincipal **Signed Material:** - canonical_request_body **Required Headers:** - X-Signature #### agent_registration **Description:** Proof of possession of the agent key at registration. ##### Applies To **Operations:** - registerAgent **Signed Material:** - canonical_request_body **Required Headers:** - X-Agent-Signature #### beacon_offer **Description:** A Beacon's signature binding it to the terms of an offer. The payload is the canonical newline-delimited form the protocol verifies. The offer identifier is assigned by the broker after submission, so it is never part of the signed payload; the signature binds the session, the Beacon, and the offered terms. ##### Applies To **Operations:** - submitOffer **Delimiter:** `LF` (U+000A) **Encoding:** UTF-8 **Payload Fields:** - session_id - beacon_id - product_json - unit_price - quantity - total_price - currency - payment_terms_hash **Optional Fields:** - payment_terms_hash ##### Notes **Product json:** Product objects serialise as recursively canonical JSON: object keys sorted lexicographically at every depth, array order preserved, so nested product content is bound (a flat object is byte-identical to the earlier top-level-sorted form); plain-string products pass through unchanged. **Numeric fields:** unit_price, quantity, and total_price serialise via String(value); an absent value serialises as the empty string, keeping the line count stable. **Currency:** Defaults to USD when absent. **Payment terms hash:** Base64-encoded SHA-256 of the canonicalised payment terms (accepted_methods sorted, keys ordered). When the offer carries no payment terms the line is omitted entirely, so seven-line signatures from before the payment-terms extension remain valid. **Verification:** Core verifies against the Beacon's registered Ed25519 public key, then counter-signs (see core_offer_countersignature). ##### Example **Description:** Worked example of the assembled, newline-delimited payload a Beacon signs for these field values. ###### Fields **Session id:** 5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b **Beacon id:** c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f **Product json:** {"name":"Industrial Widget","sku":"WDG-001"} **Unit price:** 85 **Quantity:** 500 **Total price:** 42500 **Currency:** USD **Payment terms hash:** IjMQNSmbE8lmaQ+1Q713NYiyUKur/bvp3wAKEenFab8= **Payload:** ``` 5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f {"name":"Industrial Widget","sku":"WDG-001"} 85 500 42500 USD IjMQNSmbE8lmaQ+1Q713NYiyUKur/bvp3wAKEenFab8= ``` #### webhook_delivery **Description:** Core's signature on every webhook delivery, so a receiver can verify the event came from Core. The signature binds the event type and timestamp to the body, so a valid signature cannot be replayed onto a different event, and replay of the whole delivery is bounded by the timestamp. ##### Applies To **Webhooks:** all **Delimiter:** `LF` (U+000A) **Encoding:** UTF-8 **Payload Fields:** - event - timestamp - body **Required Headers:** - X-AURA-Event - X-AURA-Timestamp - X-AURA-Signature ##### Notes **Event:** The X-AURA-Event header value. **Timestamp:** The X-AURA-Timestamp header value, ISO 8601. **Body:** The exact JSON body string as sent, byte for byte. **Verification:** Verify against the key at GET /.well-known/core-signing-key. Reject a delivery whose timestamp is outside your replay window. #### core_offer_countersignature **Description:** Core counter-signs an accepted offer at commit: it re-verifies the Beacon signature, then signs CORE-COUNTERSIGN, the canonical offer payload, and the Beacon signature with its own key. The counter-signature is recorded on the transaction and proves Core observed and accepted the signed offer. ##### Applies To **Operations:** - commitSession **Prefix:** CORE-COUNTERSIGN #### interpretation_attestation **Description:** Core's signed binding between the raw intent and its structured interpretation. ##### Applies To **Operations:** - createSession - getAttestation **Signed Material:** - interpretation - raw_intent - session_id - structured_interpretation - timestamp **Canonicalisation:** Sorted-key JSON of the attestation body; the signature and the signer key id attach after signing. #### intent_chain_link **Description:** A signature on one link of the intent chain, chained to its predecessor. ##### Applies To **Operations:** - submitChainLink **Signed Material:** - link - name - timestamp - signed_by - signer_type - payload - previous_link_hash **Canonicalisation:** JSON of the link body in the field order above. #### assembled_intent_chain **Description:** Core's signature over the assembled chain at commit. ##### Applies To **Operations:** - getIntentChain **Signed Material:** - ordered_link_hashes #### key_rotation **Description:** Dual-signed key lifecycle operations: rotation and recovery. The payload binds the entity, both keys, and the client-submitted rotation timestamp, so a signature cannot be replayed for a different entity, a different current key (stale rotation), or a different new key (substitution). The same payload carries two signatures with different signers: the new key proves possession (new_key_proof), and the current key, or the principal's key in recovery, authorizes (old_key_authorization / principal_authorization). ##### Applies To **Operations:** - rotateAgentKey - rotatePrincipalKey - replaceAgentKey **Delimiter:** `LF` (U+000A) **Encoding:** UTF-8 **Payload Fields:** - entity_type - entity_id - old_public_key - new_public_key - rotation_timestamp ##### Notes **Entity type:** 'agent' or 'principal'. **Entity id:** UUID of the rotating entity. **Old public key:** The entity's CURRENT live key as Core holds it, base64. Core derives it server-side and never trusts a client-supplied value. **New public key:** The incoming key, base64. **Rotation timestamp:** ISO 8601 exactly as submitted in the body. Must fall within 300 seconds of Core receipt, either side; outside the window the request fails as rotation_replayed. **Replay:** Core records the committed rotation tuple. An exact duplicate of a committed rotation returns idempotent success; a payload built against a key that is no longer current fails as key_rotation_conflict. #### sandbox_key_mint **Description:** Proof-of-possession for sandbox key minting (obtain_scope). The declared key signs the mint request body, so the caller proves it holds the key the domain will vouch for. Identical construction to registration: the signed material is JSON.stringify of the request object exactly as sent, and the field order is the request order domain, public_key, verification_method. ##### Applies To **Operations:** - mintSandboxKey **Signed Material:** - canonical_request_body **Canonicalisation:** JSON.stringify of the request body object, UTF-8 bytes, field order: domain, public_key, verification_method. **Required Headers:** - X-Signature ## Signature test vectors Known-good Ed25519 test vectors for every signature profile, so an implementation can prove its canonicalisation is exactly right before signing live requests. The keys are published test material derived from the stated seeds and carry no standing anywhere in the protocol. **Key derivation:** The Ed25519 private key is derived from the 32-byte seed (hex) as PKCS8 DER: the 16-byte prefix 302e020100300506032b657004220420 followed by the seed. public_key is the base64 encoding of the raw 32-byte public key, the same format the protocol uses everywhere. **Verification:** signing_payload is the exact byte string to sign, UTF-8 encoded. Signing it with the seed-derived key must produce expected_signature byte for byte (Ed25519 is deterministic). Every vector is re-executed against the implementation in continuous integration, so a published vector cannot drift from the protocol. ### authenticated_request: post_with_body - **private_key_seed**: `1111111111111111111111111111111111111111111111111111111111111111` - **public_key**: `0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=` - **method**: `POST` - **path**: `/v1/sessions` - **timestamp**: `1782000000000` - **nonce**: `9f8e7d6c5b4a39281706f5e4d3c2b1a0` - **body**: `{"intent":"I need 200 industrial widgets delivered within three weeks"}` - **body_hash**: `nDOL9AewIaRugTuLp/120G5l1owIOjUJDpVsKqYFoK8=` Signing payload (exact bytes, UTF-8, LF newlines): ``` POST /v1/sessions 1782000000000 9f8e7d6c5b4a39281706f5e4d3c2b1a0 nDOL9AewIaRugTuLp/120G5l1owIOjUJDpVsKqYFoK8= ``` **Expected signature (base64):** `XAIFHQoMwuZm7HBO/CXnaH6WR8tKITpIQ6Xx5ROLX4/SZgEd3Byfn5lfsNnW+Cr023Y0ltXcoioVVvZWzuDVBA==` ### authenticated_request: get_bodyless_empty_digest - **private_key_seed**: `1111111111111111111111111111111111111111111111111111111111111111` - **public_key**: `0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=` - **method**: `GET` - **path**: `/v1/sessions/5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b` - **timestamp**: `1782000000000` - **nonce**: `00112233445566778899aabbccddeeff` - **body**: `null` - **body_hash**: `` Signing payload (exact bytes, UTF-8, LF newlines): ``` GET /v1/sessions/5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b 1782000000000 00112233445566778899aabbccddeeff ``` **Expected signature (base64):** `KplY/4w9DnOg/I2OsfgplIxWd34SYdZTpif3CWkoWdUvYhE8/r2jHJm5vn/XZ/K3fJhdl26eqADkK9UNw2hVAw==` ### authenticated_request: post_with_host - **private_key_seed**: `1111111111111111111111111111111111111111111111111111111111111111` - **public_key**: `0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=` - **method**: `POST` - **path**: `/v1/sessions` - **timestamp**: `1782000000000` - **nonce**: `c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9` - **authority**: `api.aura-labs.example` - **body**: `{"intent":"I need 200 industrial widgets delivered within three weeks"}` - **body_hash**: `nDOL9AewIaRugTuLp/120G5l1owIOjUJDpVsKqYFoK8=` Signing payload (exact bytes, UTF-8, LF newlines): ``` POST /v1/sessions 1782000000000 c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9 nDOL9AewIaRugTuLp/120G5l1owIOjUJDpVsKqYFoK8= api.aura-labs.example ``` **Expected signature (base64):** `BN+qjyo/HJhWVUrsWyW5ugIb0Npb6M+SewYTSoAxu0WrNWrNjkPgnPcK7jA/Tu8l1varYmllk0jEXNjJ+EL3Cw==` ### principal_registration: register_organization - **private_key_seed**: `2222222222222222222222222222222222222222222222222222222222222222` - **public_key**: `oJql9HpnWYAv+VX43C0qFKXJnSO+l/hkEn/5ODRVpPA=` - **body**: `{"principal_type":"organization","legal_name":"Vector Test GmbH","jurisdiction":"DE","public_key":"oJql9HpnWYAv+VX43C0qFKXJnSO+l/hkEn/5ODRVpPA="}` - **canonical_body**: `{"principal_type":"organization","legal_name":"Vector Test GmbH","jurisdiction":"DE","public_key":"oJql9HpnWYAv+VX43C0qFKXJnSO+l/hkEn/5ODRVpPA="}` Signing payload (exact bytes, UTF-8, LF newlines): ``` {"principal_type":"organization","legal_name":"Vector Test GmbH","jurisdiction":"DE","public_key":"oJql9HpnWYAv+VX43C0qFKXJnSO+l/hkEn/5ODRVpPA="} ``` **Expected signature (base64):** `sw3foChdrqkdskaQE7aZuFWrz5QFpdSduN+yn70PibpzqRGwDK01Z3+QLg0vaxJ0PXwfdPkbs90zv8xw1/KRBg==` ### agent_registration: register_scout - **private_key_seed**: `1111111111111111111111111111111111111111111111111111111111111111` - **public_key**: `0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=` - **body**: `{"public_key":"0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=","type":"scout","principal_id":"3f2a9c7e-1b4d-4e8a-9c2f-7a1b0d3e5f60","capacity":"agent_for_principal"}` - **canonical_body**: `{"public_key":"0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=","type":"scout","principal_id":"3f2a9c7e-1b4d-4e8a-9c2f-7a1b0d3e5f60","capacity":"agent_for_principal"}` Signing payload (exact bytes, UTF-8, LF newlines): ``` {"public_key":"0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=","type":"scout","principal_id":"3f2a9c7e-1b4d-4e8a-9c2f-7a1b0d3e5f60","capacity":"agent_for_principal"} ``` **Expected signature (base64):** `f6ZKRo1rMbFE4E7kvmIWNHrlhkQBxKEZdGdWn5S7cFUCCxF9glu31BhxpyYeetOozNB7KMdYkNHFKl8WBhYUAQ==` ### beacon_offer: offer_without_payment_terms - **private_key_seed**: `3333333333333333333333333333333333333333333333333333333333333333` - **public_key**: `F8t5+ytBIPKx7GXkGY1uCLKOgT/rAeSkAIObheGAgM4=` - **fields**: `{"session_id":"5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b","beacon_id":"c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f","product_json":"{\"name\":\"Industrial Widget\",\"sku\":\"WDG-001\"}","unit_price":85,"quantity":500,"total_price":42500,"currency":"USD"}` Signing payload (exact bytes, UTF-8, LF newlines): ``` 5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f {"name":"Industrial Widget","sku":"WDG-001"} 85 500 42500 USD ``` **Expected signature (base64):** `p4anFua6FbkvWpDC93wUiPtJHlRAvHuxQR+kXdrRYPKPo2o3C9bjaIJq1EX7mARuCDboQka0STpnMI0KmJJbBg==` ### beacon_offer: offer_with_payment_terms - **private_key_seed**: `3333333333333333333333333333333333333333333333333333333333333333` - **public_key**: `F8t5+ytBIPKx7GXkGY1uCLKOgT/rAeSkAIObheGAgM4=` - **fields**: `{"session_id":"5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b","beacon_id":"c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f","product_json":"{\"name\":\"Industrial Widget\",\"sku\":\"WDG-001\"}","unit_price":85,"quantity":500,"total_price":42500,"currency":"USD","payment_terms_hash":"IjMQNSmbE8lmaQ+1Q713NYiyUKur/bvp3wAKEenFab8="}` Signing payload (exact bytes, UTF-8, LF newlines): ``` 5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f {"name":"Industrial Widget","sku":"WDG-001"} 85 500 42500 USD IjMQNSmbE8lmaQ+1Q713NYiyUKur/bvp3wAKEenFab8= ``` **Expected signature (base64):** `XrqLmPv9JH8XYDyVFdaSSR6cMiSbQ6EffFTkZ5wOIp6gN1PrEVddec//TBhxhEbm1TDklpD9fSjr+GAyk9cfAg==` ### beacon_offer: offer_with_nested_product - **private_key_seed**: `3333333333333333333333333333333333333333333333333333333333333333` - **public_key**: `F8t5+ytBIPKx7GXkGY1uCLKOgT/rAeSkAIObheGAgM4=` - **fields**: `{"session_id":"5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b","beacon_id":"c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f","product_json":"{\"name\":\"Industrial Widget\",\"sku\":\"WDG-001\",\"spec\":{\"dims\":{\"unit\":\"mm\",\"w\":40},\"grade\":\"A\",\"material\":\"steel\"}}","unit_price":85,"quantity":500,"total_price":42500,"currency":"USD"}` Signing payload (exact bytes, UTF-8, LF newlines): ``` 5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f {"name":"Industrial Widget","sku":"WDG-001","spec":{"dims":{"unit":"mm","w":40},"grade":"A","material":"steel"}} 85 500 42500 USD ``` **Expected signature (base64):** `qFkWDopb7pHNG9R3ifcAMqvZcsKYhHkvXfhe9BqyBF+i81NkQ2zgJwCiZiDUwNpnxI2TVdJGytAHzyinH/nKCg==` ### core_offer_countersignature: countersign_offer_with_payment_terms - **private_key_seed**: `4444444444444444444444444444444444444444444444444444444444444444` - **public_key**: `11l5O7wTooGagnx2rbb7qKSa7gB/SfLQmS2ZuCWtLEg=` - **offer_signing_payload**: `5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f {"name":"Industrial Widget","sku":"WDG-001"} 85 500 42500 USD IjMQNSmbE8lmaQ+1Q713NYiyUKur/bvp3wAKEenFab8=` - **beacon_signature**: `XrqLmPv9JH8XYDyVFdaSSR6cMiSbQ6EffFTkZ5wOIp6gN1PrEVddec//TBhxhEbm1TDklpD9fSjr+GAyk9cfAg==` Signing payload (exact bytes, UTF-8, LF newlines): ``` CORE-COUNTERSIGN 5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f {"name":"Industrial Widget","sku":"WDG-001"} 85 500 42500 USD IjMQNSmbE8lmaQ+1Q713NYiyUKur/bvp3wAKEenFab8= XrqLmPv9JH8XYDyVFdaSSR6cMiSbQ6EffFTkZ5wOIp6gN1PrEVddec//TBhxhEbm1TDklpD9fSjr+GAyk9cfAg== ``` **Expected signature (base64):** `PfbdUgo7rsI1EZNHyp3ERxbrveDF2xWvBtJPuYiY24WgaBb62v2JcF3K6NCNiB7A/2VveqQPlOoKjVqP4mcKDA==` ### interpretation_attestation: attestation_sorted_key_json - **private_key_seed**: `4444444444444444444444444444444444444444444444444444444444444444` - **public_key**: `11l5O7wTooGagnx2rbb7qKSa7gB/SfLQmS2ZuCWtLEg=` - **attestation_body**: `{"interpretation":{"model_id":"aura-intent-regex","model_version":"2026-04","confidence":0.94,"interpretation_method":"regex","fallback_used":false},"raw_intent":"I need 200 industrial widgets delivered within three weeks","session_id":"5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b","structured_interpretation":{"category":"industrial_chemicals","quantity":200},"timestamp":"2026-07-02T12:00:00.000Z"}` Signing payload (exact bytes, UTF-8, LF newlines): ``` {"interpretation":{},"raw_intent":"I need 200 industrial widgets delivered within three weeks","session_id":"5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b","structured_interpretation":{},"timestamp":"2026-07-02T12:00:00.000Z"} ``` **Expected signature (base64):** `dvO3F8x6xlVwIj/CSiE6pXf2rRZBLjW2zH0/ydzHvbBBpRqSjXFVvpkBausOpLJzZvwVOwy3Lug0Fon+Djy8AA==` ### intent_chain_link: core_link_l2 - **private_key_seed**: `4444444444444444444444444444444444444444444444444444444444444444` - **public_key**: `11l5O7wTooGagnx2rbb7qKSa7gB/SfLQmS2ZuCWtLEg=` - **link_body**: `{"link":"L2","name":"interpretation","timestamp":"2026-07-02T12:00:00.000Z","signed_by":"core","signer_type":"core","payload":{"session_id":"5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b"},"previous_link_hash":null}` Signing payload (exact bytes, UTF-8, LF newlines): ``` {"link":"L2","name":"interpretation","timestamp":"2026-07-02T12:00:00.000Z","signed_by":"core","signer_type":"core","payload":{"session_id":"5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b"},"previous_link_hash":null} ``` **Expected signature (base64):** `jQCFSaaR41BXw1ZYagpT4WW4sb3XnDSyVgJyJ6Y2+nhe7FEf/WPrS+trf4pGwoQtAZT34+D25yb76QRos5BbCg==` ### assembled_intent_chain: two_link_chain - **private_key_seed**: `4444444444444444444444444444444444444444444444444444444444444444` - **public_key**: `11l5O7wTooGagnx2rbb7qKSa7gB/SfLQmS2ZuCWtLEg=` - **links**: `[{"link":"L1","name":"origination","created_at":"2026-07-02T12:00:00.000Z","signed_by":"a7b8c9d0-1e2f-4a3b-8c4d-5e6f7a8b9c0d","signer_type":"scout_agent","payload":{"session_id":"5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b"},"signature":"dGVzdA==","previous_link_hash":null},{"link":"L2","name":"interpretation","created_at":"2026-07-02T12:00:01.000Z","signed_by":"core","signer_type":"core","payload":{"confidence":0.94},"signature":"dGVzdDI=","previous_link_hash":"sha256:0000000000000000000000000000000000000000000000000000000000000000"}]` - **chain_hash**: `sha256:8a5fd44ea403d9f4904881127508bfdbc778774cc6e6817f5c1212a8428509a0` Signing payload (exact bytes, UTF-8, LF newlines): ``` sha256:8a5fd44ea403d9f4904881127508bfdbc778774cc6e6817f5c1212a8428509a0 ``` **Expected signature (base64):** `NgF0WzwAFt18vT7ojryvWN5bgq10cJli2MOnLMixCwhpBq1dyiUVoVvxZLeUW8ziGNbMZhvgG8ZxCvyWhE2bAA==` ### webhook_delivery: transaction_committed_delivery - **private_key_seed**: `4444444444444444444444444444444444444444444444444444444444444444` - **public_key**: `11l5O7wTooGagnx2rbb7qKSa7gB/SfLQmS2ZuCWtLEg=` - **event**: `transaction.committed` - **timestamp**: `2026-07-02T12:00:00.000Z` - **body**: `{"transaction_id":"2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f","idempotency_key":"4d5e6f7a-8b9c-4d0e-8f1a-2b3c4d5e6f70","session_id":"5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b","offer_id":"9a0b1c2d-3e4f-4a5b-8c6d-7e8f9a0b1c2d","final_terms":{"product":"Industrial Widget","total_price":42500,"currency":"USD","delivery_date":"2026-03-10"}}` Signing payload (exact bytes, UTF-8, LF newlines): ``` transaction.committed 2026-07-02T12:00:00.000Z {"transaction_id":"2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f","idempotency_key":"4d5e6f7a-8b9c-4d0e-8f1a-2b3c4d5e6f70","session_id":"5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b","offer_id":"9a0b1c2d-3e4f-4a5b-8c6d-7e8f9a0b1c2d","final_terms":{"product":"Industrial Widget","total_price":42500,"currency":"USD","delivery_date":"2026-03-10"}} ``` **Expected signature (base64):** `XU0Tr18CtY6RNue2NCAF+/sikSSZGHSxpHoV9g/8Lwln3/xITma2BEgwbl1PbVQqqwPlpKmH2gOty3oeTplMBw==` ### key_rotation: rotate_agent_key_new_key_proof - **role**: `new_key_proof` - **private_key_seed**: `5555555555555555555555555555555555555555555555555555555555555555` - **public_key**: `xoImN8fTEOxXYnvgC6JZ0lN0n0qvZERwz/vlOjX3MkI=` - **entity_type**: `agent` - **entity_id**: `e1f2a3b4-c5d6-4e7f-8a9b-0c1d2e3f4a5b` - **old_public_key**: `0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=` - **new_public_key**: `xoImN8fTEOxXYnvgC6JZ0lN0n0qvZERwz/vlOjX3MkI=` - **rotation_timestamp**: `2026-07-02T12:00:00.000Z` Signing payload (exact bytes, UTF-8, LF newlines): ``` agent e1f2a3b4-c5d6-4e7f-8a9b-0c1d2e3f4a5b 0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc= xoImN8fTEOxXYnvgC6JZ0lN0n0qvZERwz/vlOjX3MkI= 2026-07-02T12:00:00.000Z ``` **Expected signature (base64):** `dXkM2mTtOW3lhJKMOpMNF3OvlsmC86StP0uMr8HaFeTaWl/vgtXn8zzwlIJ/73gRlhbqBbLeGW6FLP6SYRX0Dw==` ### key_rotation: rotate_agent_key_old_key_authorization - **role**: `old_key_authorization` - **private_key_seed**: `1111111111111111111111111111111111111111111111111111111111111111` - **public_key**: `0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=` - **entity_type**: `agent` - **entity_id**: `e1f2a3b4-c5d6-4e7f-8a9b-0c1d2e3f4a5b` - **old_public_key**: `0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=` - **new_public_key**: `xoImN8fTEOxXYnvgC6JZ0lN0n0qvZERwz/vlOjX3MkI=` - **rotation_timestamp**: `2026-07-02T12:00:00.000Z` Signing payload (exact bytes, UTF-8, LF newlines): ``` agent e1f2a3b4-c5d6-4e7f-8a9b-0c1d2e3f4a5b 0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc= xoImN8fTEOxXYnvgC6JZ0lN0n0qvZERwz/vlOjX3MkI= 2026-07-02T12:00:00.000Z ``` **Expected signature (base64):** `TwuvQD2mbRmt3iJx41Y1Rtr8kKARk+Gh2VndSz2ISO9vISaEuusVvCaglJi1Mh6QkBpWz4idDCXGuAHrPcsVAA==` ### sandbox_key_mint: mint_dns_txt - **private_key_seed**: `6666666666666666666666666666666666666666666666666666666666666666` - **public_key**: `NLTZBDFWy23PC+sKKUm3VZyUDSvLbb6MU6mzAnjjp0Y=` - **body**: `{"domain":"agents.example.com","public_key":"NLTZBDFWy23PC+sKKUm3VZyUDSvLbb6MU6mzAnjjp0Y=","verification_method":"dns_txt"}` - **canonical_body**: `{"domain":"agents.example.com","public_key":"NLTZBDFWy23PC+sKKUm3VZyUDSvLbb6MU6mzAnjjp0Y=","verification_method":"dns_txt"}` Signing payload (exact bytes, UTF-8, LF newlines): ``` {"domain":"agents.example.com","public_key":"NLTZBDFWy23PC+sKKUm3VZyUDSvLbb6MU6mzAnjjp0Y=","verification_method":"dns_txt"} ``` **Expected signature (base64):** `SpnD2impoE/h9gAmBPX8tkxsw/olk7LYfeGH3THDTd4x1ADhwnBkO0b8k68SMcYkIun+7FdDhvbFQltNgQL7Cg==` ## Intent chain Intent-to-commitment chain of custody: up to seven signed links tracing a transaction from the human signal to the outcome. Assembled by Core at commit; immutable. Beacons receive a redacted view. ### Links #### principal_signal **Signer:** scout_agent **Proves:** Scout received the principal's input and forwarded it faithfully. **Source:** Scout SDK at session creation #### interpretation **Signer:** core **Proves:** Core bound raw input to structured output via a specific model. **Source:** Interpretation attestation #### principal_review **Signer:** scout_agent **Proves:** Principal saw the interpretation and did not object, or was declared not consulted. **Source:** Scout SDK after interpretation #### offer_selection **Signer:** scout_agent **Proves:** The agent selected this offer from the available set. **Source:** Scout SDK at offer selection #### principal_consent **Signer:** scout_agent_or_principal **Proves:** Principal consented: explicit signature, cited policy, or cited delegation scope. **Source:** Authority attestation #### commitment **Signer:** core **Proves:** Core executed the atomic commit; counter-signature confirms authority verified and recorded. **Source:** Core at commit #### outcome **Signer:** core **Proves:** Terminal state: fulfillment/payment status or dispute resolution outcome. **Source:** Core at completion or dispute resolution **Beacon Redacted View:** - L2 - L4 - L6 - L7 ## Key lifecycle Key lifecycle for durable identities. A key is an instrument of an identity, never the identity: rotation and recovery change the key and its fingerprint while the identity, its bindings, its reputation, and its history persist unchanged. ### Rotation **Profile:** key_rotation **Operations:** - rotateAgentKey - rotatePrincipalKey **Authorization:** Dual-signed: the new key proves possession, the current key authorizes. old_key_authorization is required for every rotation, including agent self-rotation: the current key must sign the canonical payload explicitly. The request-level signature never authorizes a rotation, because it does not bind the request body (GAP-01). **Freshness Window Seconds:** 300 **Replay:** Core records the committed rotation tuple. An exact duplicate of a committed rotation returns idempotent success; any other reuse fails as rotation_replayed; a payload built against a superseded key fails as key_rotation_conflict. **Atomicity:** The retired key stops authorizing at commit. At no point do two keys authorize for the same identity. ### Recovery #### Agent **Operation:** replaceAgentKey **Authorization:** The principal's key authorizes over the same canonical payload; the compromised agent key signs nothing. #### Principal **Reason:** external_credential_reverification_required ##### Current Behaviour **Operation:** recoverPrincipalKey **Error:** recovery_not_available **Http:** 403 ### Key History **Verification Only:** true **Validity:** A rotated-out key verifies artifacts whose Core-recorded signing time falls at or after the key became active and before it rotated out. Historical verification anchors on Core-recorded time or a time bound into a Core counter-signature, never on a timestamp carried inside the artifact alone. **Uniqueness:** A key used anywhere, ever, can never be registered again by any identity. **Authorization:** Nothing in key history authorizes a new action. **Discovery:** The versioned discovery root advertises features.key_rotation, features.agent_key_recovery, and features.principal_key_recovery. ## Agent admission The ordered lifecycle through which an autonomous agent earns production access. Each phase names its purpose, the operations that execute it, the evidence that proves it was completed, and the failure modes that block it; evidence is load-bearing because a phase without evidence is a claim, and claims are verified, never assumed. The phases are ordered because each consumes the previous phase's evidence: scope is granted to a proven key, a sandbox is provisioned to a scoped key, flows execute inside a provisioned sandbox, conformance runs over flow transcripts, certification signs conformance results, and promotion presents certification. No phase is skippable. Phase status is honest: implemented phases run today against this contract; a roadmap phase lists any not-yet-served operations in roadmapOperations, and may list already-served operations in operations when only the phase's orchestration is unshipped. failureModes on implemented phases are the exact catalogued error codes the condition surfaces as; failureModes on roadmap phases name the blocking condition, and their wire-level codes enter x-aura-errors as the operations ship, under the existing two-way harvest gate. ### Phases #### discover **Purpose:** The agent finds the protocol and its machine-readable surfaces. **Entry Points:** - https://aura-labs.ai/llms.txt - https://aura-labs.ai/openapi.json - https://aura-labs.ai/api/mcp **Evidence:** #### learn **Purpose:** The agent reads the law it will be held to. ##### References **Extensions:** - x-aura-invariants - x-aura-authority - x-aura-signature-profiles - x-aura-signature-test-vectors - x-aura-errors - x-aura-key-lifecycle **Evidence:** #### request_identity **Purpose:** The agent requests a protocol identity: a principal anchor and an agent record bound to an Ed25519 key. **Operations:** - registerPrincipal - registerAgent - registerBeacon **Notes:** Keys bind through registerPrincipal and registerAgent (a Beacon operator registers its agent with type beacon). registerBeacon creates the market-facing Beacon listing and carries no key. On the bench, registration carries no build credential and stamps no namespace on the identity; a presented X-AURA-Sandbox-Context attributes the registration to a run, best-effort, and never gates it. **Evidence:** - ed25519_public_key **Failure Modes:** - invalid_key - missing_signature - invalid_signature - key_revoked #### prove_key_control **Purpose:** The agent proves possession of the private key on every request. **Mechanism:** Every request is signed by the registered key under the authenticated_request signature profile; the published signature test vectors let an agent prove its canonicalisation byte-exactly before signing live requests. Request timestamps must fall within the profile freshness window; a stale timestamp fails as invalid_signature. ##### Roadmap Mechanism **Mechanism:** RFC 9421 HTTP Message Signatures over the same Ed25519 keys (Web Bot Auth profile) **Key Discovery:** - domain_hosted_key_document - core_hosted_directory **Evidence:** - verified_request_signature **Failure Modes:** - missing_auth_headers - unknown_agent - invalid_signature #### obtain_scope **Purpose:** The agent mints a scoped, prefixed sandbox key. The key is the tenant anchor for one namespace; the verified domain proved at minting is the identity anchor every quota counts against. **Evidence:** - scoped_key_grant **Failure Modes:** - invalid_domain - mint_proof_invalid - key_already_used - sandbox_identity_not_verified - rate_limit_exceeded **Operations:** - mintSandboxKey **Mechanism:** Two proofs over one mint request. Possession: the X-Signature header carries the Ed25519 signature over the exact JSON body by the declared key. Domain control: publish the key where only the domain's controller can, either TXT _aura-agent-key. = aura-key= (dns_txt) or https:///.well-known/aura-agent-key returning JSON with a matching public_key (well_known). One active key per domain; re-mint revokes the prior key and is the compromise-recovery path. The grant is bearer, shown once, stored hashed, and consumable now: provision the namespace it anchors with provisionSandbox. #### provision_sandbox **Purpose:** Core provisions an isolated, seeded, deterministic market for the key: rows in a standing deployment, never new infrastructure, so provisioning is a single idempotent call. **Operations:** - provisionSandbox - resetSandbox **Evidence:** - sandbox_manifest **Failure Modes:** - sandbox_key_invalid - sandbox_quota_exceeded - sandbox_namespace_conflict - sandbox_contract_version_skew - sandbox_provisioning_unavailable - sandbox_run_active #### execute_validation_flows **Purpose:** The agent exercises the golden paths and the failure paths for its role against seeded deterministic counterparties. The operations are served today; running them as validation flows requires a provisioned sandbox. **Operations:** - createSession - submitOffer - counterOffer - commitSession - getClearing - fileDispute - getIntentChain **Evidence:** - flow_transcripts **Failure Modes:** - flow_incomplete - invariant_violation #### run_conformance **Purpose:** The harness executes the role profile's assertions against the flow transcripts. ##### References **Extensions:** - x-aura-conformance **Roadmap Operations:** - runConformance **Evidence:** - assertion_results **Failure Modes:** - assertion_failed #### receive_certification **Purpose:** Core signs the assertion results as presentable, expiring evidence. **Roadmap Operations:** - getCertification **Evidence:** - certification_attestation #### request_production_promotion **Purpose:** The agent presents certification and requests promotion, gated on the entity verification level the target tier requires. **Roadmap Operations:** - requestPromotion **Evidence:** - certification_attestation - entity_verification **Failure Modes:** - certification_expired - verification_insufficient ### Tooling **Description:** How an agent performs the admission chain. The action path holds the agent's Ed25519 keys and signs the requests in the agent's own environment; the private key never leaves the agent (hosted surfaces read and explain, they never sign). Two ways to act: the local action MCP, or direct REST. #### Action mcp **Package:** @aura-labs-ai/mcp-server-admission **Transport:** stdio **Install:** npx -y @aura-labs-ai/mcp-server-admission **Key custody:** local **Purpose:** A local, key-holding MCP server. It holds an Ed25519 wallet, runs the two-phase domain-control proof, and performs the signed admission requests itself, driving the chain from mint through provision, principal and agent registration, and reset, with a recorded run. **Tools:** - get_admission_guide - mint_sandbox_key - provision_sandbox - register_principal - register_agent - reset_sandbox #### Direct rest **Description:** The chain is also performable by direct REST with no packaged tool: implement Ed25519 signing against the published test vectors and call the operations named on each phase. This is supported but agent-burdened; the action MCP is the intended completion path. **Reference:** x-aura-signature-test-vectors ### Sandbox **Description:** A provisioned sandbox is a market in miniature on standing infrastructure: seeded principals at declared verification levels, deterministic Scout and Beacon counterparties, a declared market profile, and simulated settlement rails covering both reserve branches. Isolation is a logical namespace per sandbox key; a namespace is rows, never infrastructure. #### Provisioning **Operation Id:** provisionSandbox **Idempotent:** true **Description:** Re-provisioning with the same key returns the existing manifest as success, never a conflict: an agent retrying a timeout lands on the same state. #### Reset **Operation Id:** resetSandbox **Run Boundary:** true **Description:** Destroy-and-reseed at namespace grain. Every conformance run opens with a reset and receives the run identity that transcripts, assertion results, and quotas key on. Evidence is stored outside the namespace and survives reset. **Failure Modes:** - sandbox_run_active - sandbox_quota_exceeded - sandbox_namespace_conflict - sandbox_key_invalid **Manifest Schema:** #/components/schemas/SandboxManifest **Transcript Schema:** #/components/schemas/ConformanceTranscript #### Semantic Exceptions **Rule:** production_key_reuse_forbidden **Sandbox exception:** seeded_house_counterparty_keys_reused_after_namespace_reset **Applies to:** house_counterparties_only #### Quotas **Quotas Are Defaults:** true **Note:** Launch defaults, returned per namespace as manifest facts. The namespace count is quota policy, never protocol law: the operator may grant more active namespaces without protocol change. ##### Defaults ###### Active namespaces per identity **Value:** 1 **Operator grantable:** true ###### Active sandbox keys per domain **Value:** 1 **Rule:** Re-minting under the same domain revokes the prior key in the same transaction; compromise recovery is re-mint under the re-proven domain. **Provisions per identity per day:** 3 ###### Conformance runs per key per day **Value:** 10 **Counting:** each run opens with a reset; the opening reset is included, never double-counted ###### Requests per namespace per minute **Value:** 120 **Keying:** per namespace, after signature verification **Namespace idle ttl hours:** 72 ###### Global namespace cap **Value:** 500 **On exceeded:** backpressure with HTTP 429 ###### Transcript retention days **Value:** 90 **Or:** until superseded by a newer certified run ###### Outbound webhook dispatch **Rule:** Per-namespace dispatch cap; the endpoint host allowlists to the identity's verified domain. Implemented when sandbox event dispatch ships. ##### Tiers **Keying:** Tier follows the identity's verification level: T0 self_declared, T1 domain_verified, T2 entity_verified, T3 kyc_verified with a passing certification. The tier is always derived from the verified key row, never from a request field. **Activation:** T1 is enforced today: minting requires domain proof, so every live key holds at least T1, and T0 is defined but unreachable until a keyless tier exists. T2 and T3 are declared and inert until the verification-level vocabulary is enumerated in this contract; until then every key resolves to T1. The defaults block above is the T1 row, unchanged. ###### T0 **Provisions per identity per day:** 1 **Active namespaces per identity:** 1 **Namespace idle ttl hours:** 2 **Namespace idle ttl hard max hours:** 6 **Requests per namespace per minute:** 30 **Conformance runs per key per day:** 2 ###### T1 **Provisions per identity per day:** 3 **Active namespaces per identity:** 1 **Namespace idle ttl hours:** 72 **Requests per namespace per minute:** 120 **Conformance runs per key per day:** 10 ###### T2 **Provisions per identity per day:** 10 **Active namespaces per identity:** 3 **Namespace idle ttl hours:** 168 **Requests per namespace per minute:** 300 **Conformance runs per key per day:** 50 ###### T3 **Provisions per identity per day:** 25 **Active namespaces per identity:** 10 **Namespace idle ttl hours:** 336 **Requests per namespace per minute:** 600 **Conformance runs per key per day:** 200 #### Latency Budgets **Provision p50 ms:** 300 **Provision p99 ms:** 1000 #### Determinism **Level:** transcript **Normalized:** - uuids - timestamps **Statement:** Same agent behaviour produces the same canonical transcript. Signatures and hash chains bind to the raw transcript; comparison uses the normalized transcript derived through a retained first-occurrence substitution map. Nothing signs a normalized transcript. #### Scenario Versioning **Format:** scenario_version = /. The semver versions the published scenario family and increments per family revision; a conformance run binds to exactly one scenario_version. ##### Disclosure **Public Scenario Family:** Stable, documented, versioned in the contract: what kinds of flows and failures a family contains. **Manifest Scenario Facts:** Visible to the applicant for that run: concrete dial values, counterparty keys, declared tiers, the determinism statement. **Holdout Variation Rules:** Bounded and attested, never fully published: seed-varied variants within the declared family defeat memorised answers. **Families:** - scout-admission - beacon-admission ### Certification **Attests:** Conformance to a versioned scenario family at a named contract version, never general capability. The attestation names the family and scenario version the run belonged to without revealing the variant generator. **Evidence:** Assertion results signed by Core, carrying the agent identity, the role profile and its version, the contract version certified against, and an expiry. Certification ages out rather than lying forever. **Verification:** One Ed25519 signature check against the published signing key. ## Transcript events The frozen vocabulary of events a sandbox run transcript records. The names and their payload fields are frozen here; this is the single source the run recorder and the transcript event type values draw from. coverage declares which events the recorder emits in its first capture increment (required) and which names are frozen but not yet emitted by the recorder (reserved), so the vocabulary is committed independently of implementation coverage. coverage is scoped to the transcript recorder and is distinct from delivery on the webhook channel: an event may be reserved here while already delivered as a webhook. Every transcript event carries these fields. seq is the monotonic position within the run; type is one of the names in events; at is the event time. Event-specific identity and domain fields are listed per event under payload. The recorder emits raw events carrying real ids and timestamps, and the normalized layer substitutes UUIDs and timestamps through the retained map. **Event envelope fields:** - seq - type - at ### principal.registered (required) A principal was registered, the party on whose behalf an agent acts. - principal_id - verification_level - at ### agent.registered (required) An agent was registered and bound to a principal. - agent_id - principal_id - at ### sandbox_key.minted (required) A sandbox key was minted for the agent, scoped to the run's tier. - key_fingerprint - tier - at ### sandbox.provisioned (required) A sandbox namespace was provisioned and seeded from the minted key. - namespace_id - tier - at ### sandbox.reset (required) The namespace was reset, opening a new run and issuing its run boundary. - namespace_id - run_id - at ### session.created (required) A shopping session was created. - session_id - at ### session.matched (required) The session matched to counterparties able to make offers. - session_id - at ### offer.submitted (required) A beacon submitted an offer into the session. - session_id - offer_id - at ### offer.presented (required) An offer was presented to the scout for evaluation. - session_id - offer_id - at ### commit.requested (required) The scout requested commitment to an offer. - session_id - offer_id - at ### commit.accepted (required) The commitment was accepted and bound. - session_id - offer_id - transaction_id - at ### transaction.created (required) The transaction exists as the result of the accepted commitment. - transaction_id - session_id - offer_id - at ### intent_chain.link_added (required) A link was added to the transaction's intent chain. - transaction_id - link - at ### offer.expired (reserved) RESERVED (not yet emitted): an offer passed its expiry before a commitment. - session_id - offer_id - at ### offer.rejected (reserved) RESERVED (not yet emitted): an offer was rejected. - session_id - offer_id - at ### commit.rejected (reserved) RESERVED (not yet emitted): a commitment request was rejected. - session_id - offer_id - at ### clearing.started (reserved) RESERVED (not yet emitted): clearing began for a transaction. - transaction_id - at ### clearing.advanced (reserved) RESERVED (not yet emitted): clearing advanced a stage. - transaction_id - stage - at ### payment.updated (reserved) RESERVED (not yet emitted): the payment state of a transaction changed. The same lifecycle event is delivered on the webhook channel; the transcript records it independently. - transaction_id - at ### fulfillment.updated (reserved) RESERVED (not yet emitted): the fulfillment state of a transaction changed. The same lifecycle event is delivered on the webhook channel; the transcript records it independently. - transaction_id - at ### dispute.filed (reserved) RESERVED (not yet emitted): a dispute was filed against a transaction. - transaction_id - dispute_id - at ### dispute.evidence_submitted (reserved) RESERVED (not yet emitted): evidence was submitted for a dispute. - transaction_id - dispute_id - at ### dispute.resolved (reserved) RESERVED (not yet emitted): a dispute was resolved. - transaction_id - dispute_id - at ## Webhooks Core pushes these events to a Beacon's registered endpoint_url. Every delivery is signed: X-AURA-Signature is the base64 Ed25519 signature over the X-AURA-Event value, the X-AURA-Timestamp value, and the exact body, newline-delimited, verifiable against GET /.well-known/core-signing-key (see the webhook_delivery signature profile and its test vector). Delivery retries at 1s, 2s, 4s with a 5 second timeout, never follows redirects, and dead-letters after the final failure; replay re-delivers with the same idempotency key where the event carries one. Reserved names are marked roadmap: subscribe now, the emitters ship later. ### transaction.committed A Scout committed to this Beacon's offer; the transaction exists. - **transaction_id**: string (uuid) - **idempotency_key**: string. Deduplicate on this; a retried delivery carries the same key. - **session_id**: string (uuid) - **offer_id**: string (uuid) - **final_terms**: object ### transaction.disputed A dispute was filed against this transaction. - **dispute_id**: string (uuid) - **transaction_id**: string (uuid) - **reason**: string - **category**: string - **description**: string - **evidence_deadline**: string (date-time) - **resolution_deadline**: string (date-time) ### clearing.risk_assessed Clearing opened at commit: risk scored and the reserve plan set. - **transaction_id**: string (uuid) - **clearing_id**: string (uuid) - **status**: string - **reserve_status**: string - **risk_tier**: string - **reserve_margin_amount**: number - **net_settlement_amount**: number - **currency**: string - **settlement_method**: string ### clearing.settled Settlement confirmed on the rail. - **transaction_id**: string (uuid) - **clearing_id**: string (uuid) - **status**: string - **previous_status**: string ### clearing.cleared Clearing complete; the dispute term governs the reserve from here. - **transaction_id**: string (uuid) - **clearing_id**: string (uuid) - **status**: string - **previous_status**: string ### reserve.released The held reserve released to the seller after clean clearing. - **transaction_id**: string (uuid) - **clearing_id**: string (uuid) - **status**: string - **previous_status**: string ### fulfillment.updated The Beacon reported a fulfillment change (shipped, delivered). - **transaction_id**: string (uuid) - **idempotency_key**: string - **session_id**: string (uuid) - **fulfillment_status**: string - **fulfillment_reference**: string or null - **status**: string ### payment.updated Payment state changed (pending, charged, failed, refunded). - **transaction_id**: string (uuid) - **idempotency_key**: string - **session_id**: string (uuid) - **payment_status**: string - **payment_reference**: string or null - **status**: string ### reserve.drawn (roadmap) RESERVED NAME (not yet emitted): the reserve was drawn down to fund a dispute payout. Subscribe now; the emitter ships with the dispute-drawdown path. - **transaction_id**: string (uuid) - **clearing_id**: string (uuid) - **status**: string - **previous_status**: string ### enforcement.triggered (roadmap) RESERVED NAME (not yet emitted): a principal crossed an enforcement threshold. Subscribe now; the emitter ships with the risk loop. - **principal_id**: string (uuid) - **enforcement_status**: string ### reserve.rail_managed (roadmap) RESERVED NAME (not yet emitted): the rail's native repudiation infrastructure governs this transaction; no AURA-side reserve was held. Subscribe now; the emitter ships with the rail-conditional outcome events. - **transaction_id**: string (uuid) - **clearing_id**: string (uuid) - **currency**: string ### reserve.held A reserve margin is held against the seller's settlement proceeds (non-repudiation rails). - **transaction_id**: string (uuid) - **clearing_id**: string (uuid) - **reserve_margin_amount**: number - **reserve_margin_pct**: number - **currency**: string ## Vocabulary Canonical definitions of the protocol's terms. - **Scout**: An autonomous agent acting for a buyer. - **Beacon**: An autonomous agent acting for a seller. - **AURA Core**: The neutral broker. It interprets intent, routes it to beacons, mediates the exchange, and records the outcome. It holds no commercial position. - **Principal**: The human or legal entity an agent acts for under delegated authority. - **Session**: A logical exchange from a scout's request to a committed transaction. - **Request**: A scout's expression of need: a natural-language intent and optional constraints. - **Interpreted Request**: Core's structured representation of a scout's intent. - **Offer**: A beacon's signed response carrying product, price, and terms. - **Constraint**: A buyer's declared bound on an acceptable outcome. A hard constraint binds. A soft preference ranks. - **Transaction**: A committed exchange between a scout and a beacon. - **Clearing record**: The financial lifecycle of a committed transaction: risk assessment, reserve, and settlement. - **Intent chain**: The signed chain of custody from the human signal to the outcome, links L1 to L7. - **Reputation**: A multi-dimensional behavioural signal Core computes from protocol events. - **Settlement rail**: An external payment system that moves funds for a cleared transaction. - **Market profile**: A named set of market parameters a Core applies within the protocol's invariants. ### Entities The protocol's entities, their roles, relationships, and prohibitions. Tooling and agents reason over this model; humans read the glossary. - **Scout** (agent): An agent acting for a buyer. - **Beacon** (agent): An agent acting for a seller. - **Core** (neutral_broker): The disinterested party that mediates every exchange. - **Principal** (party): The human or legal entity an agent acts for. - **Session** (resource): An exchange from request to commitment. - **Offer** (resource): A beacon's signed, sealed response. - **Transaction** (resource): A committed exchange. - **ClearingRecord** (resource): The financial lifecycle of a transaction. - **IntentChain** (record): The signed chain of custody from signal to outcome. - **Request** (signal): A Scout's expression of need. - **InterpretedRequest** (derived_record): Core's structured representation of the Scout's intent. - **Constraint** (authority_boundary): A declared bound on an acceptable outcome. A hard constraint binds; a soft preference ranks. - **Reputation** (behavioural_signal): A multi-dimensional behavioural signal Core computes from protocol events. ## Authentication Every operation requires the following by default, unless its own entry says otherwise: agentId, agentTimestamp, agentSignature. - **agentId** (apiKey, in header as `X-Agent-Id`): The agent's UUID. Sent together with X-Agent-Timestamp and X-Agent-Signature; the three authenticate a request (see x-aura-signature-profiles.authenticated_request). - **agentTimestamp** (apiKey, in header as `X-Agent-Timestamp`): RFC 3339 timestamp. Sent together with X-Agent-Id and X-Agent-Signature. - **agentSignature** (apiKey, in header as `X-Agent-Signature`): Ed25519 signature over the canonical request (method, path, timestamp, body hash). Sent together with X-Agent-Id and X-Agent-Timestamp; all three are required. - **agentProof** (apiKey, in header as `X-Agent-Signature`): Proof-of-possession for agent registration: Ed25519 signature over the request body, proving control of the submitted public key. - **principalProof** (apiKey, in header as `X-Signature`): Proof-of-possession for principal registration: Ed25519 signature over the request body. - **systemToken** (apiKey, in header as `X-System-Token`): System-only shared secret for internal lifecycle endpoints. Not issued to client integrations. - **sandboxKey** (apiKey, in header as `X-AURA-Sandbox-Key`): The sandbox tenant anchor, minted by mintSandboxKey. Bearer presentation is deliberate: the key is a capability handle for one quota-bounded namespace, never a protocol identity; issuance is proof-anchored (a signed mint request plus domain publication), theft's blast radius is one namespace, and the remedy is re-mint under the re-proven domain. Protocol identity stays proof-of-possession on every flow call. Namespaced operations on the sandbox host require this header alongside the existing proof schemes now that provisioning is live. - **sandboxMintProof** (apiKey, in header as `X-Signature`): Proof-of-possession for sandbox key minting: the Ed25519 signature (base64) over JSON.stringify of the mint request body by the declared public_key, per the sandbox_key_mint signature profile and its test vector. This is the ONLY auth mintSandboxKey requires: obtain_scope mints a key for a domain-verified keypair that has no protocol identity yet, so the registered-agent auth headers do not apply. ## Operations ### Discovery Public capability discovery: profiles, settlement rails, signing key, and HATEOAS roots. #### GET /: API version discovery (HATEOAS root) An agent that has never seen this market needs a way in that asks nothing of it first. The root advertises the protocol version and the links to follow, so discovery comes before any credential or commitment. **Authentication:** public (no authentication). **Responses:** - `200`: object #### GET /v1/: v1 HATEOAS root The entry point for v1. It lists the operations an agent reaches from here, so a client navigates the protocol by following links rather than hard-coding paths. **Authentication:** public (no authentication). **Responses:** - `200`: object #### GET /v1/.well-known/core-signing-key: Core's Ed25519 public signing key Core counter-signs offers and attestations, so a counterparty has to check those signatures without taking Core's word for its own key. The signing key is published openly for exactly that, which is what lets Core act as a [neutral broker](https://aura-labs.ai/invariants.html#neutral-brokerage) whose every signature is independently verifiable. **Authentication:** public (no authentication). **Responses:** - `200`: object #### GET /v1/profiles: List active market profiles A market adapts the protocol to its vertical by setting bounded parameters: how long offers stay live, how long a deal stays repudiable, which rails settle it. Profiles publish those choices so an agent reads the terms before it enters. The parameters move within bounds the [invariants](/invariants.html) fix; they never tune the law away. **Authentication:** public (no authentication). **Responses:** - `200`: object #### GET /v1/profiles/{profile_id}: Retrieve a market profile Returns one market profile in full: the disclosure schedule, validity windows, settlement methods, and dispute terms a participant agrees to by transacting under it. An agent reads this to know the rules of the specific market it is entering. **Authentication:** public (no authentication). **Responses:** - `200`: Profile - `404`: NotFound #### POST /v1/profiles/{profile_id}/validate: Validate terms against a profile's minimums Before building against a market, an agent should learn whether a configuration is admissible under the profile rather than discovering it at commit. This checks a candidate against the profile's rules and returns the verdict. **Authentication:** public (no authentication). **Request body:** ProfileValidationRequest. **Responses:** - `200`: object #### GET /v1/settlement-rails: List active settlement-rail adapters Settlement is where value actually moves, and rails differ in finality and recourse. Publishing the available rails lets a market and its agents choose settlement with open eyes, which is what makes [rail-conditional reserve](https://aura-labs.ai/invariants.html#rail-conditional-reserve) and [verifiable settlement](https://aura-labs.ai/invariants.html#verifiable-settlement) computable rather than guessed. **Authentication:** public (no authentication). **Responses:** - `200`: object #### GET /v1/settlement-rails/{adapter_id}/capabilities: Get a settlement adapter's capabilities Returns one rail's capabilities: its finality model, whether it carries native repudiation, and the proof it emits. Clearing reads this to size the reserve to the rail ([rail-conditional reserve](https://aura-labs.ai/invariants.html#rail-conditional-reserve)) and to demand a correlated settlement proof ([verifiable settlement](https://aura-labs.ai/invariants.html#verifiable-settlement)). **Authentication:** public (no authentication). **Responses:** - `200`: SettlementRail - `404`: NotFound ### Identity Principal (legal entity) and agent (Scout/Beacon) registration and lookup. #### POST /v1/principals: Register a principal (legal entity) A market for lemons is what you get when a seller can shed a bad reputation by registering again. The principal is the durable, accountable entity behind the ephemeral agents, and registering it with a proof of key possession is what makes reputation and qualification stick to something that cannot be cheaply discarded ([persistent identity and qualification](https://aura-labs.ai/invariants.html#persistent-identity-and-qualification)). **Authentication:** principalProof. **Signature profile:** principal_registration. **Request body:** PrincipalRegistration. **Responses:** - `200`: Principal - `201`: Principal - `400`: BadRequest #### GET /v1/principals/{principal_id}: Retrieve a principal A principal's record is the accountable root the rest of the protocol chains back to. Reading it is scoped to the entity acting on its own anchor ([least-privilege delegated authority](https://aura-labs.ai/invariants.html#least-privilege-delegated-authority)): a caller sees its own principal, never another's. **Authentication:** agentId + agentTimestamp + agentSignature (default). **Responses:** - `200`: Principal - `404`: NotFound #### PUT /v1/principals/{principal_id}: Update a principal's mutable fields A principal's contact and operating name change over time; its legal identity and verification history are fixed. Update accepts the mutable fields and refuses the immutable ones, and only the entity acting on its own anchor may call it ([least-privilege delegated authority](https://aura-labs.ai/invariants.html#least-privilege-delegated-authority)). **Authentication:** agentId + agentTimestamp + agentSignature (default). **Request body:** PrincipalUpdate. **Responses:** - `200`: Principal - `400`: BadRequest - `404`: NotFound #### POST /v1/principals/{principal_id}/rotate-key: Rotate a principal signing key Rotates a principal signing key under the same canonical payload and dual-signature rule as agent rotation ([persistent identity and qualification](https://aura-labs.ai/invariants.html#persistent-identity-and-qualification)). Principal requests carry no request-level agent authentication, so old_key_authorization is required in the body: the current principal key must authorize the rotation explicitly. The verification level, bound agents, and history persist unchanged. **Authentication:** agentId + agentTimestamp + agentSignature (default). **Request body:** KeyRotationRequest. **Responses:** - `200`: object - `403`: Forbidden - `404`: NotFound - `409`: object - `422`: object #### POST /v1/principals/{principal_id}/recover-key: Recover a principal key (not yet available) A compromised principal key cannot authorize its own replacement. Principal identity anchors in external credentials, the same relying-party act that establishes the verification level, and recovery re-anchors on those credentials through a re-verification workflow that has not yet shipped. Until it does, this operation answers 403 recovery_not_available unconditionally, and a compromised principal key is an operational incident: revoke the bound agents and contact the operator. The versioned discovery root advertises features.principal_key_recovery so an agent can learn the capability without probing. **Authentication:** agentId + agentTimestamp + agentSignature (default). **Responses:** - `403`: object #### POST /v1/agents/register: Register an agent (Scout or Beacon) An agent is a key, and a key is cheap. What makes an agent trustworthy is the durable principal it acts for. Registration binds the agent's key to a principal with a proof of possession, so every action the agent takes inherits an accountable identity ([persistent identity and qualification](https://aura-labs.ai/invariants.html#persistent-identity-and-qualification)). **Authentication:** agentProof. **Signature profile:** agent_registration. **Request body:** AgentRegistration. **Responses:** - `200`: Agent - `201`: Agent - `400`: BadRequest #### GET /v1/agents/{agent_id}: Get agent details An agent is a marker that indexes a durable record, so a counterparty has to resolve what an agent is and whose authority it carries. This returns the agent's type, status, and principal binding, scoped to the caller's own anchor ([least-privilege delegated authority](https://aura-labs.ai/invariants.html#least-privilege-delegated-authority)). **Authentication:** agentId + agentTimestamp + agentSignature (default). **Responses:** - `200`: Agent - `404`: NotFound #### GET /v1/principals/{principal_id}/agents: List a principal's agents A principal may run many agents. Listing them is an administrative view of the entity's own roster, available only to the entity acting on its own anchor ([least-privilege delegated authority](https://aura-labs.ai/invariants.html#least-privilege-delegated-authority)); one agent cannot enumerate another principal's fleet. **Authentication:** agentId + agentTimestamp + agentSignature (default). **Responses:** - `200`: object - `404`: NotFound #### POST /v1/principals/{principal_id}/agents/{agent_id}/replace-key: Replace a compromised agent key (principal-authorized recovery) Compromise recovery for an agent key that can no longer be trusted to sign. The principal that anchors the agent authorizes the replacement: principal_authorization is the principal key's signature over the same canonical payload, and the compromised key signs nothing. A holder of the stolen agent key alone cannot move the identity; the authority to replace an agent's key rests with its principal ([least-privilege delegated authority](https://aura-labs.ai/invariants.html#least-privilege-delegated-authority)). The agent must be bound to the addressed principal. **Authentication:** agentId + agentTimestamp + agentSignature (default). **Request body:** KeyReplacementRequest. **Responses:** - `200`: object - `403`: Forbidden - `404`: NotFound - `409`: object - `422`: object #### GET /v1/principals/{principal_id}/transactions: List transactions a principal is party to Accountability outlives any single agent or session, so a principal has to see what was committed in its name after the fact. This returns the transactions the principal is party to, scoped to its own anchor ([least-privilege delegated authority](https://aura-labs.ai/invariants.html#least-privilege-delegated-authority)). **Authentication:** agentId + agentTimestamp + agentSignature (default). **Responses:** - `200`: object - `404`: NotFound #### POST /v1/agents/{agent_id}/revoke: Revoke an agent identity When an agent misbehaves or its key is compromised, the harm has to be stoppable without unwinding the principal behind it. Revocation blacklists the agent's key so its future requests are refused, while the principal and its history persist ([persistent identity and qualification](https://aura-labs.ai/invariants.html#persistent-identity-and-qualification)). **Authentication:** agentId + agentTimestamp + agentSignature (default). **Request body:** object. **Responses:** - `200`: object - `401`: Unauthorized - `403`: Forbidden - `404`: NotFound #### POST /v1/agents/{agent_id}/rotate-key: Rotate an agent signing key An agent's key is an instrument of its identity, never the identity itself. Rotation replaces the signing key while the agent's id, principal binding, reputation, and history persist unchanged ([persistent identity and qualification](https://aura-labs.ai/invariants.html#persistent-identity-and-qualification)). The operation is dual-signed over the canonical key_rotation payload: new_key_proof proves possession of the incoming key, and the current key authorizes. old_key_authorization is required: the current key must sign the canonical payload explicitly, because the request signature does not bind the request body and so cannot authorize the enclosed rotation. Core constructs old_public_key from the live record; a payload built against a superseded key fails as key_rotation_conflict. The rotation timestamp must fall within 300 seconds of receipt, and an exact duplicate of a committed rotation returns idempotent success. The retired key moves to verification-only history: everything it ever signed remains verifiable, and it authorizes nothing new. An agent can rotate only its own key. **Authentication:** agentId + agentTimestamp + agentSignature (default). **Request body:** KeyRotationRequest. **Responses:** - `200`: object - `401`: Unauthorized - `403`: Forbidden - `404`: NotFound - `409`: object - `422`: object #### GET /v1/agents/{agent_id}/delegation-scope: Get the active delegation scope Authority an agent assumes by default is authority no principal granted. The delegation scope is the explicit, signed boundary a principal sets on what an agent may commit. Reading it is how [least-privilege delegated authority](https://aura-labs.ai/invariants.html#least-privilege-delegated-authority) becomes inspectable. **Authentication:** agentId + agentTimestamp + agentSignature (default). **Responses:** - `200`: DelegationScope - `401`: Unauthorized - `403`: Forbidden - `404`: NotFound #### PUT /v1/agents/{agent_id}/delegation-scope: Create or replace the active delegation scope A principal narrows what its agents may do by setting their scope, never by trusting them to stay in bounds on their own. Writing the scope fixes the signed mandate a commit is later tested against ([least-privilege delegated authority](https://aura-labs.ai/invariants.html#least-privilege-delegated-authority), [constraints as bounds](https://aura-labs.ai/invariants.html#constraints-as-bounds)). **Authentication:** agentId + agentTimestamp + agentSignature (default). **Request body:** DelegationScopeRequest. **Responses:** - `200`: DelegationScope - `400`: BadRequest - `401`: Unauthorized - `403`: Forbidden - `404`: NotFound ### Market Navigation Commerce sessions and offers, the core Scout/Beacon flow. #### POST /v1/sessions: Create a commerce session from intent A buyer's intent has to enter the market somewhere. Sent straight to sellers, it hands them the buyer's position to probe and price against, and it leaves no neutral account of what was asked. The session is where Core takes the intent instead: it interprets the natural language, signs an attestation binding the raw words to their structured meaning, and stands in the middle as [neutral broker](https://aura-labs.ai/invariants.html#neutral-brokerage) rather than wiring the two sides together, recording the intent from its origin ([recorded intent and chain of custody](https://aura-labs.ai/invariants.html#recorded-intent-and-chain-of-custody)). The interpretation fixes the authorised negotiation space before any offer exists, so a later commitment can be tested against the mandate the principal actually granted ([constraints as bounds](https://aura-labs.ai/invariants.html#constraints-as-bounds)). **Authentication:** agentId + agentTimestamp + agentSignature (default). **Signature profile:** interpretation_attestation. **Request body:** SessionCreate. **Responses:** - `200`: Session - `400`: BadRequest - `401`: Unauthorized #### GET /v1/sessions/{session_id}: Retrieve a session A Scout watches its session to know when offers are ready and what state it is in. What it sees respects [identity abstraction until commitment](https://aura-labs.ai/invariants.html#identity-abstraction-until-commitment), so a counterparty's identity stays sealed, and [monotonic disclosure](https://aura-labs.ai/invariants.html#monotonic-disclosure), so a field once visible never vanishes. Reading the session never leaks what the phase has not yet earned. **Authentication:** agentId + agentTimestamp + agentSignature (default). **Responses:** - `200`: Session - `401`: Unauthorized - `403`: Forbidden - `404`: NotFound #### GET /v1/sessions/{session_id}/offers: List pending offers (Scout) Offers are what a Scout chooses between, and seeing them must not become a way to unmask sellers early. This returns the session's offers under [identity abstraction until commitment](https://aura-labs.ai/invariants.html#identity-abstraction-until-commitment) and [monotonic disclosure](https://aura-labs.ai/invariants.html#monotonic-disclosure): the terms are visible, the counterparty behind them is not, until commitment earns it. **Authentication:** agentId + agentTimestamp + agentSignature (default). **Responses:** - `200`: object - `401`: Unauthorized - `403`: Forbidden #### POST /v1/sessions/{session_id}/offers: Submit a signed offer (Beacon) An offer is a seller's commitment to terms, and a market is only as real as that commitment. A bare price is cheap to send and cheaper to retract. So the Beacon signs the offer with its key, Core verifies it and counter-signs as [neutral broker](https://aura-labs.ai/invariants.html#neutral-brokerage), and the offer carries an [expiry](https://aura-labs.ai/invariants.html#offer-expiry) from the moment it exists. The buyer's identity stays sealed while this happens ([identity abstraction until commitment](https://aura-labs.ai/invariants.html#identity-abstraction-until-commitment)), so the seller prices the goods and not the counterparty, and the terms are checked against the session's [bounds](https://aura-labs.ai/invariants.html#constraints-as-bounds). **Authentication:** agentId + agentTimestamp + agentSignature (default). **Signature profile:** beacon_offer. **Request body:** OfferSubmission. **Responses:** - `201`: Offer - `400`: BadRequest - `401`: Unauthorized #### POST /v1/sessions/{session_id}/cancel: Cancel a session A Scout that no longer wants what it asked for needs a clean exit before it commits, so abandoned sessions do not linger as phantom demand. Cancel closes a session the caller owns, provided it has not already committed. **Authentication:** agentId + agentTimestamp + agentSignature (default). **Responses:** - `200`: object - `401`: Unauthorized - `403`: Forbidden - `404`: NotFound #### GET /v1/sessions/{session_id}/attestation: Get the interpretation attestation When Core interprets a natural-language intent, the buyer has to be able to prove later what Core understood it to mean. The attestation is Core's signed binding between the raw words and their structured interpretation, the first link in the [recorded chain of custody](https://aura-labs.ai/invariants.html#recorded-intent-and-chain-of-custody). **Authentication:** agentId + agentTimestamp + agentSignature (default). **Signature profile:** interpretation_attestation. **Responses:** - `200`: Attestation - `401`: Unauthorized - `403`: Forbidden - `404`: NotFound #### POST /v1/offers/{offer_id}/counter: Counter an offer (Scout) Negotiation moves in bounded, finite steps. A counter-offer answers with revised terms that still sit inside the session's [constraints](https://aura-labs.ai/invariants.html#constraints-as-bounds) and carries its own [expiry](https://aura-labs.ai/invariants.html#offer-expiry), so each round stays within the mandate and stays finite. **Authentication:** agentId + agentTimestamp + agentSignature (default). **Request body:** CounterOfferRequest. **Responses:** - `201`: NegotiatedOffer - `400`: BadRequest - `401`: Unauthorized - `403`: Forbidden - `409`: object - `429`: Error ### Transactions Commit, retrieve, and report on transactions. #### POST /v1/sessions/{session_id}/commit: Commit to an offer Commitment is the single irreversible step, so it is where every guarantee has to hold at once. A naive accept that just flips a flag invites the failures a market cannot survive: committing on a price that has [expired](https://aura-labs.ai/invariants.html#offer-expiry), exceeding the [authority the principal delegated](https://aura-labs.ai/invariants.html#constraints-as-bounds), or leaving half a transaction behind when something fails midway. Commit refuses all of them in one [atomic act](https://aura-labs.ai/invariants.html#atomic-commitment): it checks the offer is live and within the mandate, records consent and extends the [signed chain of custody](https://aura-labs.ai/invariants.html#recorded-intent-and-chain-of-custody), and either creates the transaction and rejects its siblings or changes nothing at all. Replaying an idempotency key returns the original result rather than committing twice. Then clearing begins, sizing the reserve to the rail ([rail-conditional reserve](https://aura-labs.ai/invariants.html#rail-conditional-reserve)) and refusing any failed [business rule](https://aura-labs.ai/invariants.html#business-rules-as-hard-gates). **Authentication:** agentId + agentTimestamp + agentSignature (default). **Signature profile:** core_offer_countersignature. **Request body:** CommitRequest. **Responses:** - `200`: Transaction - `400`: BadRequest - `401`: Unauthorized - `403`: Forbidden - `409`: object #### GET /v1/transactions/{transaction_id}: Retrieve a transaction A transaction is the durable record a dispute or an audit reads long after the session closes. This returns it: the committed terms, the counter-signatures, and the current fulfilment, payment, and clearing state. **Authentication:** agentId + agentTimestamp + agentSignature (default). **Responses:** - `200`: Transaction - `401`: Unauthorized - `403`: Forbidden - `404`: NotFound #### PUT /v1/transactions/{transaction_id}/fulfillment: Report fulfillment status A committed deal still has to be delivered. Fulfilment updates record delivery progress on the transaction, moving it toward completion or surfacing the gap a dispute would test. **Authentication:** agentId + agentTimestamp + agentSignature (default). **Request body:** FulfillmentUpdate. **Responses:** - `200`: object - `400`: BadRequest - `401`: Unauthorized - `403`: Forbidden #### PUT /v1/transactions/{transaction_id}/payment: Report payment status Money moving has to leave a proof, or settlement becomes a claim nobody can check. A payment update records settlement against a rail-signed proof correlated to the instruction ([verifiable settlement](https://aura-labs.ai/invariants.html#verifiable-settlement)). **Authentication:** agentId + agentTimestamp + agentSignature (default). **Request body:** PaymentUpdate. **Responses:** - `200`: object - `400`: BadRequest - `401`: Unauthorized - `403`: Forbidden #### GET /v1/transactions/{transaction_id}/clearing: Read the clearing record Clearing is where risk is priced and the reserve is held, and a market trusts it only if the pricing is neutral and legible. This exposes the clearing record: the [rail-conditional reserve](https://aura-labs.ai/invariants.html#rail-conditional-reserve), the [settlement proof](https://aura-labs.ai/invariants.html#verifiable-settlement), and a risk score that is a function of risk and rail alone ([financial neutrality of the clearinghouse](https://aura-labs.ai/invariants.html#financial-neutrality-of-the-clearinghouse)), shown only to the party it belongs to ([bilateral risk transparency](https://aura-labs.ai/invariants.html#bilateral-risk-transparency)). **Authentication:** agentId + agentTimestamp + agentSignature (default). **Responses:** - `200`: ClearingRecord - `401`: Unauthorized - `403`: Forbidden - `404`: NotFound ### Beacons Beacon (seller agent) registration and open-session discovery. #### POST /v1/beacons/register: Register or update a beacon A seller's agent has to be discoverable to be matched, but discoverability without accountability invites throwaway offers. Registering a Beacon publishes its categories and capabilities while binding it to a principal, so the market can match it and still hold it answerable. **Authentication:** agentId + agentTimestamp + agentSignature (default). **Request body:** BeaconRegistration. **Responses:** - `200`: Beacon - `400`: BadRequest - `401`: Unauthorized - `403`: Forbidden #### GET /v1/beacons/sessions: Poll open sessions to bid on A Beacon needs to know which sessions it has been matched into before it can make an offer. This lists the open sessions awaiting the Beacon's response. **Authentication:** agentId + agentTimestamp + agentSignature (default). **Parameters:** - `status` (query): - `limit` (query): **Responses:** - `200`: object - `401`: Unauthorized #### GET /v1/beacons/{beacon_id}: Get a beacon Matching and reputation operate on what a Beacon claims it can do. This returns a Beacon's public profile so a counterparty knows its declared capabilities. **Authentication:** agentId + agentTimestamp + agentSignature (default). **Responses:** - `200`: Beacon - `401`: Unauthorized - `404`: NotFound ### Business Rules Beacon-defined business rules (age, geo, KYC). #### GET /v1/business-rules: List a beacon's active rules A Beacon's hard eligibility rules decide who it will deal with at all, so they have to be inspectable. This lists the business rules a Beacon has in force. **Authentication:** agentId + agentTimestamp + agentSignature (default). **Parameters:** - `beacon_id` (query, required): **Responses:** - `200`: object - `401`: Unauthorized - `403`: Forbidden #### POST /v1/business-rules: Register a business rule (Beacon) Some conditions decide whether a deal is allowed at all, ahead of any pricing: an age minimum, a geographic restriction, a verification requirement. A business rule registers such a gate, and Core refuses any commit that fails it however attractive the price ([business rules as hard gates](https://aura-labs.ai/invariants.html#business-rules-as-hard-gates)). **Authentication:** agentId + agentTimestamp + agentSignature (default). **Parameters:** - `Idempotency-Key` (header): **Request body:** BusinessRuleCreate. **Responses:** - `200`: BusinessRule - `201`: BusinessRule - `400`: BadRequest - `401`: Unauthorized - `403`: Forbidden #### DELETE /v1/business-rules/{rule_id}: Revoke a business rule Eligibility rules change as a Beacon's obligations change. Revoking a rule retires the gate going forward while leaving the committed transactions it once governed untouched, so the record of why a past deal was allowed stays intact. **Authentication:** agentId + agentTimestamp + agentSignature (default). **Responses:** - `204`: Revoked (no content) - `401`: Unauthorized - `403`: Forbidden - `404`: NotFound ### Disputes Dispute filing, evidence, and resolution. #### POST /v1/transactions/{transaction_id}/disputes: File a dispute A market that calls every settled deal final has no recourse, and agents will not commit real money without it. Filing a dispute reopens a committed transaction within the window the market declared before commitment ([repudiability within a bounded window](https://aura-labs.ai/invariants.html#repudiability-within-a-bounded-window)), turning finality without recourse into accountable settlement. **Authentication:** agentId + agentTimestamp + agentSignature (default). **Request body:** DisputeFile. **Responses:** - `201`: Dispute - `400`: BadRequest - `401`: Unauthorized - `403`: Forbidden #### POST /v1/disputes/{dispute_id}/evidence: Submit dispute evidence A dispute is resolved on evidence, and the strongest evidence is already in the protocol: the signed offer, the commitment, the fulfilment record. This attaches a party's evidence to an open dispute, inside its [bounded window](https://aura-labs.ai/invariants.html#repudiability-within-a-bounded-window). **Authentication:** agentId + agentTimestamp + agentSignature (default). **Request body:** EvidenceSubmission. **Responses:** - `201`: object - `400`: BadRequest - `401`: Unauthorized - `403`: Forbidden #### POST /v1/disputes/{dispute_id}/resolve: Resolve or withdraw a dispute A reopened transaction has to reach a definite end, or repudiability becomes limbo. Resolution applies an outcome (upheld, rejected, partial, or withdrawn) to a dispute filed inside its [window](https://aura-labs.ai/invariants.html#repudiability-within-a-bounded-window) and closes it. **Authentication:** agentId + agentTimestamp + agentSignature (default). **Request body:** DisputeResolution. **Responses:** - `200`: Dispute - `400`: BadRequest - `401`: Unauthorized - `403`: Forbidden #### GET /v1/disputes/{dispute_id}: Retrieve a dispute A dispute's state and the evidence on both sides have to be visible to its participants to be trusted. This returns the dispute with its protocol evidence, for a transaction still inside its [repudiable window](https://aura-labs.ai/invariants.html#repudiability-within-a-bounded-window). **Authentication:** agentId + agentTimestamp + agentSignature (default). **Responses:** - `200`: Dispute - `401`: Unauthorized - `403`: Forbidden - `404`: NotFound ### Intent Chain Intent chain of custody, L1–L7. #### POST /v1/sessions/{session_id}/chain-links: Submit the L3 (principal review) chain link Who decided what, and in what order, is the whole of accountability when agents act for principals. A chain link adds one signed step to the intent's [chain of custody](https://aura-labs.ai/invariants.html#recorded-intent-and-chain-of-custody), each link bound to its predecessor so the record cannot be reordered or forged after the fact. **Authentication:** agentId + agentTimestamp + agentSignature (default). **Signature profile:** intent_chain_link. **Request body:** ChainLinkSubmission. **Responses:** - `201`: object - `400`: BadRequest - `401`: Unauthorized - `403`: Forbidden #### GET /v1/transactions/{transaction_id}/intent-chain: Retrieve the assembled intent chain After the fact, a dispute or an audit has to replay exactly how an intent became a commitment. This returns the assembled [chain of custody](https://aura-labs.ai/invariants.html#recorded-intent-and-chain-of-custody) for a transaction, every link signed by the party responsible for it. **Authentication:** agentId + agentTimestamp + agentSignature (default). **Signature profile:** assembled_intent_chain. **Responses:** - `200`: IntentChain - `401`: Unauthorized - `403`: Forbidden - `404`: NotFound ### Sandbox The certification bench: admission-chain operations served at the sandbox host only. Each operation declares its server; nothing here serves on the production host. #### POST /v1/sandbox/keys: Mint a sandbox key (domain-verified) The obtain_scope phase of the admission chain, executable today. An agent proves two things and receives the tenant anchor for one sandbox namespace. Possession: sign the exact JSON body with the declared Ed25519 key (X-Signature header). Domain control: publish the key where only the domain's controller can, either the TXT record _aura-agent-key. with value aura-key=, or the document https:///.well-known/aura-agent-key returning JSON with a matching public_key. Possession is verified first, locally; the domain lookup runs only for a proven key, and the well-known fetch goes to public HTTPS addresses only, pinned, without redirects. One active key per domain: re-minting revokes the prior key in the same transaction, which is also the compromise-recovery path. The grant appears once and is stored hashed. The key provisions its namespace now: provisionSandbox is live, and the grant says exactly what the key is and how to consume it. Every refusal names what Core looked for and what it found. **Authentication:** sandboxMintProof. **Request body:** SandboxKeyMintRequest. **Responses:** - `201`: SandboxKeyGrant - `400`: object - `401`: object - `403`: SandboxIdentityNotVerified - `409`: object - `429`: object - `500`: object - `503`: object #### POST /v1/sandbox/namespaces: Provision the namespace a sandbox key anchors Turns a minted sandbox key into a seeded, isolated market and binds the key to it. A namespace is rows in a standing deployment, never new infrastructure, so provisioning is a single call: the seeded principals at declared verification levels, the deterministic house counterparties, the declared market profile, and both simulated settlement rails arrive together, described by the returned manifest. Provisioning does not open a conformance run; every run opens with a reset. Idempotent by the key: re-provisioning with an already-bound key returns the existing manifest as success, never a conflict, so an agent retrying a timeout lands on the same state. **Authentication:** sandboxKey. **Request body:** ProvisionSandboxRequest. **Responses:** - `200`: SandboxManifest - `201`: SandboxManifest - `400`: object - `401`: object - `409`: object - `422`: object - `429`: object - `503`: object #### POST /v1/sandbox/namespaces/current/reset: Reset the namespace: open a new conformance run Destroy-and-reseed at namespace grain. Every conformance run opens with a reset and receives the run identity that transcripts, assertion results, and run quotas key on. The house counterparties reseed with the same derived keys (the declared sandbox semantic exception), so the manifest stays valid across resets. Not idempotent, by design: each success is a new run boundary and spends run quota; the retryable conflicts are safe to retry because the tenant is serialized on the key. A reset never runs under an in-flight flow: let open sessions reach a quiescent state or expire first. Evidence recorded outside the namespace survives reset. **Authentication:** sandboxKey. **Request body:** ResetSandboxRequest. **Responses:** - `200`: SandboxResetResult - `400`: object - `401`: object - `409`: object - `429`: object - `503`: object #### GET /v1/sandbox/namespaces/current/runs/{run_id}/transcript: Read the transcript of a conformance run Assemble the run's transcript from its recorded events: the raw events exactly as they happened, the normalized events derived through the retained first-occurrence substitution map (UUIDs and timestamps only), the map itself, and the hash-chain head over the raw events. A read with no side effects, available while the run is active and after a later reset supersedes it. The run must belong to the namespace the presented key anchors; an unknown, malformed, or foreign run_id is the same not-found answer, so run existence never leaks across namespaces. **Authentication:** sandboxKey. **Parameters:** - `run_id` (path, required): The run boundary: provision opens a run and returns its run_id; each reset opens a fresh one. **Responses:** - `200`: ConformanceTranscript - `401`: object - `404`: object - `503`: object ## Error catalogue Every error response carries a stable, machine-readable code in its `error` field. This catalogue is the closed set Core emits: each code maps to the HTTP status it accompanies, whether the same request is safe to retry, a category, a human-readable meaning, and where relevant the invariant it protects. Codes are stable identifiers; messages are explanatory. - **auth**: Authentication and key validity. - **authorization**: The caller is authenticated but not permitted to act on the resource. - **validation**: The request failed a contract or field-level check. - **not_found**: The addressed resource does not exist or is not visible to the caller. - **state**: The resource is in a state that does not allow the action. - **conflict**: The action conflicts with existing state (idempotency, duplicates). - **rate_limit**: The caller has exceeded a rate limit. - **operational**: A transient server or dependency error; the same request is safe to retry. | Code | HTTP | Retryable | Category | Meaning | | --- | --- | --- | --- | --- | | `authentication_required` | 401 | no | auth | The request carried no valid agent authentication. Provide agentId, agentTimestamp, and agentSignature. (protects [Persistent identity and qualification](https://aura-labs.ai/invariants.html#persistent-identity-and-qualification)) | | `beacon_no_signing_key` | 400 | no | auth | The Beacon has no registered signing key to verify against. | | `invalid_offer_signature` | 400 | no | auth | The offer signature did not verify against the Beacon's registered key. (protects [Recorded intent and chain of custody](https://aura-labs.ai/invariants.html#recorded-intent-and-chain-of-custody)) | | `invalid_signature` | 401 | no | auth | The agent signature did not verify against the registered key. (protects [Persistent identity and qualification](https://aura-labs.ai/invariants.html#persistent-identity-and-qualification)) | | `key_revoked` | 403 | no | auth | The presented key has been revoked. (protects [Persistent identity and qualification](https://aura-labs.ai/invariants.html#persistent-identity-and-qualification)) | | `missing_offer_signature` | 400 | no | auth | The offer was submitted without its required signature. (protects [Recorded intent and chain of custody](https://aura-labs.ai/invariants.html#recorded-intent-and-chain-of-custody)) | | `missing_signature` | 401 | no | auth | A required authentication signature header was absent. | | `cross_beacon_access_denied` | 403 | no | authorization | A Beacon may only access its own sessions and offers. (protects [Identity abstraction until commitment](https://aura-labs.ai/invariants.html#identity-abstraction-until-commitment)) | | `cross_scout_access_denied` | 403 | no | authorization | A Scout may only access its own sessions. (protects [Identity abstraction until commitment](https://aura-labs.ai/invariants.html#identity-abstraction-until-commitment)) | | `forbidden` | 403 | no | authorization | The authenticated agent may not act on this resource. | | `not_filing_agent` | 403 | no | authorization | Only the agent that filed the dispute may take this action. | | `scout_cannot_register_rules` | 403 | no | authorization | Scouts may not register business rules. (protects [Business rules as hard gates](https://aura-labs.ai/invariants.html#business-rules-as-hard-gates)) | | `system_role_required` | 403 | no | authorization | This operation requires the system role. | | `dispute_already_exists` | 409 | no | conflict | A dispute already exists for this transaction. | | `duplicate_transaction` | 409 | no | conflict | A transaction already exists for this commitment; the commit is idempotent. (protects [Atomic commitment](https://aura-labs.ai/invariants.html#atomic-commitment)) | | `adapter_not_found` | 404 | no | not_found | The requested resource was not found. | | `beacon_not_found` | 404 | no | not_found | The requested resource was not found. | | `clearing_not_found` | 404 | no | not_found | The requested resource was not found. | | `not_found` | 404 | no | not_found | The requested resource was not found. | | `offer_not_found` | 404 | no | not_found | The requested resource was not found. | | `principal_not_found` | 404 | no | not_found | The requested resource was not found. | | `profile_not_found` | 404 | no | not_found | The requested resource was not found. | | `rule_not_found` | 404 | no | not_found | The requested resource was not found. | | `session_not_found` | 404 | no | not_found | The requested resource was not found. | | `transaction_not_found` | 404 | no | not_found | The requested resource was not found. | | `cancel_failed` | 500 | yes | operational | The operation could not be completed due to a server error. Safe to retry. | | `chain_fetch_failed` | 503 | yes | operational | A backend dependency was temporarily unavailable. Retry with backoff. | | `commit_failed` | 500 | yes | operational | The operation could not be completed due to a server error. Safe to retry. | | `database_unavailable` | 503 | yes | operational | A backend dependency was temporarily unavailable. Retry with backoff. | | `dispute_filing_failed` | 500 | yes | operational | The operation could not be completed due to a server error. Safe to retry. | | `evidence_submission_failed` | 500 | yes | operational | The operation could not be completed due to a server error. Safe to retry. | | `fetch_failed` | 503 | yes | operational | A backend dependency was temporarily unavailable. Retry with backoff. | | `offer_submission_failed` | 500 | yes | operational | The operation could not be completed due to a server error. Safe to retry. | | `profile_unavailable` | 503 | yes | operational | A backend dependency was temporarily unavailable. Retry with backoff. | | `registration_failed` | 500 | yes | operational | The operation could not be completed due to a server error. Safe to retry. | | `resolution_failed` | 500 | yes | operational | The operation could not be completed due to a server error. Safe to retry. | | `revocation_failed` | 500 | yes | operational | The operation could not be completed due to a server error. Safe to retry. | | `scope_creation_failed` | 500 | yes | operational | The operation could not be completed due to a server error. Safe to retry. | | `session_creation_failed` | 500 | yes | operational | The operation could not be completed due to a server error. Safe to retry. | | `update_failed` | 500 | yes | operational | The operation could not be completed due to a server error. Safe to retry. | | `rate_limit_exceeded` | 429 | yes | rate_limit | Too many requests. Retry after the indicated delay. | | `beacon_cannot_counter` | 409 | no | state | The Beacon cannot submit a counter-offer here. | | `beacon_inactive` | 403 | no | state | The Beacon is not active. | | `cannot_cancel` | 409 | no | state | The session cannot be cancelled in its current state. | | `cannot_withdraw` | 409 | no | state | The offer cannot be withdrawn in its current state. | | `consent_elevation_required` | 403 | no | state | The action requires a higher consent tier than the delegation grants. (protects [Least-privilege delegated authority](https://aura-labs.ai/invariants.html#least-privilege-delegated-authority)) | | `dispute_not_open` | 409 | no | state | The dispute is not open. | | `dispute_window_expired` | 409 | no | state | The dispute window has closed. (protects [Repudiability within a bounded window](https://aura-labs.ai/invariants.html#repudiability-within-a-bounded-window)) | | `evidence_deadline_passed` | 409 | no | state | The evidence submission deadline has passed. (protects [Repudiability within a bounded window](https://aura-labs.ai/invariants.html#repudiability-within-a-bounded-window)) | | `negotiation_exhausted` | 409 | no | state | The negotiation has reached its round limit. | | `not_disputable` | 409 | no | state | The transaction is not in a disputable state. (protects [Repudiability within a bounded window](https://aura-labs.ai/invariants.html#repudiability-within-a-bounded-window)) | | `offer_not_counterable` | 409 | no | state | The offer cannot be countered in its current state. | | `principal_inactive` | 403 | no | state | The principal is not active. | | `session_expired` | 409 | no | state | The session has expired and no longer accepts actions. | | `session_not_accepting_offers` | 409 | no | state | The session is not accepting offers in its current state. | | `session_not_committable` | 409 | no | state | The session is not in a committable state. (protects [Atomic commitment](https://aura-labs.ai/invariants.html#atomic-commitment)) | | `session_not_negotiable` | 409 | no | state | The session is not in a negotiable state. | | `transaction_frozen` | 409 | no | state | Fulfilment and payment updates are frozen while the transaction is disputed. (protects [Repudiability within a bounded window](https://aura-labs.ai/invariants.html#repudiability-within-a-bounded-window)) | | `chain_link_failed` | 400 | no | validation | The intent-chain link could not be appended. (protects [Recorded intent and chain of custody](https://aura-labs.ai/invariants.html#recorded-intent-and-chain-of-custody)) | | `chain_validation_failed` | 400 | no | validation | The submitted intent-chain link did not validate. (protects [Recorded intent and chain of custody](https://aura-labs.ai/invariants.html#recorded-intent-and-chain-of-custody)) | | `default_profile_missing` | 400 | no | validation | The request was rejected by a contract or business-rule check. | | `invalid_adapter_id` | 400 | no | validation | A request field was missing or failed validation. | | `invalid_beacon_id` | 400 | no | validation | A request field was missing or failed validation. | | `invalid_capacity` | 400 | no | validation | A request field was missing or failed validation. | | `invalid_clearinghouse_terms` | 400 | no | validation | A request field was missing or failed validation. | | `invalid_consent_requirements` | 400 | no | validation | A request field was missing or failed validation. | | `invalid_constraints` | 400 | no | validation | A request field was missing or failed validation. | | `invalid_endpoint_url` | 400 | no | validation | A request field was missing or failed validation. | | `invalid_field` | 400 | no | validation | A request field was missing or failed validation. | | `invalid_fulfillment_terms` | 400 | no | validation | A request field was missing or failed validation. | | `invalid_idempotency_key` | 400 | no | validation | The Idempotency-Key header was malformed. | | `invalid_key` | 400 | no | validation | A request field was missing or failed validation. | | `invalid_offer_id` | 400 | no | validation | A request field was missing or failed validation. | | `invalid_parameter` | 400 | no | validation | A request field was missing or failed validation. | | `invalid_price` | 400 | no | validation | A request field was missing or failed validation. | | `invalid_profile_id` | 400 | no | validation | A request field was missing or failed validation. | | `invalid_quantity` | 400 | no | validation | A request field was missing or failed validation. | | `invalid_risk_tolerance` | 400 | no | validation | A request field was missing or failed validation. | | `invalid_rule_id` | 400 | no | validation | A request field was missing or failed validation. | | `invalid_settlement_preference` | 400 | no | validation | A request field was missing or failed validation. | | `invalid_status` | 400 | no | validation | A request field was missing or failed validation. | | `missing_beacon_id` | 400 | no | validation | A request field was missing or failed validation. | | `missing_description` | 400 | no | validation | A request field was missing or failed validation. | | `missing_fields` | 400 | no | validation | A request field was missing or failed validation. | | `missing_payment_terms_hash` | 400 | no | validation | A request field was missing or failed validation. | | `missing_to_status` | 400 | no | validation | A request field was missing or failed validation. | | `no_chain` | 400 | no | validation | The request was rejected by a contract or business-rule check. | | `no_changes` | 400 | no | validation | The request was rejected by a contract or business-rule check. | | `no_scope` | 400 | no | validation | The request was rejected by a contract or business-rule check. | | `payload_too_large` | 413 | no | validation | The request body exceeded the size limit. | | `payment_terms_hash_mismatch` | 400 | no | validation | The payment terms hash did not match the signed offer. (protects [Recorded intent and chain of custody](https://aura-labs.ai/invariants.html#recorded-intent-and-chain-of-custody)) | | `unknown_profile` | 400 | no | validation | The request was rejected by a contract or business-rule check. | | `invalid_key_proof` | 422 | no | validation | new_key_proof does not verify over the canonical rotation payload against the submitted new key. (protects [Persistent identity and qualification](https://aura-labs.ai/invariants.html#persistent-identity-and-qualification)) | | `invalid_rotation_authorization` | 403 | no | authorization | The rotation was not authorized by the required key: the current key for rotation, the principal's key for agent recovery. (protects [Persistent identity and qualification](https://aura-labs.ai/invariants.html#persistent-identity-and-qualification)) | | `key_already_used` | 409 | no | conflict | The submitted key is already registered to an identity or exists in key history. A key is never reusable. | | `rotation_replayed` | 409 | no | conflict | The rotation timestamp is outside the freshness window, or the rotation tuple was already used. | | `key_rotation_conflict` | 409 | no | conflict | The identity's current key no longer matches the key the rotation payload was constructed against. Rebuild the payload against the current key. | | `recovery_not_available` | 403 | no | state | Principal key recovery requires re-verification against external credentials, which is not yet available. | | `rotation_failed` | 500 | yes | operational | The key rotation could not be completed due to a server error. Safe to retry. | | `invalid_offer_expiry` | 400 | no | validation | The declared expires_at falls outside the session profile's offer validity window. (protects [Offer expiry](https://aura-labs.ai/invariants.html#offer-expiry)) | | `offer_expired` | 409 | no | state | The offer's expiry has passed. Commits and counters on it are refused. (protects [Offer expiry](https://aura-labs.ai/invariants.html#offer-expiry)) | | `missing_auth_headers` | 401 | no | auth | The request carried none or only some of the required authentication headers. Provide agentId, agentTimestamp, agentNonce, and agentSignature. (protects [Persistent identity and qualification](https://aura-labs.ai/invariants.html#persistent-identity-and-qualification)) | | `invalid_nonce` | 401 | no | auth | The X-Agent-Nonce header is missing, malformed, or outside the required shape (16-128 characters of [A-Za-z0-9._~-]). (protects [Persistent identity and qualification](https://aura-labs.ai/invariants.html#persistent-identity-and-qualification)) | | `replayed_request` | 401 | no | auth | The request nonce has already been used. Each authenticated request must carry a fresh nonce, so a captured signed request cannot be replayed within the freshness window. (protects [Persistent identity and qualification](https://aura-labs.ai/invariants.html#persistent-identity-and-qualification)) | | `invalid_host` | 401 | no | auth | The X-Agent-Host header is malformed (not a valid host or host:port). (protects [Persistent identity and qualification](https://aura-labs.ai/invariants.html#persistent-identity-and-qualification)) | | `host_mismatch` | 401 | no | auth | The signed X-Agent-Host does not match this Core. A request signed for one Core cannot be presented to another. (protects [Persistent identity and qualification](https://aura-labs.ai/invariants.html#persistent-identity-and-qualification)) | | `unknown_agent` | 401 | no | auth | The presented agent id resolves to no registered agent. (protects [Persistent identity and qualification](https://aura-labs.ai/invariants.html#persistent-identity-and-qualification)) | | `agent_revoked` | 403 | no | auth | The presented agent identity has been revoked. (protects [Persistent identity and qualification](https://aura-labs.ai/invariants.html#persistent-identity-and-qualification)) | | `agent_suspended` | 403 | no | auth | The presented agent identity is suspended. (protects [Persistent identity and qualification](https://aura-labs.ai/invariants.html#persistent-identity-and-qualification)) | | `namespace_mismatch` | 403 | no | authorization | The write crosses sandbox namespaces: the entities it binds (a beacon and a session, or an agent and its principal) belong to different namespaces. Sandbox isolation refuses cross-tenant writes. | | `invalid_domain` | 400 | no | validation | The declared domain is not a provable identity anchor: it must be a bare public multi-label DNS hostname, never a wildcard, IP address, scheme, port, or path. | | `mint_proof_invalid` | 401 | no | auth | The X-Signature proof-of-possession does not verify: sign the exact JSON request body with the declared key (JSON.stringify, UTF-8 bytes, Ed25519, base64). | | `sandbox_identity_not_verified` | 403 | yes | auth | Domain control was not proven. The response names the record or document Core looked for and what it found; publish it, allow propagation, and retry. | | `mint_failed` | 500 | yes | operational | The mint could not be completed due to a server error. Safe to retry. | | `sandbox_key_invalid` | 401 | no | auth | The X-AURA-Sandbox-Key is absent, unknown, or revoked. Mint a key at the sandbox keys operation; after a re-mint under the re-proven domain, only the newest grant is live. | | `sandbox_quota_exceeded` | 429 | yes | rate_limit | A sandbox quota for the verified identity is exhausted. The body names the quota and the tier; wait out the window or climb a verification rung. | | `sandbox_namespace_conflict` | 409 | yes | conflict | A concurrent provision or reset holds this key's namespace. Retry: a repeated provision is idempotent and lands on the existing namespace. | | `sandbox_contract_version_skew` | 422 | no | validation | The requested scenario version is not the version this bench serves. The response names the served version; provision against it. | | `sandbox_provisioning_unavailable` | 503 | yes | operational | Provisioning could not complete and rolled back; nothing was created. Safe to retry. | | `sandbox_run_active` | 409 | yes | conflict | A flow is in flight in this namespace, or a concurrent reset opened a run first. Let open flows reach a quiescent state or expire, then reset again. | | `sandbox_run_not_found` | 404 | no | not_found | No such run in this namespace. Provision opens a run and returns its run_id; each reset opens a fresh one. | ## Data shapes The request and response objects referenced above. ### Error | Field | Type | Required | Description | | --- | --- | --- | --- | | error | string | yes | Machine-readable error code | | message | string | no | Human-readable explanation | ### Link | Field | Type | Required | Description | | --- | --- | --- | --- | | href | string | no | | | method | string | no | | ### Links HATEOAS affordances keyed by relation. ### PriceRange Reusable price range component. | Field | Type | Required | Description | | --- | --- | --- | --- | | min | number | yes | | | max | number | yes | | | currency | string | no | ISO 4217 | ### Profile Market profile governing dispute windows and settlement defaults. | Field | Type | Required | Description | | --- | --- | --- | --- | | profile_id | string | no | | | profile_version | string | no | Version of this profile; pinned onto a session at creation as profile_version_at_creation. | | display_name | string | no | Human-readable profile label. | | description | string | no | Free-text summary of the market this profile governs. | | market_context | string | no | The vertical or market context the profile applies to. | | status | string | no | Profile lifecycle status; only active profiles are resolvable. | | dispute_window_days_minimum | integer | no | | | dispute_window_days_default | integer | no | | | participation | object | no | Participation dimension: who may enter this market and under what conditions. | | disclosure | object | no | Disclosure dimension: what parties must reveal to each other. | | commitment | object | no | Commitment dimension: binding rules governing offers and commits. | | risk | object | no | Risk dimension: risk-tiering and reserve parameters for this market. | | schema | object | no | Schema overlays extending the base offer/intent shape for this market. | | governance | object | no | Governance dimension: who may amend the profile and how. | | metadata | object | no | Free-form profile metadata. | | authentication_required | boolean | no | Run-mode posture: when this profile is a Core's operating profile, whether every request to a guarded route must carry a valid signature. A live market is true; the front door reads this instance-wide, before a request's market is known. | | rate_limit_pre_auth_key | string [ip \| agent_header] | no | Run-mode posture: the pre-authentication rate-limit bucket dimension when this profile is a Core's operating profile. 'ip' does not trust an unverified X-Agent-Id header for the bucket; 'agent_header' does. | | rate_limit_post_auth_budget | boolean | no | Run-mode posture: whether a post-verification per-tenant rate budget runs when this profile is a Core's operating profile. | | _links | Links | no | | ### ProfileValidationRequest Terms to pre-flight against a market profile's minimums. | Field | Type | Required | Description | | --- | --- | --- | --- | | dispute_window_days | integer | yes | | | settlement_method | string | no | | ### SettlementRail Settlement-rail adapter and its capabilities. | Field | Type | Required | Description | | --- | --- | --- | --- | | adapter_id | string | no | | | native_repudiation | boolean | no | Whether the rail provides native chargeback/repudiation. | | capabilities | object | no | | | _links | Links | no | | ### PrincipalRegistration | Field | Type | Required | Description | | --- | --- | --- | --- | | principal_type | string [organization \| individual] | yes | | | legal_name | string | yes | | | jurisdiction | string | yes | ISO 3166 country code | | public_key | string | yes | Base64 Ed25519 public key | | operating_name | string | no | | | identifiers | object | no | | | contact | object | no | | ### Principal | Field | Type | Required | Description | | --- | --- | --- | --- | | principal_id | string (uuid) | no | | | principal_type | string [organization \| individual] | no | | | verification_level | string | no | | | verification_status | string | no | | | registered_at | string (date-time) | no | | | _links | Links | no | | ### AgentRegistration | Field | Type | Required | Description | | --- | --- | --- | --- | | public_key | string | yes | Base64 Ed25519 public key | | type | string [scout \| beacon] | yes | | | principal_id | string (uuid) | yes | | | capacity | string | no | | | manifest | object | no | | ### Agent | Field | Type | Required | Description | | --- | --- | --- | --- | | agent_id | string (uuid) | no | | | status | string | no | | | key_id | string | no | | | manifest | object | no | The agent's self-declared capability manifest submitted at registration. | | principal_id | string (uuid) | no | | | capacity | string | no | | | principal_verification_level | string,null | no | Verification level of the bound principal, resolved at read time; null when the agent has no principal. | | registered_at | string (date-time) | no | | | last_seen_at | string,null (date-time) | no | Timestamp of the agent's most recent authenticated request; null until first seen. | | _links | Links | no | | ### PrincipalUpdate Mutable principal fields. Immutable fields (legal_name, jurisdiction, principal_type, public_key, verification_level) are rejected with 400. | Field | Type | Required | Description | | --- | --- | --- | --- | | operating_name | string | no | | | contact | object | no | | | identifiers | object | no | | ### DelegationConstraints Bounds on what the agent may transact under this scope. | Field | Type | Required | Description | | --- | --- | --- | --- | | max_transaction_amount | number | no | | | currency | string | no | ISO 4217 | | valid_from | string (date-time) | no | | | valid_until | string (date-time) | no | | | allowed_categories | array of string | no | | | blocked_categories | array of string | no | | | merchant_blocklist | array of string | no | | | require_principal_approval_above | number | no | | ### DelegationScopeRequest | Field | Type | Required | Description | | --- | --- | --- | --- | | consent_tier | string [explicit \| policy \| delegated] | yes | | | constraints | DelegationConstraints | yes | | | policy_definition | object | no | | | signed_by_principal | boolean | no | | | principal_signature | string | no | | ### DelegationScope | Field | Type | Required | Description | | --- | --- | --- | --- | | scope_id | string | no | | | agent_id | string (uuid) | no | | | consent_tier | string [explicit \| policy \| delegated] | no | | | constraints | DelegationConstraints | no | | | policy_definition | object,null | no | | | signed_by_principal | boolean | no | | | status | string | no | | | created_at | string (date-time) | no | | | updated_at | string (date-time) | no | | ### BeaconRegistration | Field | Type | Required | Description | | --- | --- | --- | --- | | external_id | string | yes | Stable external identifier; the upsert key. | | name | string | yes | | | description | string | no | | | endpoint_url | string (uri) | no | HTTPS, public hostname; SSRF-validated: raw IP literals and private hostnames are rejected, and the hostname must not resolve to a private, link-local, loopback, or reserved address. Resolution is checked at registration and enforced again at delivery, where the connection is pinned to the checked DNS answer; redirects are not followed. | | capabilities | object | no | | | metadata | object | no | | ### Beacon | Field | Type | Required | Description | | --- | --- | --- | --- | | beacon_id | string (uuid) | no | | | external_id | string | no | | | name | string | no | | | status | string | no | | | capabilities | object | no | | | _links | Links | no | | ### SessionSummary Open session as seen by a beacon. Buyer constraints are redacted to categories only. | Field | Type | Required | Description | | --- | --- | --- | --- | | session_id | string (uuid) | no | | | status | string | no | | | intent | object | no | | | constraints | object | no | Redacted to categories only. | ### SessionCreate | Field | Type | Required | Description | | --- | --- | --- | --- | | intent | string | yes | Natural-language buying intent. | | constraints | object | no | Structured constraints (max 10KB). | | completeness | object | no | | | chain_links | object | no | Optional L1 intent-chain link. | | profile_id | string | no | | | settlement_preference | object | no | | | risk_tolerance | object | no | | ### Session | Field | Type | Required | Description | | --- | --- | --- | --- | | session_id | string (uuid) | no | | | status | string | no | | | intent | object,null | no | Parsed intent. | | raw_intent | string,null | no | The original unparsed intent string as submitted, returned on session retrieval. | | profile_id | string | no | | | profile_version_at_creation | string | no | | | created_at | string (date-time) | no | Timestamp the session was created. | | matched_beacons | array of object | no | | | _links | Links | no | | ### Product Product descriptor (free-form JSONB). 'name' is the canonical label; 'sku' optional. Additional vendor fields are permitted. | Field | Type | Required | Description | | --- | --- | --- | --- | | name | string | no | | | sku | string | no | | ### OfferSubmission | Field | Type | Required | Description | | --- | --- | --- | --- | | beacon_id | string | yes | | | product | Product \| string | yes | Product descriptor object, or a bare string treated as { name }. | | unit_price | number | no | | | quantity | integer | no | | | total_price | number | no | | | currency | string | no | | | delivery_date | string (date) | no | | | expires_at | string (date-time) | no | Optional declared expiry for the offer (ISO 8601). Must fall inside the session profile's offer validity window (the offer_validity_window bounded parameter of the offer-expiry invariant): at least 30 seconds and at most 24 hours from Core receipt unless the profile narrows or widens those bounds. Omitted, the profile default applies (one hour unless the profile says otherwise). The declared expiry rides in the authenticated submission and is recorded and enforced by Core; the canonical offer signing payload is unchanged. | | terms | object | no | | | signature | string | yes | Beacon Ed25519 signature over the canonical offer. | | payment_terms | PaymentTerms | no | | | payment_terms_hash | string | no | Base64 SHA-256 over canonical payment_terms (v2.4 attested path). | | acting_for_principal_id | string (uuid) | no | | | consent_requirements | object | no | | ### PaymentTerms Offer payment terms (v2.4). | Field | Type | Required | Description | | --- | --- | --- | --- | | dispute_window_days | integer | no | | | return_policy_days | integer | no | | | payment_timing | string | no | | | accepted_methods | array of string | no | | ### Offer | Field | Type | Required | Description | | --- | --- | --- | --- | | offer_id | string (uuid) | no | | | session_id | string (uuid) | no | | | beacon_id | string | no | | | beacon_name | string | no | Display name of the beacon that submitted this offer, joined at read time. | | status | string | no | | | product | Product | no | | | unit_price | number | no | Per-unit price of the offered product. | | quantity | integer | no | Number of units offered. | | total_price | number | no | Total price for the offered quantity. | | currency | string | no | ISO 4217 currency of the offer prices. | | delivery_date | string (date) | no | Committed delivery date for the offered goods. | | terms | object | no | Free-form commercial terms attached to the offer. | | metadata | object | no | Free-form offer metadata. | | consent_requirements | object | no | Principal-consent requirements the offer attaches to the commit, when present. | | payment_terms | PaymentTerms | no | | | payment_terms_hash | string | no | | | created_at | string (date-time) | no | Timestamp the offer was submitted. | | expires_at | string (date-time) | no | When the offer stops being committable and counterable. Every offer carries one: declared by the Beacon within the profile validity window, or resolved to the profile default. A commit or counter on an expired offer is refused with offer_expired. | | signatures | object | no | | | _links | Links | no | | ### CommitRequest | Field | Type | Required | Description | | --- | --- | --- | --- | | offer_id | string (uuid) | yes | | | idempotency_key | string (uuid) | yes | UUID v4 for idempotent commit. | | authority | object | no | | | chain_links | object | no | L4/L5 intent-chain links. | | settlement_method | string | no | | ### Transaction | Field | Type | Required | Description | | --- | --- | --- | --- | | transaction_id | string (uuid) | no | | | session_id | string (uuid) | no | | | offer_id | string (uuid) | no | | | beacon_id | string | no | | | beacon_name | string | no | Display name of the beacon party to the transaction. | | agent_id | string (uuid) | no | Identity of the scout agent that owns the originating session. | | status | string | no | | | final_terms | object | no | | | scout_principal | object,null | no | The scout side's principal reference, resolved at commit time; null when unbound. | | beacon_principal | object,null | no | The beacon side's principal reference, resolved at commit time; null when unbound. | | fulfillment_status | string | no | Current fulfillment state reported by the beacon. | | fulfillment_reference | string | no | Beacon-supplied reference for the fulfillment (e.g. tracking or order id). | | payment_status | string | no | Current payment state of the transaction. | | payment_reference | string | no | Reference for the payment (e.g. settlement or rail transaction id). | | created_at | string (date-time) | no | Timestamp the transaction was committed. | | updated_at | string (date-time) | no | Timestamp of the transaction's most recent state change. | | completed_at | string,null (date-time) | no | Timestamp the transaction reached a terminal completed state; null until then. | | clearinghouse | object | no | Present when the rail is AURA-cleared. | | _links | Links | no | | ### Attestation Core's signed interpretation attestation: a binding between the raw intent and its structured interpretation. | Field | Type | Required | Description | | --- | --- | --- | --- | | type | string | no | | | session_id | string (uuid) | no | | | attestation_signature | string | no | Base64 Ed25519 over the canonical attestation. | | core_key_id | string | no | | ### CounterOfferRequest | Field | Type | Required | Description | | --- | --- | --- | --- | | payment_terms | PaymentTerms | yes | | | unit_price | number | no | | | quantity | integer | no | | | product | Product \| string | no | Product descriptor object, or a bare string treated as { name }. Inherits the parent offer's product when omitted. | | total_price | number | no | | | currency | string | no | | ### NegotiatedOffer An offer created by countering a parent offer. | Field | Type | Required | Description | | --- | --- | --- | --- | | offer_id | string (uuid) | no | | | session_id | string (uuid) | no | | | beacon_id | string | no | | | parent_offer_id | string (uuid) | no | | | negotiation_status | string | no | | | depth | integer | no | | | payment_terms | PaymentTerms | no | | | payment_terms_hash | string | no | | | _links | Links | no | | ### FulfillmentUpdate | Field | Type | Required | Description | | --- | --- | --- | --- | | fulfillment_status | string [pending \| processing \| shipped \| delivered \| failed] | yes | | | fulfillment_reference | string | no | | ### PaymentUpdate | Field | Type | Required | Description | | --- | --- | --- | --- | | payment_status | string [pending \| authorized \| charged \| refunded \| failed] | yes | | | payment_reference | string | no | | | amount | number | no | | | currency | string | no | | ### ClearingRecord Clearing lifecycle record. Risk scores are filtered to the requesting party. | Field | Type | Required | Description | | --- | --- | --- | --- | | clearing_id | string (uuid) | no | | | transaction_id | string (uuid) | no | | | clearing_status | string | no | | | reserve_status | string | no | State of the settlement reserve (e.g. rail_managed, held, released). | | risk_tier | string | no | Overall risk tier assigned to the transaction. | | risk_score | number,null | no | Aggregate transaction risk score. | | scout_risk_score | number,null | no | Per-party risk score for the scout side. Returned only to the scout party; null to the counterparty. | | beacon_risk_score | number,null | no | Per-party risk score for the beacon side. Returned only to the beacon party; null to the counterparty. | | payment_method | string | no | Settlement rail / payment method used to clear the transaction. | | reserve_margin_pct | number,null | no | Reserve margin held, as a percentage of the settlement amount (wire key for the risk_margin_pct column). | | reserve_margin_amount | number,null | no | Reserve margin held, as an absolute amount (wire key for the risk_margin_amount column). | | net_settlement_amount | number,null | no | Amount to be settled net of any reserve margin. | | currency | string | no | ISO 4217 currency of the settlement amounts. | | dispute_term_days | integer | no | Length of the dispute window in days for this clearing record. | | dispute_term_expires_at | string,null (date-time) | no | Timestamp the dispute window closes. | | authorized_at | string,null (date-time) | no | Timestamp the reserve/settlement was authorized. | | settled_at | string,null (date-time) | no | Timestamp the transaction settled. | | cleared_at | string,null (date-time) | no | Timestamp the reserve released and the record cleared. | | created_at | string (date-time) | no | Timestamp the clearing record was created. | | updated_at | string (date-time) | no | Timestamp of the clearing record's most recent state change. | | _links | Links | no | | ### BusinessRuleCreate | Field | Type | Required | Description | | --- | --- | --- | --- | | rule_type | string [age_minimum \| geo_restriction \| kyc_required \| custom] | yes | | | payload | object | no | Rule-type-specific (age_minimum: { min_age }; geo_restriction: { allow: [ISO-3166] }; kyc_required: { level }). | ### BusinessRule | Field | Type | Required | Description | | --- | --- | --- | --- | | id | string (uuid) | no | | | beacon_id | string (uuid) | no | | | rule_type | string | no | | | payload | object | no | | | created_at | string (date-time) | no | | | revoked_at | string,null (date-time) | no | | ### DisputeFile | Field | Type | Required | Description | | --- | --- | --- | --- | | reason | string [product_not_as_described \| product_not_received \| product_damaged \| wrong_quantity \| unauthorized_transaction \| exceeded_delegation_scope \| payment_not_received \| payment_amount_incorrect \| duplicate_charge \| offer_terms_changed \| other] | yes | | | category | string [fulfillment \| payment \| product_quality \| authorization \| other] | yes | | | description | string | yes | | | evidence | array of EvidenceSubmission | no | | | requested_resolution | object | no | | ### Dispute | Field | Type | Required | Description | | --- | --- | --- | --- | | dispute_id | string (uuid) | no | | | transaction_id | string (uuid) | no | | | status | string | no | | | filed_by | string (uuid) | no | | | filed_at | string (date-time) | no | | | reason | string | no | | | category | string | no | | | evidence_deadline | string (date-time) | no | | | resolution_deadline | string (date-time) | no | | | outcome | string | no | | | resolution | object,null | no | | | _links | Links | no | | ### EvidenceSubmission Composed of: object & object & object & object. | Field | Type | Required | Description | | --- | --- | --- | --- | | type | string [text \| document_reference \| external_record \| protocol_record] | yes | | | description | string | no | Required for type=text. | | document_url | string (uri) | no | Required (with content_hash) for type=document_reference. | | content_hash | string | no | | | external_system | string | no | Required (with external_reference) for type=external_record. | | external_reference | string | no | Required (with external_system) for type=external_record. | | protocol_record_type | string | no | Required (with protocol_record_id) for type=protocol_record. | | protocol_record_id | string | no | Required (with protocol_record_type) for type=protocol_record. | ### DisputeResolution Composed of: object & object. | Field | Type | Required | Description | | --- | --- | --- | --- | | outcome | string [upheld \| rejected \| partial \| withdrawn] | yes | | | resolution | object | no | | | evidence_considered | array of string | no | Required unless outcome=withdrawn. | ### ChainLinkSubmission | Field | Type | Required | Description | | --- | --- | --- | --- | | link | string | yes | | | payload | object | yes | | | signature | string | yes | Ed25519 over the canonical link. | ### ConformanceTranscript The evidence unit of a conformance run (roadmap). Two layers: raw events carry what actually happened, with real ids, timestamps, and signatures, and everything cryptographic binds to them; normalized events are the comparison artifact derived through the retained first-occurrence substitution map. Nothing signs a normalized transcript. | Field | Type | Required | Description | | --- | --- | --- | --- | | run_id | string (uuid) | yes | The run boundary: issued by the reset that opens the run; transcripts, assertion results, and quota accounting key on it. | | namespace_id | string (uuid) | yes | The namespace the run executed in. | | scenario_version | string | yes | The scenario family and version the run bound to, as /. The certification attestation names it. | | raw_events | array of object | yes | Ordered typed events exactly as they happened. The hash chain and any evidence signature bind here; a verifier checks signatures against raw material, always. | | normalized_events | array of object | yes | The raw events with UUIDs and timestamps replaced through the substitution map. Determinism assertions compare these. | | normalization_map | object | yes | The first-occurrence substitution map from stable placeholders to the raw values they replaced, retained so either layer reconstructs from the other. | | transcript_hash | string | yes | Hash-chain head over the raw events, the integrity anchor of the run, in the self-describing 'sha256:' form the intent chain already uses. The chain seeds on the run_id and folds each raw event in seq order: every step hashes the previous hex digest concatenated with the event's canonical serialization (object keys sorted recursively, array order preserved). A verifier recomputes the head from run_id and raw_events alone; the normalized layer is never hashed. | ### IntentChain Assembled intent chain of custody (L1–L7). Beacons receive a redacted view (L2, L4, L6, L7). | Field | Type | Required | Description | | --- | --- | --- | --- | | transaction_id | string (uuid) | no | | | session_id | string (uuid) | no | | | chain_status | string | no | | | links | array of object | no | | | chain_hash | string,null | no | | | chain_signature | string,null | no | | ### KeyReplacementRequest Principal-authorized replacement of an agent key whose private half can no longer be trusted to sign (compromise recovery). The canonical payload is the same as rotation, with entity_type 'agent' and the agent's current key as old_public_key. The compromised key signs nothing. | Field | Type | Required | Description | | --- | --- | --- | --- | | new_public_key | string | yes | Raw 32-byte Ed25519 public key, base64. | | rotation_timestamp | string (date-time) | yes | ISO 8601, submitted explicitly so the client and Core construct the same canonical payload. Must fall within 300 seconds of Core receipt, either side. | | new_key_proof | string | yes | Base64 Ed25519 signature over the canonical rotation payload by the NEW key. Proves possession. | | principal_authorization | string | yes | Base64 Ed25519 signature over the canonical payload by the principal's key. The principal is the authority over its agents' keys. | ### KeyRotationRequest Dual-signed key rotation. The canonical payload joins entity_type, entity_id, old_public_key, new_public_key, and rotation_timestamp with LF; old_public_key is always the entity's current live key as Core holds it, never a client-supplied value. The new key proves possession, the current key authorizes. | Field | Type | Required | Description | | --- | --- | --- | --- | | new_public_key | string | yes | Raw 32-byte Ed25519 public key, base64. | | rotation_timestamp | string (date-time) | yes | ISO 8601, submitted explicitly so the client and Core construct the same canonical payload. Must fall within 300 seconds of Core receipt, either side. | | new_key_proof | string | yes | Base64 Ed25519 signature over the canonical rotation payload by the NEW key. Proves possession. | | old_key_authorization | string | no | Base64 Ed25519 signature over the same canonical payload by the CURRENT key. Required for principal rotation. Optional for agent self-rotation: a request authenticated by the current key that carries the payload fields authorizes exactly the enclosed rotation. | | old_public_key | string | no | Optional diagnostic echo of the key the payload was constructed against. Core never trusts it; the live key is authoritative. | ### SandboxIdentityNotVerified The domain proof failed. The response names exactly what Core looked for and what it found, so the agent can publish the missing record or document and retry. | Field | Type | Required | Description | | --- | --- | --- | --- | | error | string | yes | | | message | string | yes | Human-readable summary including looked_for and found. | | looked_for | string | yes | The exact record or document Core required: the TXT name and value, or the well-known URL and JSON shape. | | found | string | yes | What Core actually observed: the TXT values present, the document contents, or the lookup error. | ### SandboxKeyGrant The mint grant. The sandbox_key appears here once and is stored hashed; if lost or compromised, re-mint under the re-proven domain and the prior key is revoked in the same transaction (revoked_previous says so). The key is a bearer capability handle: its blast radius is one namespace and its quotas, never a protocol identity. | Field | Type | Required | Description | | --- | --- | --- | --- | | sandbox_key | string | yes | The bearer key, ak_sandbox_ prefixed. Shown once. Present it as the X-AURA-Sandbox-Key header to provision the namespace it anchors and on every namespaced call. | | display_prefix | string | yes | The short prefix Core will use when referring to this key in logs and errors. Safe to store and display. | | domain | string | yes | The verified identity anchor. Every quota counts against it. | | verification_method | string | yes | | | granted_at | string (date-time) | yes | | | revoked_previous | boolean | yes | True when this mint revoked the domain's prior active key (one active key per domain; re-mint IS compromise recovery). | | key_semantics | object | yes | What the key is, how it presents, and when it becomes consumable, stated normatively so an agent never infers. | | quotas | object | yes | The quota defaults this grant inherits, as contract-visible facts; the operator may raise the namespace-count default without a protocol change. | | verification_reference | object | no | The exact record and document Core accepted or would accept for this domain and key, echoed for the agent to keep. | ### SandboxKeyMintRequest Mint a sandbox key: the tenant anchor for one namespace, granted to a domain-verified Ed25519 key. Two proofs are required. Possession: the X-Signature header carries the Ed25519 signature over this exact JSON body by the declared public_key (serialize with JSON.stringify, sign the UTF-8 bytes, send base64). Domain control: publish the declared key at the location only the domain's controller can write, then name the method here. dns_txt: a TXT record at _aura-agent-key. with the exact value aura-key=. well_known: the document https:///.well-known/aura-agent-key returning JSON with a matching public_key field, fetched over HTTPS to public addresses only, no redirects, 5 second timeout. Possession is checked first and cheaply; no network lookup happens for an unproven key. | Field | Type | Required | Description | | --- | --- | --- | --- | | domain | string | yes | The identity anchor: a bare public multi-label DNS hostname you control. Lowercased on receipt. No wildcards, IP addresses, schemes, ports, or paths: those cannot prove control and are refused before any lookup. | | public_key | string | yes | Raw 32-byte Ed25519 public key, base64. Never reused: a key bound to any identity, key history, or another domain is refused. | | verification_method | string [dns_txt \| well_known] | yes | Which proof Core should check. Both prove the same statement: the controller of this domain authorizes this key. | ### SandboxManifest What a provisioned sandbox namespace is, as machine-readable fact: the market it seeds, the quotas it enforces, the determinism it promises, and every semantic exception where sandbox behaviour deviates from production. Returned by provisionSandbox (live). | Field | Type | Required | Description | | --- | --- | --- | --- | | namespace_id | string (uuid) | yes | The logical namespace all state registered with this sandbox key lands in. | | scenario_version | string | yes | The versioned scenario family this namespace certifies against, as /. | | contract_version | string | yes | The protocol contract version the sandbox deployment is pinned to. Runs re-check it at start; skew is discovered here, never mid-run. | | signing_key_id | string | yes | Fingerprint of the sandbox deployment's signing key. Distinct from production's key and never listed in the production key directory. | | market_profile | object | yes | The seeded market profile with its concrete dial values, declared as facts. | | rails | array of object | yes | The simulated settlement rails, with declared reversibility, covering both reserve branches. | | counterparties | array of object | no | The seeded house counterparties: role and public key, deterministically derived per namespace. | | applicant_risk_tier | string | no | The risk tier a freshly registered applicant principal lands in, declared so reserve assertions are written against a known tier. | | quotas | object | yes | The quota values enforced for this namespace: the declared defaults, or the operator-granted namespace count where one was granted. | | latency_budgets | object | no | Published provisioning latency budgets, measured as service objectives. | | determinism | object | yes | The determinism statement: what is reproducible and what is normalized. | | sandbox_semantic_exceptions | array of object | yes | Every place sandbox semantics deviate from production, as named machine-readable entries, so an agent cannot learn a false production rule from sandbox observation. | | run_id | string (uuid) | no | The conformance run this namespace has open. Provision opens the run and returns it; reset opens a fresh one. Transcript events and the transcript endpoint key on it. | | sandbox_context | string | no | An opaque developer-plane context token, shown once with the run this provision or reset opened. Present it as the X-AURA-Sandbox-Context header on namespaced calls so the bench attributes the recorded run without the sandbox key. An attribution selector, not an authorization grant; recover a lost one by resetting. | ### ProvisionSandboxRequest Optional provisioning parameters. An empty body provisions the scenario this bench serves. | Field | Type | Required | Description | | --- | --- | --- | --- | | scenario_version | string | no | The scenario family and version to provision, as family/semver. Omitted means the version this bench serves; a mismatch is refused sandbox_contract_version_skew naming the served version, so an agent pinning a scenario never runs against a drifted bench. | Additional properties are not allowed. ### ResetSandboxRequest Optional reset parameters. An empty body resets to the scenario this bench serves. | Field | Type | Required | Description | | --- | --- | --- | --- | | reason | string | no | A note recorded in the bench log for the operator and for run forensics. It changes nothing about the reset. | Additional properties are not allowed. ### SandboxResetResult The run boundary: the namespace is destroyed and reseeded, and this run identity is what transcripts, assertion results, and run quotas key on. | Field | Type | Required | Description | | --- | --- | --- | --- | | namespace_id | string (uuid) | yes | The namespace that was reset. Unchanged across resets: the tenant anchor is the key, the namespace follows it. | | run_id | string (uuid) | yes | Opaque identifier for the run this reset opens. No ordering or format semantics are promised; treat it as a handle. | | scenario_version | string | yes | The scenario family and version this run certifies against. | | contract_version | string | yes | The protocol contract version the bench is pinned to for this run. | | reset_at | string (date-time) | yes | When the run opened. | Additional properties are not allowed. ### Shared responses - **BadRequest**: Invalid request (Error) - **Unauthorized**: Missing or invalid agent authentication (Error) - **Forbidden**: Authenticated but not authorized for this resource (Error) - **NotFound**: Resource not found (Error)