Whish Money
Whish Money
Partner Integration Guide

Whish Pay QR

Generate a Whish Pay payment session that returns a QR payload and a six-digit code the customer scans or enters to pay from their Whish balance.

REST over HTTPS with JSON requests and responses. Intended for authorized distributors.

v1.0.0Platform: WhishJSON over HTTPSAuthor: TecFrac
Authentication
channel + secret + websiteUrl
Production base URL
https://api.whish.money/itel-service/api
Currencies
USD · LBP

Integration flow

  1. 1
    Create a session. Call Create a payment session with the amount, currency, your externalId, and optionally a callbackUrl. You receive a qr_payload, a six-digit code, and a pending status.
  2. 2
    Present the QR or code. Show the customer the QR payload or the six-digit code. They scan the QR or type the code and pay from their Whish balance.
  3. 3
    Receive the callback. If you set a callbackUrl, Whish sends it an HTTP POST with a JSON body after every payment attempt, whether it succeeded or failed. A failed attempt does not close the session: it stays payable until it is either paid or expires.
  4. 4
    Confirm before fulfilling. Verify the outcome with Get payment status before releasing the order. Poll it as the fallback if a callback did not arrive, or as your primary signal if you did not set a callback.

A status: true response means the session was created and the qr_payload and six-digit code were returned. It does not confirm payment. The payment result (data.status starts as pending) comes only from your callback and/or the payment status endpoint, so confirm it there before fulfilling the order.

Authentication & headers

Every request must include the HTTP headers below, plus Content-Type: application/json on requests that send a body.

HeaderDescription
channelMerchant channel provided by Whish.
secretMerchant secret provided by Whish.
websiteUrlMerchant website URL or registered application name. Use the exact value Whish issued with your keys.
User-AgentIdentifies your app. Use your own details, not Whish's. Format: AppName/version (website; contact-email). Example: AcmeStore/2.1 (https://acme.example; dev@acme.example).

Keep your credentials secret. They authorize account actions and money movement, so send them only over HTTPS, store them in a secure secrets manager, and never expose them in client-side code, logs, or version control. Rotate them immediately if you suspect a leak.

Environments

EnvironmentBase URLPurpose
Sandboxhttps://partner.api.sbx.whish.money/itel-service/apiTesting, QA, integration verification.
Productionhttps://api.whish.money/itel-service/apiLive environment for real transactions.

The cURL examples on this page target Sandbox. To go live, swap the host for the Production base URL above.

Sandbox payment simulation is not yet available. You can create sessions and integrate the request/response and callback handling in sandbox, but a way to complete a QR payment as a customer is not provided yet. Contact Whish Money for end-to-end test steps.

Response format

All endpoints return HTTP 200 with Content-Type: application/json and a shared envelope. Always branch on the status and code fields in the body, never on the HTTP status code.

FieldTypeDescription
statusBooleantrue when the call was accepted and processed. false when it was not; read code for the reason. Not to be confused with data.status, the String payment status.
codeStringnull whenever status is true. When status is false, an operation-specific error code; the value 500 is special (see below). Not to be confused with data.code, the numeric code the payer enters.
dialogObjectOptional title / message to display to the user.
retrievedBooleanfalse for a new session; true when an existing active session is returned.
dataObjectResponse payload for the operation; shape varies per endpoint.
actions / extraObjectReserved; typically null.

The two fields move together, so read them as a pair. There are only these combinations:

statuscodeTreat as
truenullSucceeded. Process data.
false500Pending. The call did not return an outcome, so the result is unknown rather than failed. Escalate to Whish and do not mark it failed.
falseany other codeFailed, unless that code is a documented challenge for the endpoint you called. Handle documented challenges as an expected step in the flow, not as a failure; see the relevant endpoint reference.

A status: true is never accompanied by a code, and a code never reports how far a payment has progressed. The payment's own lifecycle is data.status on a session, collectStatus on Get payment status, and status in the callback body; a QR session returns status: true with data.status: "pending", which is a successful call for a payment nobody has made yet.

Get account balance

Returns the real balance of the merchant account. Pass currency as a query-string parameter on the request URL to choose which balance to return.

