Payment methods: per-method codes, currencies, amount limits, required fields and failure modes # Card payments > Accept Visa and Mastercard payments in USD through the Pesepay-hosted payment page. Pesepay accepts Visa and Mastercard payments in USD. Visa and Mastercard are separate payment methods with their own codes and their own amount limits, but they behave identically from your side. | | Visa | Mastercard | | ----------------------- | ------------------ | ------------------ | | **Payment method code** | `PZW204` | `PZW205` | | **Currency** | USD | USD | | **Amount range** | $0.10 – $10,000.00 | $0.10 – $20,000.00 | Caution **Card payments use the [redirect flow](/payments/redirect-flow/).** There is no seamless card integration today — the customer enters their card details on the Pesepay-hosted payment page, not in your checkout. That keeps raw card data out of your systems and out of your PCI DSS scope entirely. ## Customer experience [Section titled “Customer experience”](#customer-experience) The customer picks Visa or Mastercard on the Pesepay-hosted payment page, enters their card details there, completes 3-D Secure with their bank if the card requires it, and is returned to your `returnUrl`. Pesepay’s own status wording while the payment runs is *“Your payment is being processed.”* ## How to accept cards [Section titled “How to accept cards”](#how-to-accept-cards) You don’t do anything card-specific. Create the transaction with [Initiate Transaction](/api/initiate-transaction/), redirect the customer to the `redirectUrl` you get back, and Pesepay’s page offers Visa and Mastercard alongside the other methods enabled for your application. Confirm the outcome the same way as any other method: the [result callback](/webhooks/result-callback/), backed by [Check Payment Status](/api/check-payment-status/). The customer landing back on your `returnUrl` is not proof of payment — 3-D Secure can be abandoned at the last step. ## Amount limits [Section titled “Amount limits”](#amount-limits) Visa and Mastercard have **different ceilings** — $10,000 and $20,000 respectively — so a payment your Mastercard customers can make may be rejected on Visa. Amounts above the ceiling are rejected, not collected in parts. If your checkout shows an “up to” figure or validates amounts before sending the customer to Pesepay, read `minimumAmount` and `maximumAmount` live from [Get Payment Methods by Currency](/api/get-payment-methods-by-currency/) rather than hardcoding these numbers. ## Card validation rules [Section titled “Card validation rules”](#card-validation-rules) The hosted page enforces these before a card is submitted. They’re worth knowing when you’re reading a rejected sandbox payment: | Field | Rule | | ----------- | ------------------------------------------------------------------------------------------------------------------------------ | | Card number | Digits only, spaces stripped. Visa: 13, 16, or 19 digits starting with `4`. Mastercard: 16 digits. Both must pass a Luhn check | | Expiry date | 4–7 characters, month first: `MM/YY`, `MM/YYYY`, `MM-YY`, `MM-YYYY`, `MMYY`, or `MMYYYY`. Must not already have passed | | CVV | The security number printed on the card | Failures are returned as `400`, with multiple problems joined into a single message — see [Errors](/api/errors/). ## Failure modes [Section titled “Failure modes”](#failure-modes) | What happened | What you see | | --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | Card declined by the issuer | The transaction ends in a non-success [status](/resources/transaction-statuses/); the decline reason is passed through from the issuer as free text | | 3-D Secure abandoned or failed | The transaction never reaches a success status — treat it as unpaid | | Amount outside the method’s range | The payment is rejected | ## Locally-issued bank cards [Section titled “Locally-issued bank cards”](#locally-issued-bank-cards) Cards issued by Zimbabwean banks are handled through [Zimswitch](/payment-methods/zimswitch/), not through the Visa/Mastercard methods above. ## Testing [Section titled “Testing”](#testing) Sandbox card numbers for successful and failed payments are on [Test credentials](/testing/test-credentials/). # EcoCash > Accept EcoCash mobile money payments in US dollars and Zimbabwe dollars, including payments above the per-transaction limit. EcoCash is Zimbabwe’s largest mobile money network. Customers pay by entering their PIN on the phone registered to the number they’re paying with. It works in both the [redirect](/payments/redirect-flow/) and [seamless](/payments/seamless-flow/) flows, in both currencies. | | US dollars | Zimbabwe dollars | | ------------------------- | --------------------- | --------------------- | | **Payment method code** | `PZW211` | `PZW201` | | **Currency code to send** | `USD` | `ZiG` | | **Amount range** | $1.00 – $500.00 | 2.00 – 8,000.00 | | **Required field** | `customerPhoneNumber` | `customerPhoneNumber` | Amounts above the range aren’t rejected — they’re [collected in several parts](#payments-above-the-limit). No redirect is required in either currency; the payment completes on the customer’s phone. ## Customer experience [Section titled “Customer experience”](#customer-experience) * Redirect flow The customer selects EcoCash on the Pesepay-hosted payment page, enters their EcoCash-registered phone number, and enters their PIN on that phone to approve the payment. * Seamless flow You collect the customer’s phone number in your own UI and submit it as `customerPhoneNumber`. Pesepay pushes a prompt to that phone; the customer enters their EcoCash PIN to approve. Your UI should show a waiting state — Pesepay’s own wording for this step is *“Please enter PIN on the phone that is making the payment.”* ## Seamless flow: required fields [Section titled “Seamless flow: required fields”](#seamless-flow-required-fields) ```json { "paymentMethodCode": "PZW211", "paymentMethodRequiredFields": { "customerPhoneNumber": "0771234567" } } ``` | Field | Type | Required | Description | | --------------------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `customerPhoneNumber` | string | Yes | The customer’s EcoCash-registered phone number. Digits only — a leading `+` and any spaces are stripped. Must start with a recognised Econet prefix and be no more than 14 digits | Send `PZW201` instead of `PZW211` when you’re charging in Zimbabwe dollars — the field is the same. See [Make Payment](/api/make-payment/) for the full request and response shape with code samples. ## Payments above the limit [Section titled “Payments above the limit”](#payments-above-the-limit) A single EcoCash transaction can’t exceed **$500** (or **8,000** in Zimbabwe dollars). Pesepay doesn’t reject larger payments — it collects them in several parts automatically, and your integration doesn’t have to do anything different. 1. **Pesepay divides the amount into legs**, each within the ceiling. A $1,200 payment becomes three legs: $500, $500, and $200. 2. **The customer approves each leg on their phone.** They get one prompt per leg and enter their PIN each time, so a large payment takes longer and asks more of the customer than a small one. 3. **You still see one transaction.** The legs are internal — you get the same single `referenceNumber` you’d get for any other payment, one [result callback](/webhooks/result-callback/) when it’s done, and one status when you [check the payment](/api/check-payment-status/). The individual legs are never exposed to you. 4. **If any leg fails, the whole payment is reversed.** Every leg that already succeeded is refunded automatically, and the transaction ends `REVERSED`. The customer doesn’t have to ask for the money back, and you never have to handle a partly-paid order. Caution In the rare case where a reversal itself fails, the transaction ends `FAILED` rather than `REVERSED` and the customer may be temporarily out of pocket for one or more legs. Treat a `FAILED` status on a large EcoCash payment as something to reconcile, not just an unpaid order — contact Pesepay support with the `referenceNumber`. This applies to EcoCash only — every other method rejects amounts over its ceiling. Because a multi-part payment asks the customer for several PIN entries, tell them what to expect at checkout when the amount is over the limit: an unexplained second prompt is the most common reason customers abandon these payments. ## Amount limits [Section titled “Amount limits”](#amount-limits) The ranges above are configured per payment method and currency, and can change without a documentation update. Read `minimumAmount` and `maximumAmount` live from [Get Payment Methods by Currency](/api/get-payment-methods-by-currency/) if you want your checkout’s validation to stay in sync automatically. ## Failure modes [Section titled “Failure modes”](#failure-modes) | What happened | What you see | | ------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | | Phone number isn’t a valid Econet number | `400` with `Invalid Ecocash phone number supplied` | | `customerPhoneNumber` missing | `400` with `Ecocash paying phone number should be provided` | | Customer enters the wrong PIN, cancels, or ignores the prompt | The transaction ends in a non-success [status](/resources/transaction-statuses/) | | Insufficient wallet balance | The transaction fails; the message comes from EcoCash and is passed through as free text | | One leg of a multi-part payment fails | The whole payment is reversed — see [above](#payments-above-the-limit) | Decline messages for mobile money come from EcoCash, not from Pesepay, so match on [transaction status](/resources/transaction-statuses/) rather than on message text. ## Testing [Section titled “Testing”](#testing) Sandbox numbers that force a successful or failed EcoCash payment are on [Test credentials](/testing/test-credentials/). # InnBucks > Accept InnBucks payments in USD — the customer scans a QR code or enters a short code. InnBucks is a Zimbabwean mobile wallet. Unlike EcoCash it needs no customer details from you — Pesepay generates a QR code and a short code, and the customer authorises the payment from their own InnBucks app or the InnBucks USSD menu. It works in both the [redirect](/payments/redirect-flow/) and [seamless](/payments/seamless-flow/) flows. | | | | ----------------------- | ----------------- | | **Payment method code** | `PZW212` | | **Currency** | USD | | **Amount range** | $1.00 – $1,000.00 | | **Required fields** | None | | **Redirect required** | No | ## Customer experience [Section titled “Customer experience”](#customer-experience) * Redirect flow The customer selects InnBucks on the Pesepay-hosted payment page and is shown a QR code with a short code beneath it. They either scan the QR with the InnBucks app or enter the short code through the InnBucks USSD menu, then approve the payment there. * Seamless flow You submit the payment with no customer fields. Pesepay’s own wording for what the customer does next is: *“Please scan the QR Code on the screen using your Innbucks mobile app or enter the code below the QR Code via the Innbucks USSD menu.”* Show a waiting state until the [result callback](/webhooks/result-callback/) arrives or [Check Payment Status](/api/check-payment-status/) returns a terminal status. ## Seamless flow: required fields [Section titled “Seamless flow: required fields”](#seamless-flow-required-fields) InnBucks needs no required fields — send an empty object: ```json { "paymentMethodCode": "PZW212", "paymentMethodRequiredFields": {} } ``` See [Make Payment](/api/make-payment/) for the full request and response shape with code samples. ## Amount limits [Section titled “Amount limits”](#amount-limits) InnBucks accepts **$1.00 to $1,000.00** per transaction. Unlike [EcoCash](/payment-methods/ecocash/#payments-above-the-limit), larger amounts are **not** collected in parts — they’re rejected, so validate against the ceiling in your checkout. Read `minimumAmount` and `maximumAmount` live from [Get Payment Methods by Currency](/api/get-payment-methods-by-currency/) to stay in sync if the limits change. ## Failure modes [Section titled “Failure modes”](#failure-modes) | What happened | What you see | | --------------------------------------------- | ----------------------------------------------------------------------------------------- | | Customer never scans the code, or abandons it | The transaction ends in a non-success [status](/resources/transaction-statuses/) | | Insufficient wallet balance | The transaction fails; the message comes from InnBucks and is passed through as free text | | Amount outside the $1–$1,000 range | `400` — see [Errors](/api/errors/) | ## Testing [Section titled “Testing”](#testing) Caution The sandbox currently offers EcoCash, Visa and Mastercard only, so InnBucks can’t be exercised there — see [Sandbox environment](/testing/sandbox-environment/). # Omari > Accept Omari mobile money payments in US dollars and Zimbabwe dollars. Omari is a two-step OTP payment — the customer is texted a code and you submit it to complete the charge. Omari is a Zimbabwean mobile money wallet. Unlike the other wallets, **Omari does not push an approval prompt to the phone.** Paying takes two steps: the customer is sent a one-time password by SMS, and that code has to be submitted back to Pesepay to actually move the money. Omari works in both the [redirect](/payments/redirect-flow/) and [seamless](/payments/seamless-flow/) flows, in both currencies. | | US dollars | Zimbabwe dollars | | ------------------------- | --------------------- | --------------------- | | **Payment method code** | `PZW216` | `PZW217` | | **Currency code to send** | `USD` | `ZWG` | | **Amount range** | $0.50 – $500.00 | 0.10 – 100,000.00 | | **Required field** | `customerPhoneNumber` | `customerPhoneNumber` | | **Redirect required** | No | No | Caution Charge `PZW217` with the currency code `ZWG`, not `ZiG`. Zimbabwe dollars are addressed by two different currency codes depending on the method — see [Payment method codes](/resources/payment-method-codes/) for which one goes with which. ## Customer experience [Section titled “Customer experience”](#customer-experience) * Redirect flow The customer selects Omari on the Pesepay-hosted payment page and enters the phone number registered to their Omari wallet. Omari sends them a six-digit code by SMS, and the hosted page then shows an **O’mari OTP** field for them to type it into. Nothing extra is required of you — the hosted page handles both steps. * Seamless flow You build both screens: one to collect the phone number, and one to collect the six-digit code Omari texts the customer. A waiting state alone is not enough — if you never submit the code, the payment never completes. The two calls are below. ## Seamless flow [Section titled “Seamless flow”](#seamless-flow) Omari takes **two calls**. The first sends the customer a one-time code and moves no money; the second spends that code and debits the wallet. ### Step 1: request the OTP [Section titled “Step 1: request the OTP”](#step-1-request-the-otp) Send the customer’s Omari phone number as `customerPhoneNumber` to [Make Payment](/api/make-payment/): ```json { "paymentMethodCode": "PZW216", "paymentMethodRequiredFields": { "customerPhoneNumber": "263771234567" } } ``` | Field | Type | Required | Description | | --------------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------ | | `customerPhoneNumber` | string | Yes | The customer’s Omari-registered number, in full international form without a `+` — twelve digits matching `2637XXXXXXXX` | Send `PZW217` instead of `PZW216` when you’re charging in Zimbabwe dollars — the field is the same. Caution Omari is stricter about number format than the other wallets. A local form like `0771234567` is **not** accepted — send `263771234567`. Pesepay’s own checkout rejects anything that doesn’t match `2637XXXXXXXX` before it submits, and you should validate the same way so the customer sees your error rather than a failed transaction. This call does **not** debit the customer — it asks Omari to text them a code. The decrypted response comes back with a `transactionStatus` of `PENDING` and an `otpReference` in `transactionMetadata`: | Key | Description | | -------------- | ------------------------------------------------------------------------------------------------------------ | | `otpReference` | Omari’s identifier for the OTP it just sent. Store it against the transaction for support and reconciliation | Store the `referenceNumber` as usual — you need it for step 2. ### Step 2: submit the OTP [Section titled “Step 2: submit the OTP”](#step-2-submit-the-otp) Omari sends the customer a **six-digit numeric** code by SMS. Collect it in your own UI, then post it with the transaction’s `referenceNumber`. **This is the call that debits the wallet.** | Environment | URL | | ----------- | ------------------------------------------------------ | | Production | `https://api.pesepay.com/api/omari/v1/payments/charge` | ```json { "otp": "123456", "referenceNumber": "20260901103214123-A1B2C3D4" } ``` | Field | Type | Required | Description | | ----------------- | ------ | -------- | ----------------------------------------------- | | `otp` | string | Yes | The six-digit code the customer received by SMS | | `referenceNumber` | string | Yes | The `referenceNumber` from step 1 | The response carries the resulting status directly: | Field | Description | | -------------------------- | ------------------------------------------------------------------------------------------------ | | `referenceNumber` | The transaction’s reference number | | `transactionStatus` | The resulting [status](/resources/transaction-statuses/) — `SUCCESS` when the wallet was debited | | `paymentProviderMessage` | Human-readable description of that status | | `paymentProviderStatus` | Omari’s own numeric response code | | `paymentProviderReference` | Omari’s reference for the debit | ### Step 3: confirm the result [Section titled “Step 3: confirm the result”](#step-3-confirm-the-result) The charge response tells you what happened immediately, but reconcile against the [result callback](/webhooks/result-callback/) or [Check Payment Status](/api/check-payment-status/), exactly as with every other method. ## Status while you’re waiting [Section titled “Status while you’re waiting”](#status-while-youre-waiting) Between steps 1 and 2 the transaction sits at `PENDING`. That is the normal state for “the OTP has been sent but not yet submitted”, not a sign that something has gone wrong, and polling during this window keeps returning `PENDING`. If the customer abandons the flow and no OTP is ever submitted, the transaction stays non-terminal until Pesepay’s status reconciliation resolves it against Omari. It will not complete on its own. ## Amount limits [Section titled “Amount limits”](#amount-limits) Omari rejects amounts outside its configured range — **$0.50 to $500.00** for US dollars, and a much wider range in Zimbabwe dollars. Amounts above the ceiling are rejected, not collected in parts. Validate in your own checkout so the customer sees your error message rather than a failed transaction. Limits are configured per payment method **and** currency, and can change without a documentation update. Read them live from [Get Payment Methods by Currency](/api/get-payment-methods-by-currency/) (`minimumAmount` / `maximumAmount`) if you want your checkout to stay in sync automatically. ## Failure modes [Section titled “Failure modes”](#failure-modes) | What happened | What you see | | ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | Phone number isn’t in `2637XXXXXXXX` form | Omari rejects it at step 1 and the transaction ends `FAILED` | | Omari won’t send the OTP | Step 1 comes back non-`PENDING` and the transaction ends `FAILED` | | Customer enters the wrong code | The transaction ends in a terminal non-success [status](/resources/transaction-statuses/), usually `DECLINED` or `AUTHORIZATION_FAILED` | | Customer never enters the code | The transaction stays `PENDING` until reconciliation resolves it | | Omari times out | The transaction ends `TIME_OUT` | | Insufficient wallet balance | The transaction ends `INSUFFICIENT_FUNDS`; the message comes from Omari and is passed through as free text | | Amount outside the range | The API rejects the request with `400` — see [Errors](/api/errors/) | Caution A rejected OTP is terminal. There is no second attempt on the same transaction — the customer has to start a new payment, which sends a new code. Build your UI around a single attempt rather than a retry loop. Failure messages for mobile money come from the wallet provider, not from Pesepay, so match on [transaction status](/resources/transaction-statuses/) rather than on message text. ## Testing [Section titled “Testing”](#testing) Caution The sandbox currently offers EcoCash, Visa and Mastercard only, so Omari can’t be exercised there — see [Sandbox environment](/testing/sandbox-environment/). # Payment methods overview > Every payment method Pesepay supports, in each currency, with codes, amount limits, and required fields. These are the payment methods live on Pesepay today. Codes and limits are configured per method **and** currency, so the same wallet has a different code — and a different amount range — in each currency it supports. ## US dollars [Section titled “US dollars”](#us-dollars) Send `USD` as the currency code. | Method | Code | Amount range | Required fields | Flows | | --------------------------------------------- | -------- | ------------------------------------------------------------------------------------------ | --------------------- | -------------------------------------------------------------------------- | | [EcoCash](/payment-methods/ecocash/) | `PZW211` | $1 – $500 ([collected in parts above](/payment-methods/ecocash/#payments-above-the-limit)) | `customerPhoneNumber` | Redirect, seamless | | [InnBucks](/payment-methods/innbucks/) | `PZW212` | $1 – $1,000 | none | Redirect, seamless | | [Omari](/payment-methods/omari/) | `PZW216` | $0.50 – $500 | `customerPhoneNumber` | Redirect, seamless ([two-step OTP](/payment-methods/omari/#seamless-flow)) | | [Zimswitch](/payment-methods/zimswitch/) | `PZW215` | $0.10 – $5,000 | none | Redirect only | | [Visa](/payment-methods/card-payments/) | `PZW204` | $0.10 – $10,000 | none | Redirect only | | [Mastercard](/payment-methods/card-payments/) | `PZW205` | $0.10 – $20,000 | none | Redirect only | ## Zimbabwe dollars [Section titled “Zimbabwe dollars”](#zimbabwe-dollars) | Method | Code | Currency code to send | Amount range | Required fields | Flows | | ---------------------------------------- | -------- | --------------------- | ------------------------------------------------------------------------------------------ | --------------------- | -------------------------------------------------------------------------- | | [EcoCash](/payment-methods/ecocash/) | `PZW201` | `ZiG` | 2 – 8,000 ([collected in parts above](/payment-methods/ecocash/#payments-above-the-limit)) | `customerPhoneNumber` | Redirect, seamless | | [PayGo](/payment-methods/paygo/) | `PZW210` | `ZiG` | 1 – 2,400 | none | Redirect, seamless | | [Zimswitch](/payment-methods/zimswitch/) | `PZW213` | `ZWG` | 1 – 100,000 | none | Redirect only | | [Omari](/payment-methods/omari/) | `PZW217` | `ZWG` | 0.10 – 100,000 | `customerPhoneNumber` | Redirect, seamless ([two-step OTP](/payment-methods/omari/#seamless-flow)) | Caution **Zimbabwe dollars use two different currency codes.** EcoCash and PayGo are charged with `ZiG`; Zimswitch and Omari are charged with `ZWG`. Both work — send the code listed on the method’s row, not whichever one you used last. [Get Active Currencies](/api/get-active-currencies/) returns only `ZiG`, so don’t use it to decide whether `ZWG` is available. Caution **Omari is the one method whose seamless flow takes two calls.** Make Payment only sends the customer an OTP by SMS; a second call submits that code to complete the charge, and the phone number must be in `2637XXXXXXXX` form. See [Omari](/payment-methods/omari/#seamless-flow) before you build against it. ## Choosing which to support [Section titled “Choosing which to support”](#choosing-which-to-support) Start with the mobile money methods your customers actually use day to day — EcoCash has the broadest reach in Zimbabwe — then add cards and Zimswitch for higher-value customers. You don’t need to support everything on day one. Watch the amount ranges when you decide. They differ sharply per method: Visa tops out at $10,000 where Mastercard allows $20,000, and only [EcoCash collects payments above its ceiling in several parts](/payment-methods/ecocash/#payments-above-the-limit) rather than rejecting them. ## Redirect vs. seamless, per method [Section titled “Redirect vs. seamless, per method”](#redirect-vs-seamless-per-method) In the [redirect flow](/payments/redirect-flow/), Pesepay’s hosted page presents whichever methods are enabled for your application — you build no method-specific UI at all, and card data never touches your systems. Every method in the tables above works this way. The [seamless flow](/payments/seamless-flow/) is where you collect each method’s required fields yourself and submit them with [Make Payment](/api/make-payment/). Card methods — [Visa, Mastercard](/payment-methods/card-payments/) and [Zimswitch](/payment-methods/zimswitch/) — are **not** available this way: card entry happens on the Pesepay-hosted page. # PayGo > Accept PayGo QR code payments in Zimbabwe dollars. PayGo is a QR-code wallet. The customer scans a code to authorise the payment — you collect nothing from them up front. It is currently offered in **Zimbabwe dollars only**. | | | | ------------------------- | --------------- | | **Payment method code** | `PZW210` | | **Currency code to send** | `ZiG` | | **Amount range** | 1.00 – 2,400.00 | | **Required fields** | None | | **Redirect required** | No | ## Customer experience [Section titled “Customer experience”](#customer-experience) The customer is shown a QR code and scans it with the PayGo app to approve the payment. On the [redirect flow](/payments/redirect-flow/) the Pesepay-hosted page renders the code for you, which is the simplest way to support PayGo. ## Seamless flow [Section titled “Seamless flow”](#seamless-flow) PayGo needs no required fields — send an empty object: ```json { "paymentMethodCode": "PZW210", "paymentMethodRequiredFields": {} } ``` Because you’re not redirecting the customer, you have to render the QR code yourself. [Make Payment](/api/make-payment/) returns it in `transactionMetadata`: | Key | Description | | ----------- | --------------------------------------------------- | | `qrCodeUrl` | URL of the QR code image to display to the customer | | `qrCode` | The PayGo transaction identifier the code encodes | Show the code, then wait for the [result callback](/webhooks/result-callback/) or poll `pollUrl` until the [status](/resources/transaction-statuses/) is terminal. ## Amount limits [Section titled “Amount limits”](#amount-limits) PayGo accepts **1.00 to 2,400.00** per transaction. Amounts above the ceiling are rejected, not collected in parts. Read `minimumAmount` and `maximumAmount` live from [Get Payment Methods by Currency](/api/get-payment-methods-by-currency/) to stay in sync if the limits change. ## Failure modes [Section titled “Failure modes”](#failure-modes) | What happened | What you see | | ------------------------------------------------- | -------------------------------------------------------------------------------------- | | The customer never scans the code, or abandons it | The transaction ends in a non-success [status](/resources/transaction-statuses/) | | Insufficient balance | The transaction fails; the message comes from PayGo and is passed through as free text | | Amount outside the range | `400` — see [Errors](/api/errors/) | ## Testing [Section titled “Testing”](#testing) Caution The sandbox currently offers US dollar methods only, so PayGo can’t be exercised there — see [Sandbox environment](/testing/sandbox-environment/). # Zimswitch > Accept payments from locally-issued bank cards through Zimswitch, in US dollars and Zimbabwe dollars. Zimswitch is Zimbabwe’s national payment switch. It lets customers pay with a debit card issued by a local bank — the domestic equivalent of paying by [Visa or Mastercard](/payment-methods/card-payments/), and the option most Zimbabwean bank customers already have in their wallet. | | US dollars | Zimbabwe dollars | | ------------------------- | ----------------- | ----------------- | | **Payment method code** | `PZW215` | `PZW213` | | **Currency code to send** | `USD` | `ZWG` | | **Amount range** | $0.10 – $5,000.00 | 1.00 – 100,000.00 | | **Required fields** | None | None | ## Customer experience [Section titled “Customer experience”](#customer-experience) The customer selects Zimswitch on the Pesepay-hosted payment page and enters their bank card details there, then completes any authentication their bank requires. Pesepay’s own status wording while this runs is *“Processing payment via Zimswitch USD.”* ## Which flow to use [Section titled “Which flow to use”](#which-flow-to-use) Caution **Zimswitch is a [redirect flow](/payments/redirect-flow/) method.** It exposes no `paymentMethodRequiredFields`, so there is nothing for you to collect and submit through [Make Payment](/api/make-payment/) — card entry happens on the Pesepay-hosted page. That also keeps card data out of your systems entirely. You don’t need to do anything Zimswitch-specific: initiate the transaction as usual and Pesepay’s hosted page offers Zimswitch alongside the other methods enabled for your application. ## Amount limits [Section titled “Amount limits”](#amount-limits) The US dollar ceiling is **$5,000** — well above [EcoCash](/payment-methods/ecocash/) and [InnBucks](/payment-methods/innbucks/), which makes Zimswitch a useful option to enable for higher-value checkouts. Unlike EcoCash, amounts above the ceiling are **rejected**, not collected in parts. Read `minimumAmount` and `maximumAmount` live from [Get Payment Methods by Currency](/api/get-payment-methods-by-currency/) if you want your checkout to stay in sync when the limits change. ## Failure modes [Section titled “Failure modes”](#failure-modes) | What happened | What you see | | ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | | The bank declines the card | The transaction ends in a non-success [status](/resources/transaction-statuses/); the reason is passed through from the bank as free text | | The customer abandons the page | The transaction never reaches a success status — treat it as unpaid | | Amount outside the range | `400` — see [Errors](/api/errors/) | ## Testing [Section titled “Testing”](#testing) Sandbox cards for the domestic card flow are listed as **CABS** cards on [Test credentials](/testing/test-credentials/).