/oauth2/token
ZainCash Merchant Payment Gateway – Integration Guide
Thank you for choosing ZainCash, Iraq’s leading mobile payment network. The ZainCash Merchant Payment Gateway provides a secure, scalable, and seamless way for businesses to accept digital payments. By integrating our solution, you offer your customers a fast and familiar checkout experience directly through their mobile wallets.
Version
1.0
Updated
22 Jan, 2026
The ZainCash Payment Gateway v2 lets you accept payments from ZainCash wallets using a secure redirect flow, with real-time status updates via API and webhooks.
Payment Flow
A typical payment using the Payment Gateway v2 looks like this:
- Customer starts payment on your website or mobile app.
- Your backend authenticates with ZainCash using POST /oauth2/token.
- You create a transaction using POST /api/v2/payment-gateway/transaction/init.
- You redirect the customer to the Payment Gateway redirectUrl.
- Customer completes the payment (including OTP).
- ZainCash redirects the customer back to your successUrl or failureUrl with a JWT token.
- Your backend verifies the JWT and/or calls the Inquiry API to confirm final status.
- Optionally, you receive webhook notifications for status changes and refunds.
Environments
- Test: https://pg-api-uat.zaincash.iq
- Production: Provided during onboarding.
Use separate client credentials per environment.
High-level capabilities
- Wallet.
- OTP-based authentication where applicable.
- Inquiry and reversal APIs.
- JWT-based redirect and webhook callbacks.
This is the fastest way to go from zero to a working payment:
- Obtain your client_id, client_secret, and API key from ZainCash.
- Get an OAuth2 access token using client_credentials grant.
- Call the transaction/init endpoint to create a payment.
- Redirect the user to redirectUrl from the response.
- Handle the redirect to your successUrl/failureUrl using the token.
- Verify the JWT and update your order status.
1. Get Access Token
2. Create Payment
All API requests (except /oauth2/token) require a valid bearer token in the Authorization header.
Endpoint
Header | Value |
|---|---|
| Content-Type | application/x-www-form-urlencoded |
Body Parameters
Field | Type | Required | Description |
|---|---|---|---|
| grant_type | string | yes | Must be client_credentials. |
| client_id | string | yes | Your client ID. |
| client_secret | string | yes | Your client secret. |
| scope | string | yes | Space-separated scopes, e.g., payment:read payment:write. |
Get Access Token
Response
Use the access token in all subsequent API requests.
Create a new payment session and obtain the redirectUrl where you should send the customer to complete the payment.
payment:read
Header | Value |
|---|---|
| Authorization | Bearer <access_token> |
| Content-Type | application/json |
Field | Type | Required | Description |
|---|---|---|---|
| language | string | yes | Please make sure to choose the correct language based on your application locale. Supported values: "En" for English, "Ar" for Arabic And "Ku" for Kurdish. |
| externalReferenceId | string (UUID) | yes | Unique per request; use for idempotency and reconciliation. |
| orderId | string | yes | Your internal order identifier. |
| serviceType | string | yes | Service identifier (e.g., JAWS) provided by ZainCash. |
| amount.value | string / number | yes | Transaction amount. |
| amount.currency | string | yes | Must be IQD. |
| customer.phone | string | optional | Customer phone in international format (e.g., 96477...). |
| redirectUrls.successUrl | string | yes | Where the user is redirected after a successful payment. |
| redirectUrls.failureUrl | string | yes | Where the user is redirected after a failure or cancel. |
Create Payment
Request Body
Sample Response
Retrieve the latest status and details for a given payment transaction.
payment:read
Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
| transactionId | Path | string (UUID) | yes | Transaction ID from the init response. |
Transaction Inquiry Request
Sample Response
Status Values
Reverse a successfully completed transaction.
reverse:write
Reverse/Refund Request
Request Body
Field | Type | Required | Description |
|---|---|---|---|
| transactionId | string (UUID) | yes | The original successful transaction ID. |
| reason | string | yes | Business reason for initiating the reversal. |
Sample Response
After the customer completes payment on the Payment Gateway page, ZainCash redirects the user back to your site.
Redirect URLs:
- successUrl?token=JWT_TOKEN
- failureUrl?token=JWT_TOKEN
Decoded Token Example
Webhooks allow ZainCash to notify your backend whenever a transaction status changes or a refund completes. You configure a server-side notificationUrl that receives POST requests.
Prerequisites:
- Contact the business team to set the webhook URL in our system and register it.
- Please ensure that the webhook URL is separate from the success and failure URLs.
- The configuration of the webhook only works in production and doesn't work in the test environment
Create WebHook
Webhook Request
Method | Header | Description |
|---|---|---|
| POST | Content-Type: application/json | Body contains a webhook_token (JWT string). |
Decoded JWT Example STATUS_CHANGED SUCCESS
Decoded JWT Example STATUS_CHANGED FAILED
Webhook Testing with cURL
Here are all the params that you need to know about the response and request:
Params
Field | Type | Required | Description | Location |
|---|---|---|---|---|
| grant_type | string | yes | Must be client_credentials. | /oauth2/token endpoint body request |
| client_id | string | yes | Your client ID. | /oauth2/token endpoint body request |
| client_secret | string | yes | Your client secret. | /oauth2/token endpoint body request |
| scope | string | yes | Space-separated scopes, e.g., payment:read payment:write. | /oauth2/token endpoint body request |
| language | string | yes | Language code: En, Ar, or Ku. | /api/v2/payment-gateway/transaction/init endpoint body request |
| externalReferenceId | string (UUID) | yes | Unique per request; use for idempotency and reconciliation. | /api/v2/payment-gateway/transaction/init endpoint body request |
| orderId | string | yes | Your internal order identifier. | /api/v2/payment-gateway/transaction/init endpoint body request |
| serviceType | string | yes | Service identifier (e.g., JAWS) provided by ZainCash. | /api/v2/payment-gateway/transaction/init endpoint body request |
| amount.value | string / number | yes | Transaction amount. | /api/v2/payment-gateway/transaction/init endpoint body request |
| amount.currency | string | yes | Must be IQD. | /api/v2/payment-gateway/transaction/init endpoint body request |
| customer.phone | string | optional | Customer phone in international format (e.g., 96477...). | /api/v2/payment-gateway/transaction/init endpoint body request |
| redirectUrls.successUrl | string | yes | Where the user is redirected after a successful payment. | /api/v2/payment-gateway/transaction/init endpoint body request |
| redirectUrls.failureUrl | string | yes | Where the user is redirected after a failure or cancel. | /api/v2/payment-gateway/transaction/init endpoint body request |
| transactionId | string (UUID) | yes | Transaction ID from the init response. | /api/v2/payment-gateway/transaction/inquiry/{transactionId} endpint body request |
| transactionId | string (UUID) | yes | The original successful transaction ID. | /api/v2/payment-gateway/transaction/reverse endpont response body |
| reason | string | yes | Business reason for initiating the reversal. | /api/v2/payment-gateway/transaction/reverse endpont response body |
Status
Status Code | Description |
|---|---|
| SUCCESS | The final states of the transaction lifecycle . after a successful payment. |
| FAILED | The final states of the transaction lifecycle . after a failed payment attempt. |
| PENDING | Transaction created; awaiting next steps. |
| OTP_SENT | OTP delivered to the customer for authentication. |
| CUSTOMER_AUTHENTICATION_REQUIRED | Extra steps required (e.g., phone validation/fee computation pending or failed) |
| EXPIRED | Transaction exceeded its expiry time. |
| REFUNDED | The final states of the transaction lifecycle after a successful reversal/refund. |
| STATUS_CHANGED | Emitted when a transaction’s status after the payment process ends.. |
| REFUND_COMPLETED | Emitted when a reversal/refund succeeds. |
| REFUND_FAILED | Emitted when a reversal fails. |
Scopes
Scopes are basically the permissions needed for authorization to use the endpoints.
Scope | Description |
|---|---|
| payment:read | For writing privileges for payment gateway transaction processing |
| payment:write | For reading privileges for payment gateway transaction processing |
| reverse:write | For reversing a transaction |
Common error patterns you may encounter when integrating.
HTTP Status Codes
HTTP Code | Description | Notes |
|---|---|---|
| 400 | Bad Request | Invalid format (e.g., non-UUID transactionId) or missing fields. |
| 401 | Unauthorized | Missing / invalid bearer token, or expired token. |
| 403 | Forbidden | Transaction not owned by this merchant (e.g., PAYMENT_GATEWAY_UNAUTHORIZED). |
| 404 | Not Found | Transaction does not exist (PAYMENT_GATEWAY_TRANSACTION_NOT_FOUND). |
Recommendations
- Always log the HTTP status, error code, and full response body.
- Use a correlation ID if provided by the gateway for debugging with ZainCash support.
Integration Guidelines
Idempotency
- Use a unique externalReferenceId per payment attempt.
- Do not reuse the same ID for multiple different orders.
- On duplicate errors, perform an inquiry to determine the current status.
Security
- Never expose your client_secret or API key in client-side code.
- Verify all JWT tokens (redirect and webhook) using your API key and HS256.
- Use HTTPS for all your redirect and notification URLs.
Resilience
- Prefer webhooks as the primary signal for final status.
- Use transactional retries with backoff when calling the gateway APIs.
- Implement fallbacks with the inquiry API if webhooks are delayed.
Customer Wallet Management
The customer.phone field in the /transaction/init request is optional. ZainCash recommends the following approach for populating it.
Recommended flow
1. First-time payment — omit customer.phone
For a customer's first "Pay with ZainCash" transaction on your platform, send the /transaction/init request without the customer.phone field. ZainCash will prompt the customer to enter their wallet mobile number manually on the payment page.
2. Capture the wallet number from the success callback
Once the payment is completed successfully, ZainCash redirects the customer to your successUrl with a signed JWT token. After verifying the token with your API Secret Key, extract the payer wallet number from the token payload and store it against the customer's profile in your system.
3. Keep the stored wallet number up to date
After every successful transaction, update the stored wallet number with the new wallet number used in that transaction. Always rely on the Wallet Number from the latest successful payment — not only the first one — since a customer may switch wallets over time.
4. Subsequent payments — pass the latest saved wallet number
For every following transaction by the same customer, include the most recently saved wallet number in the customer.phone field of the /transaction/init request. The customer will not need to re-enter their wallet number on the payment page.
Why this guideline:
- To ensure consistent, professional, and user-friendly integration of “Pay with ZainCash” across web and mobile platforms.
- To help merchants, developers, and designers implement ZainCash payment with correct branding, UI behavior, and user flow.
- To maintain the integrity of ZainCash’s visual and interaction identity across partners.
Who should use this:
- Front-end developers / integration engineers implementing ZainCash Pay.
- UI/UX designers building checkout flows with ZainCash.
- Product/marketing teams referencing ZainCash in UI, marketing, or payment-option contexts.
Brand Name & Terminology:
- Always refer to the service as “ZainCash” or “ZainCash Pay”. Do not abbreviate, translate, or alter the name (e.g., avoid “Z-Pay”, “ZCash wallet”, etc.).
- In user-facing text, use consistent capitalization: capital “Z” and “C” — e.g., “Pay with ZainCash”.
- The merchant must ensure that the correct language is used based on the customer’s language on the merchant platform. Supported languages are Arabic, English, and Kurdish.
Logo / Mark Usage:
- Use only the official ZainCash logo or brand mark provided in their “Branding Guideline” asset pack.
- Do not recolor, distort, stretch, or apply shadows or extra effects to the logo.
- Maintain sufficient clear-space around the logo (no overlapping with other UI elements).
- Do not combine the logo with other symbols or custom icons in a way that alters its appearance.
Download Links
Button Style
- Provide a dedicated button or UI element labeled “Pay with ZainCash” (or similar), when showing payment options.
- Button styling should be clean, contrasting, and legible — consistent in padding, size, and color across pages (checkout, product page, etc.).
- On light backgrounds — use a version of button that ensures text/logo readability; on dark or complex backgrounds — ensure contrast (e.g. light text/logo on dark background)
- The button must trigger the actual ZainCash payment flow (not just a UI placeholder).
Primary Button
Primary Button Disabled
Secondary Button
Secondary Button Disabled
1. Minimum Button Size (Smallest Allowed)
- To ensure readability + tapability (especially on mobile):
Minimum button size:
- Width: 120px
- Height:40px
Padding (Minimum):
- Horizontal padding:16px
- vertical padding:8–12px
Minimum Button Size:

