Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -84,7 +84,7 @@ Denial reason codes: `missing_identity`, `identity_verification_required`, `toke

### Operator handle: what durable merchant state keys on

`getOperatorHandle(ctx)` (per-adapter; `gate.operatorHandle` on the Next.js / Web Fetch wrapper surface, `ctx.operatorHandle` inside `Checkout` hooks) returns the stable pairwise `oph_...` handle for the ACCOUNT behind the request's operator token.
`getOperatorHandle(ctx)` (per-adapter; `gate.operatorHandle` on the Next.js / Web Fetch wrapper surface, `ctx.operatorHandle` inside `Checkout` hooks, readable from `computePricing` onward; the gate that populates it runs AFTER `preValidate`, so a `preValidate` read is always `undefined` and zero-settles whatever keys on it) returns the stable pairwise `oph_...` handle for the ACCOUNT behind the request's operator token.

**Key state on this, never on the token.** An `opc_` lives 24h and rotates silently off a 90-day refresh, so anything keyed on the token instance is stranded daily, and revoking a leaked token would forfeit a prepaid balance. The handle derives from the account, so rotation, expiry and revocation are all free. It is pairwise per consuming merchant, so the same buyer presents an unrelated handle at every store and handles never correlate across them.

Expand Down
8 changes: 7 additions & 1 deletion src/checkout.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -289,7 +289,13 @@ export interface CheckoutContext {
* token instance is stranded every time one rotates.
*
* `undefined` when no gate is configured, on wallet or AIT paths, on anonymous discovery
* legs, or when the API has no handle salt configured. */
* legs, or when the API has no handle salt configured.
*
* ORDERING: populated by the gate, which runs AFTER `preValidate`, so it is readable
* from `computePricing` onward (`mintRecipients`, `composeMppx`, `onSettled` included)
* and ALWAYS `undefined` inside `preValidate`. A `preValidate` read compiles, passes
* every keyless-dev test, and zero-settles every production request whose flow keys on
* it (a live store shipped exactly that). */
operatorHandle?: OperatorHandle;
}

Expand Down