GET/payment/account/balance?currency={currency}
ParameterTypeRequiredDescription
currencyStringRequiredCurrency to return the balance for: USD or LBP. Sent in the query string, for example ?currency=USD.

Each channel supports two currencies (USD and LBP). Use currency to pick which balance to return.

Example request · cURL
cURL · Sandbox
curl 'https://partner.api.sbx.whish.money/itel-service/api/payment/account/balance?currency=USD' \
  -H 'channel: YOUR_CHANNEL' \
  -H 'secret: YOUR_SECRET' \
  -H 'websiteUrl: https://yoursite.com' \
  -H 'User-Agent: AcmeStore/2.1 (https://acme.example; dev@acme.example)'
Response · 200 success
application/json
{
  "status": true,
  "code": null,
  "dialog": null,
  "actions": null,
  "extra": null,
  "data": {
    "balance": 10439.0
  }
}

Create a payment session

Creates a Whish Pay payment session from your backend. A successful response returns a session identifier, a six-digit payment code, a QR payload, the expiry time, and the initial session status.

POST/payment/whish/session
Example request · cURL
cURL · Sandbox
curl -X POST 'https://partner.api.sbx.whish.money/itel-service/api/payment/whish/session' \
  -H 'channel: YOUR_CHANNEL' \
  -H 'secret: YOUR_SECRET' \
  -H 'websiteUrl: https://yoursite.com' \
  -H 'User-Agent: AcmeStore/2.1 (https://acme.example; dev@acme.example)' \
  -H 'Content-Type: application/json' \
  -d '{
  "amount": 10.0,
  "currency": "USD",
  "externalId": "ORDER-2026-0001",
  "invoice": "INV-2026-0001",
  "callbackUrl": "https://merchant.example/api/whish/payment-success?orderId=ORDER-2026-0001",
  "expiry": 10
}'

Request body

FieldTypeRequiredDescription
amountDoubleRequiredPayment amount. Must be greater than 0.
currencyStringRequiredPayment currency: USD or LBP.
externalIdStringRequiredUnique merchant transaction reference; must not be blank. Reuse the same value to return the existing active session (idempotency); a new payment needs a new value.
invoiceStringOptionalInvoice or order reference.
callbackUrlStringOptionalPayment-result callback URL. Whish POSTs to it after every payment attempt, successful or failed. Must be a valid, reachable URL.
expiryIntegerOptionalRequested session lifetime in minutes. Effective range 5–30 (see Session behavior).
Request
Request body
{
  "amount": 10.0,
  "currency": "USD",
  "externalId": "ORDER-2026-0001",
  "invoice": "INV-2026-0001",
  "callbackUrl": "https://merchant.example/api/whish/payment-success?orderId=ORDER-2026-0001",
  "expiry": 10
}
Response · 200 success
application/json
{
  "status": true,
  "code": null,
  "dialog": null,
  "actions": null,
  "extra": null,
  "retrieved": false,
  "data": {
    "session_id": 123456789,
    "code": "583921",
    "qr_payload": "https://api.sandbox.whish.money/pay/AbC123xY",
    "expiry_time": "2026-06-30T12:10:00Z",
    "status": "pending"
  }
}

Session data

FieldTypeDescription
session_idLongWhish payment session identifier, for your records and support queries. You do not need it to check status or receive callbacks; those key off your externalId.
codeStringSix-digit payment code.
qr_payloadStringWhish Pay deeplink to encode as a QR code.
expiry_timeDate/TimeSession expiry date and time.
statusStringInitial value is pending.

qr_payload is the exact value to encode as a QR code. The API returns the payload string, not a PNG, SVG, or Base64 image. The six-digit code and the QR payload refer to the same session, share the same expiry time, and a session can be completed only once.

The callbackUrl must be publicly reachable. Sending localhost (or any loopback or non-public host) is not allowed: the request is rejected with HTTP 403 Forbidden. Use a public URL.

Get payment status

Returns the collect status of the session. Use it to confirm the outcome when a callback did not arrive, and to tell a settled outcome from an open one: a failure callback reports one failed attempt and leaves the session payable, so this endpoint is what confirms a session finally failed.

