PovitoDevelopers

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#

bash
curl https://api.checkout.povito.com/v1/payment_methods \
  -H "Authorization: Bearer $POVITO_SECRET_KEY"
Response 200json
{
  "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.

What the page receives for a present methodjson
{
  "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 payment with method: "cashondelivery", gateway: "cashondelivery", a gateway_reference of the form cod_<attempt_id>, captured_amount: null, captured_currency: null, presented_amount: 45000, presented_currency: "IQD";
  • emits checkout.session.completed like 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.

A COD-only session, phone already verified on your sidebash
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.

json
"amount": 45000,
"currency": "IQD",
"payment_method_types": ["zaincash", "card"],
"presentment": { "currency": "USD", "fx_rate": 1310000000 }

fx_rate is in micro-units1000000 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:

json
"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.