Whish Pay API
v1.4.3Collect payments from your customers through their Whish balance. Generate a hosted payment page, track status, and issue refunds. REST over HTTPS with JSON requests and responses, for authorized distributors.
Base URL
api.whish.money/itel-service/apiGetting started
Overview
Authentication is by channel + secret + websiteUrl, issued by Whish. Payments settle in USD · LBP. This is API v1.4.3; breaking changes are released under a new version.
Note
Flow. Call Create a payment to get acollectUrl, then redirect the payer there. To confirm the outcome, rely on your successCallbackUrl and failureCallbackUrl as the primary signal. Whish calls these when the payment settles. Use Get payment status only as a fallback, for example if a callback did not arrive.Getting started
Authentication & headers
Every request must include the headers below, plus Content-Type: application/json on requests that send a body.
| Header | Description |
|---|---|
channel | Value provided by Whish. |
secret | Value provided by Whish. |
websiteUrl | Site URL or app name. Use the exact value Whish issued with your keys. |
User-Agent | Identifies 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). |
Important
Keep credentials server-side.channel and secret are server-side credentials. Never expose them in browser code, mobile apps, or public repositories. Call the API only from a secure backend, and contact Whish to rotate credentials if they are exposed.Getting started
Environments
| Environment | Base URL | Purpose |
|---|---|---|
| Sandbox | https://api.sandbox.whish.money/itel-service/api | Testing, QA, integration verification. |
| Production | https://api.whish.money/itel-service/api | Live environment for real transactions. |
Getting started
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.
| Field | Type | Description |
|---|---|---|
status | Boolean | true when the call succeeded. false when it did not; read code to tell a definitive failure apart from a pending result. |
code | String | null on success. When status is false, an operation-specific code; the value 500 is special (see below). |
dialog | Object | Optional title / message to display to the user. |
data | Object | Response payload for the operation; shape varies per endpoint, and may be a scalar or null for some operations. |
actions / extra | Object | Reserved; typically null. |
retrieved | Boolean | Present on idempotent operations. true means this response replays an already-processed request (the original was not run again); false or absent means it ran now. |
Interpret the outcome from status and code:
| Response | Treat as |
|---|---|
status: true | Call succeeded |
status: false and code: 500 | Pending (outcome unknown; escalate to Whish and do not mark it failed) |
status: false and any other code | Failed; read code (and any dialog message) to see why. |
Getting started
Integration flow
The happy path from a checkout to a confirmed order. Each step links to its endpoint below.
- 1
Create a payment
Call Create a payment with the amount, currency, your numeric externalId, and your callback URLs. You receive a collectUrl.
- 2
Redirect the payer
Send the customer to the collectUrl. They pay from their Whish balance and authorize the charge by entering the OTP delivered to their Whish app. This happens entirely on the hosted page; your integration is not involved in it.
- 3
Receive the callback
When the payment settles, Whish calls your successCallbackUrl or failureCallbackUrl by GET.
- 4
Confirm before fulfilling
Call Get payment status to verify the outcome, then release the order. Poll it as a fallback if no callback arrived.
- 5
Refund if needed
Use Refund a payment with the original externalId.
Endpoint
Get account balance
/payment/account/balance?currency={currency}Returns the real balance of the account. Pass currency as a query-string parameter on the request URL to choose which balance to return.
Query parameters
| Field | Type | Description |
|---|---|---|
currencyRequired | String | Currency to return the balance for: USD or LBP. Sent in the query string, for example ?currency=USD. |
{
"status": true,
"code": null,
"dialog": null,
"actions": null,
"extra": null,
"data": {
"balance": 10439.0
}
}Note
Each channel supports two currencies (USD and LBP). Use currency to pick which balance to return.Endpoint
Create a payment
/payment/whishReturns the hosted URL where the client is redirected to pay the merchant through their Whish balance.
Request body
| Field | Type | Description |
|---|---|---|
amount | String | Amount to be paid, sent as a JSON string (double-quoted). USD allows up to 2 decimals (minimum 1.00); LBP takes no decimals (minimum 1000). |
currency | String | Currency: USD or LBP. |
invoice | String | Description/details of the payment. |
externalId | Long | Your unique reference for the payment, and the idempotency key. Reusing an externalId within your channel returns the original response and does not charge again. |
successCallbackUrl | String | GET callback URL for a successful transaction. |
failureCallbackUrl | String | GET callback URL for a failed transaction. |
successRedirectUrl | String | Redirect URL after a successful payment. |
failureRedirectUrl | String | Redirect URL after a failed payment. |
{
"amount": "1",
"currency": "USD",
"invoice": "Order #1",
"externalId": 1,
"successCallbackUrl": "https://example.com/api/payment/success",
"failureCallbackUrl": "https://example.com/api/payment/failure",
"successRedirectUrl": "https://example.com/thank-you",
"failureRedirectUrl": "https://example.com/payment-error"
}{
"status": true,
"code": null,
"dialog": null,
"extra": null,
"data": {
"collectUrl": "https://whish.money/pay/8nQS2mL"
}
}Note
status: true here means the request succeeded and a collectUrl was generated. It does not mean the customer has paid. The payment outcome is separate: it is delivered to your callback URLs and can be checked with Get payment status.Note
The callback URLs are your primary confirmation. Whish calls them via GET when the payment settles, so treat them as the source of truth and update the order from them. The redirect URLs only send the client's browser onward. You may append custom query params (order reference, timestamp), and Whish forwards them unchanged. No OTP is delivered in sandbox.Note
Sandbox test: use phone 96170902894 with OTP 111111 for a successful payment; any other phone number or OTP produces a failure. Sandbox credentials are separate from Production.Endpoint
Get payment status
/payment/collect/statusReturns the collect status of a Whish Pay transaction. Use this endpoint as a fallback to reconcile when a callback did not arrive; the callback URLs remain the primary confirmation.
Request body
| Field | Type | Description |
|---|---|---|
currency | String | Currency: USD or LBP. |
externalId | Long | ID provided by the third party. |
{
"currency": "USD",
"externalId": 1
}{
"status": true,
"code": null,
"dialog": null,
"extra": null,
"data": {
"collectStatus": "success",
"payerPhoneNumber": "96170902894"
}
}Response fields
| Field | Type | Description |
|---|---|---|
collectStatus | String | pending, success, failed, refunded (after a refund), or unknown (final state could not be determined). |
payerPhoneNumber | String | Phone number that performed the payment. |
Endpoint
Refund a payment
/payment/whish/refundInitiates a full refund for a Whish Pay transaction (partial refunds are not supported). Requires IP whitelisting: it only accepts requests from source IPs that Whish has registered for your account. Send Whish the public egress IP(s) your servers call from, for both Sandbox and Production; otherwise refund requests are rejected. See IP whitelisting below.
Request body
| Field | Type | Description |
|---|---|---|
currency | String | Currency: USD or LBP. |
externalId | Long | ID of the original transaction to refund. |
refundReason | String | Reason for the refund. |
{
"currency": "USD",
"externalId": 1,
"refundReason": "Customer canceled order"
}{
"status": true,
"code": null,
"dialog": null,
"actions": null,
"extra": null,
"retrieved": false,
"data": null
}{
"status": true,
"code": null,
"dialog": null,
"actions": null,
"extra": null,
"retrieved": true,
"data": null
}{
"status": false,
"code": "external_id.not_exists",
"dialog": null,
"actions": null,
"extra": null,
"data": null
}Response fields
| Field | Type | Description |
|---|---|---|
retrieved | Boolean | true when you try to refund a transaction that was already refunded (a duplicate refund attempt). |
Note
Refunds are instant and the customer is notified. The original transaction is not modified; a separate reversal entry is recorded, and the transaction cannot be refunded again. There is no refund time window.Reference
Callbacks
When a payment settles, Whish sends an HTTP GET request to the successCallbackUrl or failureCallbackUrl you supplied in Create a payment, with your query parameters and nothing added by Whish. Which URL is called tells you the result. The callback is your primary confirmation; the browser redirect is not.
Important
Authenticate every callback. Whish does not sign callbacks, and IP allowlisting is only a network filter, not proof of authenticity. Add a per-payment secret token to your callback URLs and verify it on receipt with a constant-time comparison. This is exactly what the official WooCommerce plugin does.Handle callbacks like this:
- Whish sends the callback once and does not retry. If your endpoint is unavailable when it fires, you will not receive it again, so reconcile with Get payment status using the externalId.
- Before you fulfil the order, confirm the outcome with Get payment status. Requests are idempotent by externalId, so re-checking is always safe.
- Callback URLs must use HTTPS and be publicly reachable. localhost and private addresses will not receive callbacks.
Reference
Error codes
On failure, read code from the response body. Match on the exact literal value, including any unusual spelling. The documented code is below; code: 500 is a pending result, not a failure (see Response format).
| Code | Description |
|---|---|
external_id.not_exists | The provided externalId does not exist. |
Note
This list is not exhaustive. Other codes exist (for example around disabled channels and version requirements). Ask Whish for the complete error catalogue with each code's meaning, cause, whether it is retryable, and who must act.Reference
IP whitelisting
Two kinds of IP allowlisting apply, in opposite directions. Set up whichever your integration needs.
1. Inbound: your IP, allowlisted by Whish (required for Refund)
The Refund endpoint only accepts requests from source IPs Whish has registered for your account. Register or update your public egress IP(s) by contacting Whish Money, per environment (Sandbox and Production); otherwise refund requests are rejected.
2. Outbound: Whish's IPs, allowlisted by you (for callbacks)
Whish calls your callback URLs from the fixed addresses below. If your infrastructure restricts inbound traffic, allow all of them so callbacks are not blocked. If these addresses change, they will be updated on this page.
| Environment | Outbound callback IPs |
|---|---|
| Production | 18.213.222.4552.21.189.5152.21.55.64 |
| Sandbox | 52.4.4.47 |
Reference
Troubleshooting
| Problem | What to check |
|---|---|
| A request is rejected or credentials are not accepted | Confirm channel, secret, and websiteUrl exactly match the values Whish issued, and that you are calling the base URL for the same environment (Sandbox vs Production). Credentials are environment-specific. |
| status: false with code: 500 | This is a pending result, not a failure. Do not mark the order failed. Reconcile with Get payment status and retry later if it is still pending. |
| A refund is rejected | The Refund endpoint requires IP whitelisting. Confirm your server's public egress IP for this environment is registered with Whish (see IP whitelisting). |
| external_id.not_exists on status or refund | The externalId does not match a transaction in this environment. Verify you are using the same externalId and the same environment as the original payment. |
| A callback never arrives | Make sure your callback URL is publicly reachable over HTTPS (not localhost or a private address) and not blocked by a firewall. Allowlist Whish's outbound IPs if you filter inbound traffic, and reconcile with Get payment status as a fallback. |
| The customer paid but the order is still pending | A browser redirect is not proof of payment. Rely on the callback and confirm with Get payment status using the externalId before fulfilling the order. |
Reference
Postman & tools
Import the collection and one of the environment files, fill in your credentials, and call every endpoint without writing code. The {{baseUrl}} defaults to Sandbox so you cannot accidentally hit Production; switch to the Production environment for live traffic. Each request ships with an example response.
For credentials, Production access, or clarification, contact the Whish Pay team at whishpay@whish.money.