POST/payment/collect/status
Example request · cURL
cURL · Sandbox
curl -X POST 'https://partner.api.sbx.whish.money/itel-service/api/payment/collect/status' \
  -H 'channel: YOUR_CHANNEL' \
  -H 'secret: YOUR_SECRET' \
  -H 'websiteUrl: https://yoursite.com' \
  -H 'User-Agent: AcmeStore/2.1 (https://acme.example; dev@acme.example)' \
  -H 'Content-Type: application/json' \
  -d '{ "currency": "USD", "externalId": "ORDER-2026-0001" }'

Request body

FieldTypeRequiredDescription
currencyStringRequiredCurrency: USD or LBP.
externalIdStringRequiredThe externalId you sent when creating the session.
Request
Request body
{
  "currency": "USD",
  "externalId": "ORDER-2026-0001"
}
Response · 200 success
application/json
{
  "status": true,
  "code": null,
  "dialog": null,
  "actions": null,
  "extra": null,
  "data": {
    "collectStatus": "success",
    "payerPhoneNumber": "96170123456"
  }
}

Response fields

FieldTypeDescription
collectStatusStringSession status: pending, success, failed, refunded, or unknown.
payerPhoneNumberStringPhone number that performed the payment.

Session behavior

QR and code

  • qr_payload is the exact value to encode as a QR code.
  • The API returns the payload, not a PNG, SVG, or Base64 image.
  • The six-digit code and the QR payload refer to the same session and share the same expiry time.
  • A session can be completed only once.

Expiry

Submitted valueEffective expiry
Not provided or null5 minutes
Less than 55 minutes
Between 5 and 30Submitted value
Greater than 3030 minutes

After expiry, the QR payload and code must no longer be used. A new payment attempt must use a new externalId.

Duplicate externalId

Existing conditionResult
Active session with the same amountExisting session returned with retrieved: true.
Existing session with a different amountexternal_id.already_used
Successful, failed, or refunded sessionwhishpay.tx.invalid_state
Expired sessioncollect.expired

Supported statuses

StatusDescription
pendingWaiting for customer payment.
successPayment completed successfully.
failedThe session expired without being paid. A single failed attempt does not land here: the session stays pending and payable until it is paid or expires.
refundedSuccessful payment was refunded.
unknownFinal state could not be determined.

A QR payment is a Whish Pay collection, so refunds are issued with the Whish Pay Refund endpoint (/payment/whish/refund) using the same externalId. Once refunded, the session status here becomes refunded. See Whish Pay → Refund a payment.

Callbacks

When callbackUrl is provided, Whish reports the outcome of every payment attempt on the session to it.

A failure callback is not the end of the payment. A QR session stays payable until it is either paid successfully or expires, so a customer whose attempt failed can simply scan or enter the same code again. That is why Get payment status keeps reporting pending after a failure callback: the payment can still succeed. Only a session that expires without a successful payment settles as failed. So treat a failure callback as this attempt failed, never as this order failed, and do not cancel the order on it.

  • Whish calls it after every attempt: once with status: "success" when the session is paid, and once with status: "failed" for each attempt that fails.
  • You get one callback per attempt, so a session paid on the second try produces a failed callback followed by a success callback.
  • The callback uses HTTP POST with Content-Type: application/json.
  • The request body carries the payment result; both shapes are identical apart from status.
  • Query parameters already included in the merchant URL are preserved.
  • Respond with HTTP 200 to acknowledge receipt.
Callback URL
POST
https://merchant.example/api/whish/payment-result?orderId=ORDER-2026-0001
Callback body success
application/json
{
  "status": "success",
  "amount": 10000,
  "currency": "LBP",
  "timestamp": 1787299542710,
  "external_id": "17872994498120050",
  "session_id": 25257080
}
Callback body failure
application/json
{
  "status": "failed",
  "amount": 10000,
  "currency": "LBP",
  "timestamp": 1787299530415,
  "external_id": "17872994498120050",
  "session_id": 25257080
}

Callback body

