Authorize (and immediately debit) a wallet payment via a credential
Present a customer credential (otp, rotating QR nonce, 5-char short_code, or pass_tap) and debit the wallet atomically. There is no reservation or hold: the debit is immediate. Promotional grants are spent first (FIFO by expiry) then actual balance; the result reports the split as debited_promo_minor and debited_actual_minor. When credential.type is otp, the credential carries the otp_session_id returned by POST /payments/otp/send (the trigger leg) plus the code the customer received; the OTP is consumed atomically with the debit, so a failed debit (for example INSUFFICIENT_FUNDS) does not consume the OTP and it remains retryable. QR nonces are single-use; a replayed nonce returns CREDENTIAL_EXPIRED_OR_REPLAYED. The credential is a discriminated union on credential.type, so additional types extend the enum without changing the route. Idempotent on the Idempotency-Key header: a same-key, same-payload retry replays the original result byte-identical, and a same-key, different-payload request returns IDEMPOTENCY_KEY_REUSED. Cross-tenant calls (a merchant_id not authorized for the integration) resolve to FORBIDDEN. Terminal and cashier-driven flows (OTP, QR) authenticate with the PosTerminalJWT scheme. Identity-verified wallets only: a pending_proof wallet may not pay. This resource returns the debit result, never a standalone debit or authorization token.
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
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.
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.
- Option 1
- Option 2
- Option 3
- Option 4
Amount to debit in the currency's minor unit (e.g. fils for QAR, halalas for SAR). Server-authoritative; the debit is exactly this value.
x >= 13500
ISO-4217 currency code.
"QAR"
Partner's order or receipt reference, stored for reconciliation. Maps to context.partner_session_id if absent. For an otp credential this effective value (order_ref, or partner_session_id when absent) must equal the order_ref the OTP session was minted with at POST /payments/otp/send; a mismatch fails the anti-replay check.
"ord-88812"
Basket lines. Optional but increases data_completeness_score. Line totals are captured but NOT the debit basis, amount_minor is.
Response
Wallet debited. meta.idempotency_replayed is true on a replay.
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.
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.