Skip to main content
Canonical end-to-end flow: OACP authority overview. AgenticOrg calls Grantex when it needs authority artifacts, mandates, a countersigned arbiter decision or a witnessed audit head. It does not route non-binding buyer messages through Grantex. Before any of this works in an environment, that environment needs an active OACP issuer key and, for verification, OACP_STATUS_LIST_PUBLIC_ENABLED=true. Without the key, issuance answers 503 oacp_issuer_key_unavailable; without the public status list, AgenticOrg’s verifier refuses every artifact and mandate with revocation_status_unavailable. Order: operator runbook.

Runtime Flow

Request Contract

AgenticOrg sends:
  • tenant, merchant, seller agent, and source identifiers;
  • merchant self-service config refs for source connector, buyer channels, provider-owned payment rails, public publishing, and POS metadata;
  • requested OACP artifact families;
  • source observed timestamp;
  • public-safe connector evidence;
  • no raw Shopify credential, raw provider payload, checkout URL, or payment URL.
  • no raw POS payload, raw payment payload, order-created claim, or POS paid-state claim.
Grantex returns:
  • 201 artifact_issuance_ready with artifact families when ready;
  • 202 received when connector evidence is still required;
  • 422 when the request is private, stale, executable, or otherwise unsafe.
Every refusal is recorded in Grantex (refusal_record_id); a 202 received intake is not.

Synthetic Demo Source

A demonstration merchant whose catalogue is invented sends connector_choice: "synthetic_demo" and synthetic_data: true in the request, and source_system: "synthetic_demo" with synthetic_data: true in the connector evidence, never shopify. Grantex accepts it only for a tenant on both COMMERCE_C6Z_DEMO_SOURCE_TENANTS and COMMERCE_C6Z_AUTHORITY_SERVICE_TENANTS; otherwise it answers 422 unsupported_or_enabling_authority_request, as for any unsupported source, and records the refusal. Accepted artifacts carry source_system: "synthetic_demo" and synthetic_data: true in the signed payload and in source_lineage, with merchant_system_source_of_record: false. AgenticOrg should label answers and public surfaces built from them as demonstration data. Public discovery for such a tenant follows the usual opt-in, and its public_discovery_state artifact carries synthetic_data: true.

Verifying Artifacts

AgenticOrg must verify every artifact before caching it, as OACP artifact authority describes:
  • pin the Grantex issuer (JWT_ISSUER) and JWKS URI (<issuer>/.well-known/jwks.json) in configuration; never follow a URL taken from an artifact;
  • run the eight verification steps with the refusal codes listed there (the shared vectors in spec/examples/oacp/oacp-artifact-jws-v1.json cover steps 1-6);
  • read the status list at status.status_list.uri, verify it against the same JWKS, cache it no longer than its ttl (30 s), and refuse with revocation_status_unavailable when it cannot be read;
  • treat schema_version oacp.artifact.v1 as the signed profile, and artifact ids as unique per issuance (oacp_art_<ULID>), not stable per family.
Recovery after a cache loss uses replay: GET /v1/commerce/oacp/artifacts?tenant_id=... with the same service token, following next_cursor. Revocation uses POST /v1/commerce/oacp/artifacts/:artifactId/revoke.

Public Catalog Publishing Boundary

AgenticOrg publishes public buyer-safe seller and product surfaces after it has valid Shopify/OACP evidence and the operator enables public catalog publishing. Grantex does not host these catalog pages and does not sit in the hot path for non-binding buyer questions. Expected AgenticOrg public surfaces: Those outputs must include source and freshness labels, must not expose Shopify credentials or raw provider payloads, and must not claim checkout, payment, mandate, order, certification, or external platform approval. If the AgenticOrg cache is stale, revoked, or source-mismatched, the public surface must block or label the missing requirement instead of inventing facts.

Required Configuration

Failure Handling

If Grantex is unavailable, AgenticOrg may answer non-binding buyer questions from valid cached artifacts. Commitment-bound or POS-bound requests must refresh, prepare no execution, use only valid cached policy when risk permits, or refuse.

Arbiter Decisions

