Verify phone ownership: flip PENDING_PROOF → VERIFIED with atomic side-effect resolution
Step 2 of cashier signup: verify phone ownership and transition the customer’s wallet identity from PENDING_PROOF to VERIFIED. The customer clicks the SMS link (or the cashier keys the code); the service decodes the signed verification token, guards that it is not-expired, not-consumed, and that its wallet identity is still PENDING_PROOF, then in ONE transaction flips the state to VERIFIED and resolves ALL deferred side-effects atomically: (1) create the provider-customer link binding the POS provider’s customer id to the wallet identity, (2) bind the customer to their canonical wallet (find-or-create at credit time), (3) RELEASE any LOCKED cashback-class promotional grants escrowed against the proto-wallet via the claim-gate (so the customer keeps the reload plus the now-released bonus), and (4) arm marketing/offers eligibility. None of these resolve partially: if any step fails the whole flip rolls back and the link stays consumable. Idempotent: a re-submit of an already-consumed token replays the original verified result (meta.idempotency_replayed:true) and does NOT re-release grants. A token for a wallet identity owned by another integration returns 403. The claim release engine is itself the POST /claims resource; this endpoint INVOKES it inline for the common path, while /claims is the explicit ops re-drive.
Authorizations
POS terminal JWT minted by /auth/token; carries integrationId + terminal/cashier claims (server-trusted).
Headers
Partner-generated UUID; the ONE dedup key for all mutating endpoints. 24h TTL. Same key + same payload -> byte-identical replay; same key + different payload -> IDEMPOTENCY_KEY_REUSED (422).
Body
- Option 1
- Option 2
Body for POST /enroll/verify. Supply EXACTLY ONE of the signed token (SMS link) or the keyed code, enforced by the oneOf below (a body carrying both, or neither, is invalid).
The signed single-use token from the SMS link. Provide this OR code, never both.
Canonical request context, shared across all partner domains. merchant_id is key-enforced to a merchant the calling credential is authorized for (a platform-scoped credential acts only on its own tenants), so it is never a free-text trust field: a merchant_id outside the credential's authority is rejected rather than honored.
The 6-digit numeric code the cashier keyed (alternative to the link token). Exactly 6 ASCII digits.
"482913"
Common request metadata shared across all Partner API domains. partner_request_id is a correlation identifier only: it appears in logs and responses for tracing but is never used as the deduplication key. Request deduplication is keyed exclusively on the Idempotency-Key header.
Response
Phone ownership proven; wallet identity is now VERIFIED, all side-effects resolved in one transaction (or idempotent replay of a prior verify).
The standard response envelope that every enveloped endpoint serializes through. ok is a boolean discriminator: when ok is true, the typed result is carried in data; when ok is false, a typed error object is returned instead. The meta object is uniform across the entire API surface.
The uniform response metadata block returned on every response. data_completeness_score is computed per call and reports the completeness of the returned data. decision_trace_id is present on responses that carry decision or insight output and can be used to correlate the response with its reasoning. capabilities is an additive, response-level array of hints advertising features the caller may use, and may be extended over time without notice.
Result of a successful POST /enroll/verify request. Returned when the submitted one-time passcode is accepted, confirming the customer's wallet identity and transitioning its enrollment state to VERIFIED. Once this result is returned, the wallet identity is active and eligible for subsequent wallet operations.
The typed error object returned with every non-2xx response. code is a string enum (for example WALLET_PROGRAM_AMBIGUOUS, CREDENTIAL_TYPE_UNSUPPORTED, INSUFFICIENT_FUNDS, IDEMPOTENCY_KEY_REUSED, CURRENCY_NOT_SUPPORTED), never a bare HTTP status number. Inspect code for programmatic branching, not the HTTP status. Some codes echo the valid set in details so clients can present or reconcile the accepted values: for example CREDENTIAL_TYPE_UNSUPPORTED lists the supported credential types, CURRENCY_NOT_SUPPORTED lists the supported ISO-4217 currencies, and WALLET_PROGRAM_AMBIGUOUS lists the candidate wallet_program_id values that matched the request.