FieldTypeDescription
statusStringResult of this attempt: success or failed. failed describes the attempt, not the session, which stays payable until paid or expired.
amountNumberAmount of the session, in currency.
currencyStringPayment currency: USD or LBP.
timestampLongWhen the attempt was recorded, as a Unix timestamp in milliseconds (not an ISO date string).
external_idStringThe externalId you sent when creating the session. This is your key for matching the callback to an order.
session_idLongWhish payment session identifier, for your records and support queries.

Because a failure callback is not a settled outcome, confirm with Get payment status before releasing an order, and use it to reconcile if a callback did not arrive (for example a transient network failure) or if the session expired unpaid, which is reported by status rather than by a callback. A missing callback should be reconciled by polling status, not treated as a failed payment.

Whish calls your callbackUrl from a fixed set of source IPs. If your callback endpoint restricts inbound traffic, allowlist them; the list is maintained in the Reliability & Idempotency guide.

Error codes

Example failure
application/json
{
  "status": false,
  "code": "amount.invalid",
  "dialog": {
    "title": "Error",
    "message": "Amount must be greater than zero"
  },
  "actions": null,
  "extra": null,
  "data": null
}

Core codes

CodeDescription
invalid.requestRequest body is missing.
400Mandatory authentication/request parameters are missing, or request field validation failed.
auth.session_not_existMissing, invalid, expired, or mismatched merchant session, token, or websiteUrl.
auth.session_expiredMerchant session token is expired. Re-authenticate or request a new session.
external_id.requiredexternalId is missing or blank.
currency.requiredcurrency is missing or blank.
amount.invalidAmount is missing, zero, or negative.
currency.not_supportedCurrency is not USD or LBP.
external_id.already_usedExternal ID is linked to another amount or invalid session.
whishpay.tx.invalid_stateExisting session is in a final state such as successful, failed, or refunded.
collect.expiredExisting session has expired. Use a new externalId.
collect.wrong_denominationMerchant payment denomination is not configured.

Additional error codes

CodeDescription
collect.wrong_phone_formatPhone number could not be normalized or validated.
collect.wrong_email_formatEmail value is present but invalid.
refresh.denominationsConfigured denomination is unavailable or not refreshed on the server.
credit_card_payment.account_verification_requiredMerchant account must be verified before this transaction can proceed.
whish_pay.missing_pricing_idWhish Pay pricing is not configured for the merchant profile.
whish_pay.code_generation_failedPayment code could not be generated or retrieved.
purchase.confirmQuoted price changed before confirmation. Re-quote and resubmit with the new price.
failPricing or amount computation failed. Check the returned dialog for details.
sales.account_balance_insufficientMerchant account balance cannot cover the transaction amount.
sales.account_balance_insufficient_no_balanceMerchant account balance is insufficient on the third-party sale route.
account.terminatedCalling account is terminated.
account.dealer.terminatedParent dealer account is terminated.
sales.denomination_not_activeRequested service or denomination is disabled.
sales.schema_not_activePricing schema is not configured or active for this account and service.
sales.exceeded_daily_limitDaily amount or count limit has been reached.
sales.exceeded_monthly_limitMonthly amount or count limit has been reached.
sales.lost_transactions_existPrevious transaction results must be checked before submitting a new transaction.
emoji.not_supportedPayload contains unsupported characters such as emoji.
collect_qr.general_errorQR deeplink could not be generated or retrieved.
500Unhandled server-side exception.
itel.unknown_errorUnexpected internal error or generic fallback.

Version history

Notable changes to this API and its reference, newest first. The current version is the one shown at the top of this page.

VersionDateChange
v1.02026-07-15Pre-release documentation update: callback aligned to HTTP POST with a JSON body; error codes expanded; externalId documented as a String; sandbox base URL updated.
v1.02026-06-30Initial release for the Whish Pay payment session endpoint.

Postman & tools

Import the ready-made Postman collection for this API, set your credentials as collection variables (or attach a sandbox / production environment), and call every endpoint without writing code. The OpenAPI 3.1 specification is also available to generate client SDKs or validate requests.

Download collectionOpenAPI specAll downloads & environments

In Postman: Import → select the file → choose the Sandbox or Production environment → fill in your credentials. Requests use {{baseUrl}} and the credential variables provided.