Skip to main content
Canonical end-to-end flow: OACP authority overview. Launch closure source of truth: OACP Runtime Launch Closure PRD.

Provision AgenticOrg Authority Access

  1. Store COMMERCE_C6Z_AUTHORITY_SERVICE_TOKEN through the production secret path.
  2. Add the AgenticOrg tenant id to COMMERCE_C6Z_AUTHORITY_SERVICE_TENANTS.
  3. Deploy or restart the Grantex auth service with both values available. PUBLIC_BASE_URL must be https (status list URIs are built from it).
  4. Create the first OACP issuer key: POST /v1/commerce/oacp/issuer-keys/rotate with the platform admin key. Confirm its kid (oacp-...) appears in GET /.well-known/jwks.json.
  5. Set OACP_STATUS_LIST_PUBLIC_ENABLED=true and restart when relying parties are ready to check status; until then they refuse artifacts with revocation_status_unavailable.
  6. Submit a fixture POST /v1/commerce/oacp/c6z/authority-requests for that tenant. Public discovery stays disabled unless OACP_PUBLIC_DISCOVERY_ISSUANCE_ENABLED=true and the request opts in (public_discovery_requested: true with namespace_attestation_ref and serving_host); turn the flag on only after the owner approves publishing UCP profiles.
  7. Confirm artifact_count = 11, or record the exact refusal/blocker.
  8. To roll back, remove the tenant id from COMMERCE_C6Z_AUTHORITY_SERVICE_TENANTS and rotate the token if there is any suspicion of exposure.

Enable a Synthetic Demo Tenant

A demonstration merchant with an invented catalogue gets real signed artifacts without claiming a merchant system of record. Issuance accepts connector_choice: "synthetic_demo" (and connector evidence with source_system: "synthetic_demo") only when all of these hold:
  • the tenant id is on COMMERCE_C6Z_DEMO_SOURCE_TENANTS (comma-separated; empty by default, so no tenant can use the synthetic source);
  • the same tenant id is on COMMERCE_C6Z_AUTHORITY_SERVICE_TENANTS, whoever calls (the platform admin included);
  • the request carries synthetic_data: true, and so does the connector evidence.
Otherwise the request is refused exactly as an unsupported source always was (422, status: "rejected", refusal_code: "unsupported_or_enabling_authority_request") and the refusal is recorded in oacp_artifacts with a refusal_record_id. Evidence that names another source, or is not marked synthetic, is refused connector_evidence_scope_mismatch, also recorded. Every artifact issued from the synthetic source says so in its signed payload: source_system: "synthetic_demo" and synthetic_data: true at the top level, and in source_lineage source_system: "synthetic_demo", synthetic_data: true and merchant_system_source_of_record: false. Shopify issuance is unchanged, byte for byte. Public discovery follows the same opt-in rules as for any tenant (OACP_PUBLIC_DISCOVERY_ISSUANCE_ENABLED, the allowlist and the namespace / host attestation); the public_discovery_state artifact then carries synthetic_data: true, and GET /v1/commerce/oacp/ucp-profile adds synthetic_data: true to its render, so a relying party can see the profile is a demonstration. To enable one demo tenant:
  1. Confirm with the owner that the tenant is a demonstration tenant whose catalogue is invented.
  2. Add its tenant id to COMMERCE_C6Z_AUTHORITY_SERVICE_TENANTS and to COMMERCE_C6Z_DEMO_SOURCE_TENANTS; redeploy.
  3. Submit its authority request with connector_choice: "synthetic_demo" and synthetic_data: true. Confirm 201, artifact_count = 11, and that every payload carries synthetic_data: true.
  4. Only if the demo is to publish a UCP profile: the public discovery opt-in, as above.