2. Recommended Standard Button Size
- This is the size most platforms use for wallet payments:
Standard recommended size:
- Width: 200–240px
- Height:48-54px
Padding (Recommended)
- Horizontal padding:20-24px
- vertical padding:12-14px
Standard Button Size

3. Largest Button Size (Maximum Recommended)
- Avoid going too large — keep it balanced and professional.
Largest size:
- Width:300–320px
- Height:56–64px
Padding (Recommended)
- Horizontal padding:24–32px
- vertical padding:14-16px
Largest Button Size

Test credentials used to make tests in a safe environment to try and handle all possible responses before going live.
Please use the following merchant credentials to test transaction ID creation and status checks. Ensure you copy the credentials exactly as shown, without spaces, and note that the secret key must be entered as a single line.
# | MSISDN | Client ID | Client Secret |
|---|---|---|---|
| 1 | 9647829744545 | 758055f4a8044779a35f6ceb69f858b3 | bibLCGTxVAig5To3OLLKPJQMlRR7Pefp |
Please select one of the following customer test wallets to submit your transaction.
# | MSISDN | PIN | OTP |
|---|---|---|---|
| 1 | 9647802999569 | 1111 | 111111 |
| 2 | 9647829744432 | 1111 | 111111 |
| 3 | 9647829744464 | 1111 | 111111 |
| 4 | 9647829744474 | 1111 | 111111 |
Finished testing? Congratulations! You are ready to move to the live environment.
If you have already submitted your business request: Please contact your Business Development Account Manager to obtain your live credentials.
If you haven’t submitted a request yet, please complete your application by clicking here.
Once your business is registered in the ZainCash system, you will gain full access to our powerful reporting portal.
1- Check Your Email: You will automatically receive your login credentials from [email protected].
2- Log In: Access the Merchant Dashboard using your provided Merchant Password.
3- Take Control: Search transactions, view real-time history, and process reversals or partial refunds with one click.
Didn’t find what you’re looking for?
If you require any support or have questions not covered in this documentation, please open a request through our Ticket System.
Our team is available Sunday through Thursday, from 9:00 AM to 5:00 PM (Baghdad Time). We strive to respond to all inquiries within 12–24 hours on business days. While response times may occasionally be extended during peak periods, we are committed to providing you with a resolution as quickly as possible.
Please refer to the Service Level Agreement (SLA) table below for detailed response times related to Production issues only:
Severity Level | Definition | Response Time | Resolution Time |
|---|---|---|---|
| P1 High | Complete Outage (Payment Gateway API down). Major degradation impacting a large portion of payments, but not a total outage. Merchant dashboard down, cash disbursement. | <1 Hour | <8 Hours |
| P2 Medium | Limited disruption affecting a subset of transactions or non-financial functions (e.g., merchant dashboard reports not updating real-time, no financial loss). | <4 Hours | <24 Hours |
| P3 Low | Minor/localized issues with no significant business or financial impact (e.g., single refund delayed, individual user cases) or settlement delayed by 1 day. | <1 Business Day | <10 Business Days |
Note: While we aim to provide the best support possible, please keep in mind that it only extends to resolving technical matters. We will not implement the integration for you or fix unrelated issues. However, we will suggest fixes and provide guidance.