Direct Credit
Credit funds from your merchant account directly into a customer's Whish wallet. This is a wallet-to-wallet transfer, settled instantly.
REST over HTTPS with JSON requests and responses. Intended for authorized distributors.
Integration flow
- 1Credit the wallet. Call Send a whish-to-whish credit with the recipient
msisdn,countryCode, amount, currency, and a uniqueexternalId. This endpoint requires IP whitelisting. - 2Funds settle instantly. The amount lands in the recipient's Whish wallet immediately; there is no separate settlement step.
- 3Confirm the outcome. Call Get credit status with the same
externalIdto verify before you record the payout as complete. - 4Retry safely. On a timeout, resend the same
externalId; an already-processed credit replays its recorded result and never double-credits.
Authentication & headers
Every request must include the HTTP 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). |
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
| Environment | Base URL | Purpose |
|---|---|---|
| Sandbox | https://partner.api.sbx.whish.money/itel-service/api | Testing, QA, integration verification. |
| Production | https://api.whish.money/itel-service/api | Live environment for real transactions. |
The cURL examples on this page target Sandbox. To go live, swap the host for the Production base URL above.
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 was accepted and processed. false when it was not; read code for the reason. |
code | String | null whenever status is true. When status is false, an operation-specific error code; the value 500 is special (see below). This field only ever reports errors, never a transaction's progress. |
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. |
The two fields move together, so read them as a pair. There are only these combinations:
status | code | Treat as |
|---|---|---|
true | null | Succeeded. Process data. |
false | 500 | Pending. The call did not return an outcome, so the result is unknown rather than failed. Reconcile as described below; do not mark it failed. |
false | any other code | Failed, unless that code is a documented challenge for the endpoint you called (for example a required provider OTP). 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 transaction has progressed. Where an operation has a lifecycle of its own (created, paid, refunded), the endpoint reports it on a separate field inside data; see that endpoint's response fields.
Get account balance
Returns the real balance of the account for the given currency. Pass currency as a query-string parameter on the request URL.
| Parameter | Type | Required | Description |
|---|---|---|---|
currency | String | Required | Currency 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.
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)'{
"status": true,
"code": null,
"dialog": null,
"actions": null,
"extra": null,
"data": {
"balance": 940977.0
}
}Send a whish-to-whish credit
Sends a wallet-to-wallet (W2W) transfer from the merchant account to a customer's Whish wallet.
Requires IP whitelisting. The sendw2w endpoint only accepts requests from source IPs that Whish has registered for your account. Provide Whish with the public egress IP(s) your servers call from (Sandbox and Production) to be allowlisted; otherwise requests are rejected. See IP whitelisting.
curl -X POST 'https://partner.api.sbx.whish.money/itel-service/api/payment/sendw2w' \
-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 '{
"externalId": "1234",
"note": "Payout for order #A-1234",
"countryCode": "961",
"msisdn": "+9617XXXXXXX",
"amount": 50.0,
"currency": "USD"
}'Request body
| Field | Type | Required | Description |
|---|---|---|---|
externalId | String | Required | Unique per transaction (idempotency key). |
note | String | Optional | Payment reason or internal remark. |
countryCode | String | Required | Recipient's international dialing code (e.g. 961). |
msisdn | String | Required | Recipient wallet number, starting with + and country code (e.g. +961XXXXXXXX). |
amount | Double | Required | Amount to transfer. |
currency | String | Required | Currency: USD or LBP. |
{
"externalId": "1234",
"note": "Payout for order #A-1234",
"countryCode": "961",
"msisdn": "+9617XXXXXXX",
"amount": 50.0,
"currency": "USD"
}{
"status": true,
"code": null,
"dialog": null,
"actions": null,
"extra": null,
"data": null
}Get credit status
Returns the status of a W2W transaction. Pass externalId and currency as query-string parameters on the request URL. Read the outcome from the shared envelope, exactly as described in Response format: status: true means the credit was found and completed, status: false with code: 500 means still pending, and any other code is a definitive failure.
| Parameter | Type | Required | Description |
|---|---|---|---|
externalId | String | Required | External identifier of the W2W transaction (the same value you sent on the credit). Passed in the query string, for example ?externalId=123456. |
currency | String | Required | Transaction currency: USD or LBP. Sent in the query string, for example ¤cy=USD. |
curl 'https://partner.api.sbx.whish.money/itel-service/api/payment/sendw2w/status?externalId=123456¤cy=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)'{
"status": true,
"code": null,
"dialog": null,
"actions": null,
"extra": null,
"retrieved": true,
"data": null
}{
"status": false,
"code": 500,
"dialog": null,
"actions": null,
"extra": null,
"retrieved": false,
"data": null
}retrieved: true here means the credit was already processed and its recorded result is being returned (not re-run). Use this endpoint to reconcile after a timeout by re-querying the same externalId. A completed credit returns data: null: the outcome is carried by status and code, not by a payload.
IP whitelisting
The Send a whish-to-whish credit (sendw2w) endpoint is IP-restricted: it only accepts requests from source IPs that Whish has registered for your account.
Send Whish the public egress IP address(es) your servers call from, for both Sandbox and Production, and Whish allowlists them on their side. Until your IPs are registered, sendw2w requests are rejected.
This is the you → Whish direction: you register your server IPs with Whish. Direct Credit has no callbacks, so there are no Whish source IPs for you to allowlist here. Keep your egress IPs stable (for example a dedicated NAT gateway) so allowlisting does not break as your infrastructure scales.
Error codes
Every code below is returned with status: false. Match the string exactly and branch on it, never on the dialog message text, which is written for display and can change.
Re-sending an already-used externalId never re-executes the transaction: the recorded result is replayed verbatim, including the original error code (safe retry, no double charge).
Direct Credit codes
| Code | Meaning | Recommended handling |
|---|---|---|
bill.invalid_amount_message_min | Amount is zero, negative, or below the service minimum. | Send a valid amount. |
auth.wrong_phone_format | Recipient msisdn cannot be parsed or validated. | Fix the msisdn (E.164 for the target country). |
auth.wrong_country_code | The msisdn's country does not match the countryCode field. | Align countryCode with the msisdn. |
invalid_currency | Unsupported currency. | Send a supported currency. |
p2p.receiver_same_as_sender | Sender and recipient are the same account. | Use a different recipient. |
p2p.cannot_receive | Recipient account is inactive or deleted. | Recipient must contact Whish; final failure. |
topup.cannot_receive | Recipient's account type or tags do not allow receiving W2W transfers. | Final failure for this recipient. |
auth.restricted_country | Recipient's country is not enabled for this service. | Final failure for this destination. |
p2p.note.too.long | The note exceeds the configured maximum length. | Shorten the note. |
p2p.limit_reached / p2p.limit_reached_count | Daily W2W amount or count limit reached. | Wait until next day or request a limit increase. |
p2p.monthly_limit_reached_amount / p2p.monthly_limit_reached_count / p2p.Monthly_limit_reached | Monthly W2W amount or count limit reached (variant depends on account tier). | Wait until next month, request an increase, or complete eKYC. |
transfer.failed.title | Recipient would exceed their maximum wallet balance. | Recipient must reduce balance or upgrade verification. |
refresh.denominations | Direct-credit service is not configured server-side. | Contact Whish. |
itel.unknown_error | Server misconfiguration or unhandled error. | Escalate to Whish if persistent. |
Common codes (all payment & billing endpoints)
Authentication, session, and request validation:
| Code | Meaning | Recommended handling |
|---|---|---|
auth.session_not_exist | Missing or invalid session token. | Re-authenticate, then retry. |
auth.session_expired | Session token expired. | Re-authenticate, then retry. |
400 | Required parameters or headers are missing, or the body failed field-level validation. | Fix the request payload; do not retry unchanged. |
timestamp.invalid | Request timestamp is outside the allowed clock-skew window. | Sync the client clock (NTP), then retry. |
request.invalid / device.invalid_os | Device or channel-level validation rejected the request. | Verify your integration headers; contact Whish if persistent. |
500 | Unhandled server-side exception. | Retry with backoff using the same externalId to avoid double execution; report if persistent. |
itel.unknown_error | Generic fallback for unexpected errors or server misconfiguration. | Retry with backoff; escalate if persistent. |
emoji.not_supported | Payload contained characters the database rejects (for example emoji). | Strip unsupported characters, then retry. |
deprecation | The endpoint version is deprecated. | Migrate to the current endpoint version. |
Account, balance, and limits (any debiting endpoint):
| Code | Meaning | Recommended handling |
|---|---|---|
sales.account_balance_insufficient | Account balance cannot cover the amount. | Top up the account, then retry with a new externalId. |
sales.account_balance_insufficient_no_balance | Same insufficient-balance condition; variant returned on third-party sale routes. | Top up, then retry with a new externalId. |
account.terminated | The calling account has been terminated. | Contact Whish (not recoverable client-side). |
account.dealer.terminated | The parent dealer account is terminated. | Contact Whish. |
sales.denomination_not_active | The requested service/denomination is disabled. | Verify the denomination id; retry later or contact Whish. |
sales.schema_not_active | Pricing schema not configured/active for this account and service. | Contact Whish (configuration issue). |
sales.exceeded_daily_limit | Daily amount/count limit reached. | Wait for the next day, or request a limit increase. |
sales.exceeded_monthly_limit | Monthly limit reached. | Wait, or request a limit increase. |
sales.lost_transactions_exist | Earlier transaction results were not acknowledged. | Query the status of prior transactions (replay their externalIds) before submitting new ones. |
account.topup.check.condition.fail (surfaced as transfer.failed.title) | The receiving account would exceed its maximum allowed wallet balance. | Final failure; the receiver must reduce balance or verify their account. |
currency.not_supported / invalid_currency | The currency is not enabled or recognized for this route (typically only LBP and USD). | Send a supported currency. |
fatal | Internal failure while registering the externalId (defensive path; not expected in practice). | Retry with the same externalId; escalate if persistent. |
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.
| Version | Date | Change |
|---|---|---|
v1.0 | 2026-07-15 | Pre-release documentation update: error-code reference added; externalId documented as a String; sandbox base URL updated. |
v1.0 | 2026-02-24 | Initial release. |
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.