AgenticOrg’s policy arbiter is authoritative and deterministic: it seals allow or refuse from the mandate, consent, Commerce Passport cap and OACP artifact evidence, and never waits for a person. It posts every sealed decision to Grantex, which only records and countersigns it. POST /v1/commerce/oacp/arbiter-decisions uses the same service token and tenant allowlist as the authority route; developer, merchant and agent credentials are refused. The body:
AgenticOrg verifies the returned decision_grant against the Grantex JWKS (typ decision+jwt, aud urn:grantex:decision, approver_auth policy_arbiter, action_hash equal to its own payload_hash) before storing the jti beside its decision row. Grantex’s human decision-grant verifiers (POST /v1/decisions/consume, SDK verifyDecisionGrant(s) and enforce()) refuse a policy_arbiter grant, so it can never stand in for a human approval. The profile is specified in spec/decision-grant.md section 10.

Witness Checkpoints

AgenticOrg anchors the head of its hash-chained audit_log and asks Grantex to witness it, so a later rewrite below a witnessed head is provable outside AgenticOrg. POST /v1/audit/witness-checkpoints (same AgenticOrg service token) takes {source: "agenticorg", tenant_ref, chain: "audit_log", head_seq, head_hash, anchored_at} (head_hash lowercase hex SHA-256) and answers 201 {witness_id, countersignature, witnessed_at, created: true}. countersignature is a compact JWS (typ audit-witness+jwt, platform key, kid in /.well-known/jwks.json) over those fields plus witnessed_at, with jti = witness_id and no exp. GET /v1/audit/witness-checkpoints?source=agenticorg&tenant_ref=...&limit=... returns {checkpoints, forks}, newest head_seq first. AgenticOrg verifies the countersignature against the Grantex JWKS before storing the witness_id beside its anchor row, and treats a WITNESS_FORK as an irregularity of its own chain.

UCP And ACP Surfaces

Each route takes the same service token with its own route scope and the tenant allowlist. Details: OACP runtime authority and adapter mappings.

Mandates

Grantex issues Intent, Cart and Payment mandates as ES256 JWTs signed with the OACP issuer key. Each mandate is on the OACP Token Status List. Why plain JWTs, and how they map to AP2: OACP mandates decision. Each route takes the service token with its own route scope and the tenant allowlist, or an operator of the tenant. tenant_id is the Commerce Passport’s commerce tenant. An issue response is {mandate, jti, mandate_type, exp, status: {status_list: {idx, uri}}, mandate_hash, claims, audit_event_id}; a refusal carries error.audit_event_id when the tenant is a commerce tenant. Store jti and mandate_hash (lowercase hex SHA-256 of the compact JWT) in the ledger and in the arbiter evidence (mandate_ref, mandate_hash). Put the three mandate hashes in the Plural order metadata. Verify every mandate locally before relying on it. Use the pinned Grantex issuer and JWKS, and check the status list. Order and refusal codes:
  • mandate_malformed, mandate_algorithm_unsupported, mandate_type_mismatch (check the expected typ);
  • issuer_key_untrusted, mandate_signature_invalid, mandate_issuer_mismatch, mandate_claims_invalid;
  • mandate_not_yet_valid (60 s skew), mandate_expired, mandate_lifetime_exceeded (exp - iat over 600 s);
  • mandate_audience_mismatch (aud is the merchant id);
  • mandate_revoked, mandate_suspended, revocation_status_unavailable (fail closed).
Then check the chain:
  • the cart’s intent_mandate_jti and the payment’s cart_mandate_jti;
  • payment.transaction_id == cart.checkout_hash;
  • the payment amount and currency equal the cart total;
  • the cart total is within the intent cap;
  • the same tenant, merchant, sub, buyer agent and consent_ref.
