Trigger a payment OTP, SMS a 6-digit code bound to this order + amount
Triggers the OTP leg of a wallet payment: resolves the customer’s wallet from the phone, mints an OTP session bound to the calling integration, the order, and the amount, and sends the customer a 6-digit code by SMS. No money moves on this call. The point of sale then submits the code via POST /payments with credential.type: otp, carrying the returned otp_session_id plus the code; verification and debit are atomic there (one call, no hold). The order and amount binding is the anti-replay boundary: a session minted for one order cannot authorize another, and an amount change requires a fresh send. This is an SMS-cost and abuse surface, so it is aggressively rate-limited per phone and per terminal; re-sending before resend_after_seconds elapses returns RATE_LIMITED with a Retry-After header. Idempotent on the Idempotency-Key header: a retried send replays the same session without a duplicate SMS. Cross-tenant requests resolve to 403 or 404; a pending_proof wallet may not pay.
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
Body for POST /payments/otp/send, the OTP trigger leg. Binds the minted OTP session to the order and amount so the code cannot be replayed across orders.
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.
Customer phone in E.164 format. Used to resolve the wallet.
"+97433001122"
The amount this OTP session authorizes, minor units. The subsequent POST /payments must match.
x >= 13500
ISO-4217 currency code for amount_minor.
"QAR"
The partner order identifier this OTP session is bound to (the anti-replay boundary). MUST equal the order_ref sent on the subsequent POST /payments, or, when that request omits order_ref, its context.partner_session_id. A session minted for one order cannot authorize another.
"odoo-pos-000123"
Response
OTP session minted + code SMSed. Submit the code via POST /payments with the otp credential.
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 POST /payments/otp/send. Carry otp_session_id into the otp credential of POST /payments.
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.