Payment methods#
A method is what the shopper sees on a tile. A gateway is the vendor Povito talks to. For most methods they are the same thing (zaincash is ZainCash); card is the exception — it is a method type that routes to one of several card rails. payment.method and payment.gateway on a completed session tell you both.
What your merchant can offer#
curl https://api.checkout.povito.com/v1/payment_methods \
-H "Authorization: Bearer $POVITO_SECRET_KEY"{
"data": [
{
"code": "zaincash",
"display_name": { "ar": "زين كاش", "ku": "زەین کاش", "en": "ZainCash" },
"flow": "redirect",
"currencies": ["IQD"],
"limits": {},
"capabilities": { "refunds": "full", "saved_instruments": false, "wallets": [] },
"enabled": true
},
{
"code": "fib",
"display_name": { "ar": "FIB", "ku": "FIB", "en": "FIB" },
"flow": "present",
"currencies": ["IQD"],
"limits": {},
"capabilities": { "refunds": "none", "saved_instruments": false, "wallets": [] },
"enabled": true
},
{
"code": "cashondelivery",
"display_name": { "ar": "الدفع عند الاستلام", "ku": "پارەدان لە کاتی وەرگرتن", "en": "Cash on delivery" },
"flow": "offline",
"currencies": ["IQD"],
"limits": {},
"capabilities": { "refunds": "none", "saved_instruments": false, "wallets": [] },
"enabled": true
},
{
"code": "stripe",
"display_name": { "ar": "بطاقة دولية", "ku": "کارتی نێودەوڵەتی", "en": "International card" },
"flow": "redirect",
"currencies": ["USD"],
"limits": {},
"capabilities": { "refunds": "partial", "saved_instruments": true, "wallets": ["apple_pay", "google_pay"] },
"enabled": false
}
]
}The list is in your display order and includes methods that are deployed but not enabled for you (enabled: false) so you can see what exists. Only enabled: true codes may go in payment_method_types; a disabled one fails the create with 422 method_not_enabled. Povito enables methods per merchant and per mode when your vendor agreements are in place.
The catalogue#
| Code | Shown as | Flow | Currencies | Refunds via API | Saved instruments | Notes |
|---|---|---|---|---|---|---|
zaincash |
ZainCash | redirect | IQD | full only | no | Wallet. Reversal is whole-transaction. |
fib |
FIB | present | IQD | none | no | QR + app links; the shopper approves in the FIB app. |
fib_card |
FIB Card | redirect | IQD | none | yes | Iraqi cards, 3-D Secure on FIB's page. |
fastpay |
FastPay | redirect | IQD | partial | no | Wallet. |
nasspay |
NassPay | redirect (form POST) | IQD | none | no | Wallet. |
asiapay |
AsiaPay | redirect | IQD | full only | no | Wallet. |
stripe |
International card | redirect | USD | partial | yes | Stripe Checkout; Apple Pay / Google Pay once the domain is verified (Phase 2). |
card |
Card | routes | IQD or USD | per rail | per rail | An umbrella — see card routing. |
apple_pay, google_pay |
Apple Pay, Google Pay | redirect | USD | partial | — | Wallet variants of card, served by Stripe. Phase 2. |
cashondelivery |
Cash on delivery | offline | IQD | none | no | No money moves — see cash on delivery. |
qicard |
Qi Card | — | — | — | — | Reserved in the contract; no gateway is deployed yet, so it never appears enabled. |
test |
Test gateway | redirect | IQD, USD | partial | no | Test mode only — see testing. |
limits is per currency ({ "IQD": { "min", "max" } }) when a vendor publishes them; no deployed vendor does today, so it is {}. "Refunds via API" is what POST /refunds can do; for none you refund through the vendor's own tools and record it on your side — see refunds.
Flows#
Every method belongs to one of four flows. You only see the flow on the hosted page (or in the embedded drop-in); on the merchant API the outcome is always the same session with payment filled in.
redirect#
The page sends the shopper to the vendor's hosted page (ZainCash, FIB Card's 3DS page, Stripe Checkout, …). The vendor sends them back to checkout.povito.com/r/{attempt_id}. The return handler ignores every vendor query parameter for money purposes and triggers a verify against the vendor's own status API; only a verified capture whose amount equals what was presented marks the attempt succeeded and the session completed.
NassPay wants a form POST rather than a link: the attempt carries form_post fields and the page auto-submits them. You never see this on the merchant side.
present#
FIB does not redirect. The page shows a QR code, a readable code and deep links to the FIB personal and business apps, valid until the vendor's deadline; the shopper approves in the app while the page polls. Polling is what triggers verification — a vendor callback, when one arrives, only prompts the same verify.
{
"attempt_id": "pa_live_3M8XQ2K7A9BC4DEFGH1J",
"kind": "present",
"redirect_url": null,
"form_post": null,
"present": {
"qr_code": "data:image/png;base64,…",
"readable_code": "FIB-482-119-034",
"personal_app_link": "https://personal.fib.iq/…",
"business_app_link": "https://business.fib.iq/…",
"valid_until": "2026-09-10T12:19:00.000Z"
}
}charge#
A server-side charge against a saved instrument — a card the shopper stored on a previous checkout (fib_card, stripe). The page shows "pay with •••• 4242", the API charges the token and verifies; the shopper may still be bounced to the issuer for 3-D Secure. Saved instruments are a Phase 2 feature; the flow is listed so the enum is complete.
offline#
Nothing is charged. Choosing the method completes the session immediately with payment_status: "requires_offline_collection". Today that is cash on delivery only.
Cash on delivery#
Cash on delivery is a first-class method because in Iraq it is the default. Selecting it on the page:
- moves the session to
status: "completed",payment_status: "requires_offline_collection"; - fills
paymentwithmethod: "cashondelivery",gateway: "cashondelivery", agateway_referenceof the formcod_<attempt_id>,captured_amount: null,captured_currency: null,presented_amount: 45000,presented_currency: "IQD"; - emits
checkout.session.completedlike any other completion.
requires_offline_collection is your signal to dispatch and collect. No money has moved and Povito never learns whether it did: when your courier collects, record it in your own system. Refunds through POST /refunds are refused for these sessions (409 session_not_open — there is no captured payment to refund).
Because there is no vendor, a cash-on-delivery session can skip the phone step: create it with collect: { "phone": "none", "name": "optional", "shipping_address": "none" } when you already verified the shopper yourself, and the page completes in one tap. With the default collect, the shopper still verifies their phone first — usually what you want for a delivery.
curl -X POST https://api.checkout.povito.com/v1/checkout/sessions \
-H "Authorization: Bearer $POVITO_SECRET_KEY" \
-H "Idempotency-Key: 0c2c6b1e-9d6a-4f0e-8a5c-1b2d3e4f5a6b" \
-H "Content-Type: application/json" \
-d '{
"reference_id": "POV-1042",
"amount": 45000,
"currency": "IQD",
"line_items": [
{ "label": "Basket", "amount": 42000, "type": "charge" },
{ "label": "Delivery", "amount": 5000, "type": "shipping" },
{ "label": "Coupon", "amount": 2000, "type": "discount" }
],
"payment_method_types": ["cashondelivery"],
"customer": { "phone": "+9647800000000", "name": "Ali M. Ismail" },
"collect": { "phone": "none", "name": "optional", "shipping_address": "none" },
"success_url": "https://your-store.example/checkout/return"
}'Card routing#
card is one tile that resolves to a rail per session:
| Session | Rail | Why |
|---|---|---|
currency: "USD", or presentment set |
stripe (if configured for this mode) |
The shopper is paying in dollars. |
| Otherwise | fib_card (if configured) |
Iraqi card, IQD, 3-D Secure. |
fib_card not configured |
stripe |
Fallback. |
| Neither configured | tile shown as unavailable (not_configured) |
RT Bank acquiring will join as a second IQD rail behind the same tile when its integration is available; the router will pick by BIN country. Nothing about routing leaks into your integration beyond payment.method (card) and payment.gateway (fib_card or stripe), which you should store — refund capability and reconciliation depend on the gateway, not the method.
USD presentment for cards#
Stripe presents USD only. To offer international cards on an IQD basket, pass a presentment block with the rate your business uses. Povito snapshots the rate on the attempt, reports it back, and never recomputes it.
"amount": 45000,
"currency": "IQD",
"payment_method_types": ["zaincash", "card"],
"presentment": { "currency": "USD", "fx_rate": 1310000000 }fx_rate is in micro-units — 1000000 is 1.0 — and is session currency per presentment currency: 1310000000 means 1 USD = 1,310 IQD. Povito converts 45,000 IQD to 34.351… USD and rounds half-to-even to cents: 3435. Only the methods that cannot present IQD use it; ZainCash on the same session still presents 45,000 IQD.
The page tells the shopper the presented amount per method before they choose, and a completed card payment reports every number:
"payment": {
"attempt_id": "pa_live_3M8XQ2K7A9BC4DEFGH1J",
"method": "card",
"gateway": "stripe",
"gateway_reference": "cs_live_a1B2c3D4…",
"captured_amount": 3435,
"captured_currency": "USD",
"presented_amount": 3435,
"presented_currency": "USD",
"fx_rate": 1310000000,
"captured_at": "2026-09-10T12:04:31.000Z",
"instrument": { "brand": "visa", "last_four": "4242" }
}Note that captured_amount is 3435 USD cents, not 45,000 IQD — Povito reports what the vendor took, in the currency it took it, and checked that it equalled what was presented. Your ledger converts at the snapshotted fx_rate if it needs the dinar figure. Refunds on such a payment are in USD cents too.
Without presentment, a USD-only method on an IQD session is shown as unavailable with IQD_not_supported. A presentment.currency without a recorded exponent is 400 unsupported_currency.
Saved instruments#
capabilities.saved_instruments: true means the rail can tokenise a card for reuse (fib_card, stripe). The shopper opts in on the page; the token is stored encrypted at Povito, never returned to you, and surfaces as payment.instrument: { brand, last_four } on the session and as customer.instrument.saved events. Reuse — the charge flow above — and revocation arrive with customer profiles in Phase 2.
Wallets#
capabilities.wallets lists the wallets a rail can surface (apple_pay, google_pay on stripe). They render as an express row above the tiles once checkout.povito.com is domain-verified with Apple and Google — Phase 2. Passing apple_pay or google_pay in payment_method_types today requires Stripe to be enabled and simply routes to Stripe Checkout, where the wallet button appears if the shopper's device supports it.