A failed chain check is mandate_chain_mismatch. The SDK sources carry this as verifyOacpMandate / checkOacpMandateChain (TypeScript), verify_oacp_mandate / check_oacp_mandate_chain (Python) and VerifyOacpMandate / CheckOacpMandateChain (Go); they are not yet in a published package release. The shared vectors are in spec/examples/oacp/oacp-mandates-v1.json and oacp-mandates-v1-extra.json. Issuance refuses, and records the refusal (the error details.refusal_record_id), with these codes:
  • passport and consent: passport_invalid, passport_revoked, passport_not_checkout, passport_scope_missing, passport_cap_missing, consent_not_active, passport_cap_exceeded, currency_mismatch, merchant_not_allowed;
  • presence: presence_mismatch (a human_not_present mandate under a human_present consent or parent);
  • parent mandate: parent_mandate_expired, parent_mandate_revoked, parent_mandate_suspended, parent_mandate_invalid, mandate_chain_mismatch, intent_cap_exceeded;
  • passkey: passkey_evidence_required (a human_present cart without an assertion), passkey_evidence_invalid, passkey_evidence_replayed;
  • request content: checkout_invalid, card_data_refused, payment_rail_unsupported, token_binding_invalid, intent_invalid.
If revocation state is unavailable, the response is 503 revocation_unavailable. A mandate never outlives its passport or its parent, and a checkout passport lives 600 s, so request the three mandates within one passport’s life.

Mandate Capability Evidence

Send the result of the provider capability verifier (verify_plural_pine_mandate_capability) with the C6Z authority request. It is a top-level mandate_capability_evidence member beside request and connector_evidence. Grantex binds it into the signed mandate_capability artifact. The object is closed: unknown members are refused, and it must hold no secrets.
The rules:
  • result_status and redacted_evidence_ref are the verifier’s own values.
  • rails and caps use the mandate rail names plural, upi_autopay and card_network_token, with integer minor units.
  • verified_at must be at most 6 h old and not in the future.
  • available needs external_validation_performed: true and at least one rail.
The artifact then says mandate_capability_status: "verified". It carries mandate_capability_ref (the redacted reference) and mandate_capability_evidence: the object without tenant and merchant, plus evidence_object_hash, Grantex’s SHA-256 of the RFC 8785 form of what it received.
  • Any other result_status gives unavailable.
  • With no evidence the artifact says unverified and carries no reference. The placeholder provider:mandate_rail:capability:pending:redacted is gone.
  • Malformed, stale, out-of-scope or placeholder evidence is refused as mandate_capability_evidence_invalid (422, recorded).
  • The UCP profile emits checkout and order only while the live mandate_capability artifact is verified.

Settlement Receipts

When a payment settled over x402 or MPP, AgenticOrg can bind the receipt to the commitment: POST /v1/commerce/oacp/commitment-evidence/settlement-receipts with the service token (scope commerce.oacp.commitment_evidence.write, tenant allowlist; operators and the platform admin are refused). Grantex issues a signed commitment_evidence artifact with the receipt hash, network and transaction reference, never the payer, and records the receipt as reported, not verified, because neither receipt format is signed. The same commitment and receipt again answers 200; another receipt for that commitment answers 409. settlementReceiptEvidence in @grantex/x402 shapes an x402 receipt for this body (a source addition, not yet released); an MPP receipt is sent as {protocol: "mpp", receipt: <the decoded Payment-Receipt object>}.

Agent Request Signatures

AgenticOrg verifies and signs agent HTTP requests with grantex-agent-httpsig (verify_with_profile / sign_with_profile, profiles grantex, tap and web-bot-auth). The library, the shared vectors and the registry’s key directory are described in agent network identity. The registry key directory is served only with HTTP_SIGNATURE_DIRECTORY_ENABLED on, and its keys carry the registry’s countersignature rather than per-key signatures.

Presence And Authentication Methods

A consent request names presence: human_present (the buyer confirms each cart with a passkey) or human_not_present (the buyer delegated purchases within the consented caps). The default is human_not_present. The buyer sees the mode on the consent page and it is part of the payload whose hash they approve. Approval records amr: ["consent", "otp"]. The Commerce Passport carries both as presence and amr claims, and mandates copy them. A passport issued before these claims existed reads as human_not_present with no methods. AgenticOrg’s arbiter applies its stricter not-present rule set to human_not_present; neither mode adds a human step to a delegated purchase.

Ownership

Grantex is owned by Orchestrum Technologies LLP. Inventor and owner: Sanjeev Kumar. Ownership contact: sanjeev@orchestrum.in or mishra.sanjeev@gmail.com.
Last modified on October 21, 2026