To withdraw it, remove the tenant id from COMMERCE_C6Z_DEMO_SOURCE_TENANTS (new synthetic requests are refused at once) and revoke its live artifacts if they must stop verifying before they expire. For a local stack (PUBLIC_BASE_URL=http://localhost:<port>), also set OACP_ALLOW_LOOPBACK_HTTP=true; without it issuance refuses the http status list URI. It is ignored when NODE_ENV is production. OACP_AUTO_GENERATE_ISSUER_KEY=true creates the first key on first use in a local or test stack; it is also ignored in production. Then run the live conformance suite from the in-tree build (the oacp suite is not yet in a published release of @grantex/conformance): GRANTEX_CONFORMANCE_INTERNAL_TOKEN=<service token> node packages/conformance/dist/index.js --base-url http://localhost:<port> --api-key <developer key> --include oacp --suite oacp --oacp-issuer http://localhost:<port> --oacp-tenant <tenant>.

Production Turn-On Order

A merge to main deploys the auth service, so the OACP code is deployed before anything is turned on. On 2026-10-20 production had no oacp- key in its JWKS and the status list route was off. Turn OACP on in this order, and do not start a step before the previous one is confirmed: Rollback, in reverse: turning OACP_STATUS_LIST_PUBLIC_ENABLED off makes every relying party refuse (fail closed), it does not make anything valid; revoking the issuer key withdraws everything it signed; removing a tenant from the allowlist stops new issuance for it. Never put Shopify tokens, provider credentials, payment credentials, raw provider payloads, checkout links, raw POS callbacks, or webhook secrets in Grantex artifacts or logs.

Keys and Revocation

Smoke Tests

Checklist

Rollback

  1. Remove the AgenticOrg tenant from COMMERCE_C6Z_AUTHORITY_SERVICE_TENANTS.
  2. Rotate the service token if compromise is suspected.
  3. Ask AgenticOrg to stop refreshing artifacts and mark affected cache records stale.
  4. Leave existing historical artifacts reviewable for audit/export (oacp_artifacts).
  5. To invalidate artifacts already handed out, revoke them individually, or revoke the issuer key to invalidate everything it signed.
  6. Publish an operator note with affected tenants, merchant ids, artifact families, and timestamps.

Arbiter Decision Ledger

POST /v1/commerce/oacp/arbiter-decisions records every AgenticOrg arbiter decision in commerce_arbiter_decisions (migration 134_commerce_ledger.sql), append-only: a trigger refuses UPDATE, DELETE and TRUNCATE, and a check constraint refuses a refusal row that carries a grant. It needs no new configuration: the service token and COMMERCE_C6Z_AUTHORITY_SERVICE_TENANTS already provisioned for authority requests apply. To stop countersigning for a tenant, remove it from COMMERCE_C6Z_AUTHORITY_SERVICE_TENANTS; recorded decisions stay readable for audit.

Witness Checkpoints

POST /v1/audit/witness-checkpoints stores AgenticOrg audit chain heads in audit_witness_checkpoints and refused forks in audit_witness_forks (both append-only, migration 134_commerce_ledger.sql). It is authenticated with the AgenticOrg service token alone; no tenant allowlist applies, because tenant_ref names AgenticOrg’s own tenant. A row in audit_witness_forks means AgenticOrg presented a second, different hash for a chain position Grantex had already witnessed: treat it as an irregularity, open an incident with AgenticOrg, and keep both the witnessed countersignature and the fork record for the review. Read them with GET /v1/audit/witness-checkpoints?source=agenticorg&tenant_ref=....

Wallet Ledger Chain

Migration 134_commerce_ledger.sql adds chain_seq, prev_hash and entry_hash to wallet_ledger_entries, chains every new entry in a BEFORE INSERT trigger under a per-wallet advisory lock, and backfills existing entries per wallet in (created_at, id) order. The backfill disables the table’s append-only trigger only inside the migration transaction, which already holds an exclusive lock on the table; it is enabled again before commit. Plan the migration for a maintenance window on a large ledger. No flag: the columns and trigger are additive and no existing response changes. A failed verification is an irregularity in financial evidence: block the wallet, keep a database snapshot, and reconcile from backups before any repair. Never repair a ledger by editing or deleting entries.

Protocol Surfaces, Receipts And Network Identity

These routes ship enabled behind authentication (the service token with its route scope and the tenant allowlist, an operator of the tenant, or the platform admin) and need no new configuration. All of them depend on step 2 (issuer key); relying parties depend on step 3.

Refusal Copy

Use exact blockers: missing source evidence, stale artifact, unsafe executable request, provider capability missing, tenant not allowlisted, or authority temporarily unavailable.

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