Installment plans
List installment banks and plans, pay with a selected plan, and see the standalone BNPL providers (valU, Octo, Souhoola, Contact, Mogo, Tru, Forsa)
To retrieve installment plans and pay with one:
Step 1: Get available banks
| Endpoint | Value |
|---|---|
| URL | https://test-api.kashier.io/merchant/installments/banks/plans?mid=yourMerchantID&amount=productPrice |
| Method | GET |
Whenever you are ready for production, use the following production API endpoint URL instead.
| Endpoint | Value |
|---|---|
| URL | https://api.kashier.io/merchant/installments/banks/plans?mid=yourMerchantID&amount=productPrice |
| Method | GET |
curl -X 'GET'
'https://test-api.kashier.io/merchant/installments/banks/plans?mid=MID-0000-000&amount=500'Full parameter and response reference → Get available banks.
Query parameters
| Parameter | Required | Notes |
|---|---|---|
mid | Yes | Your merchant ID. |
amount | Yes | The product price, used to filter out plans whose minimum the order doesn't meet. |
clientType | No | Sending POS removes QNB and Banque Misr from the returned bank list. |
minimunInstallmentAmount is misspelled on the wire
This step returns each bank's minimum as minimunInstallmentAmount — the missing second
m is genuinely part of the wire key, not a typo in these docs. Step 2 returns the same
value under a different name, Minimum installment amount. Handle both spellings across
the two steps.
allowFawry
allowFawry may still appear in this response, but as far as we can confirm nothing
routes to Fawry today: the provider is implemented in Kashier's payment-object layer,
yet it has no entry in the payment routing tables that back the /v3/orders flow, so
there is no Fawry equivalent of the Basata reference-code path. Confirm with Kashier
support before planning a Fawry integration or building against the flag.
BNPL availability flags
Alongside banks, the response carries boolean flags showing which BNPL providers are available for the merchant, computed from real provisioning for that merchant:
| Flag | Enabled when |
|---|---|
allowValu | valU is provisioned for the merchant |
allowOcto | Octo is provisioned for the merchant |
allowSouhoola | Souhoola is enabled for the merchant |
These BNPL providers use their own dedicated payment flow — they are not paid via the installments.planId card path described in Step 3 below.
Step 2: Get plans for a specific bank
| Endpoint | Value |
|---|---|
| URL | https://test-api.kashier.io/merchant/installments/plans?mid=yourMerchantID&amount=productPrice¤cy=EGP&fiId=banknSystemID |
| Method | GET |
Whenever you are ready for production, use the following production API endpoint URL instead.
| Endpoint | Value |
|---|---|
| URL | https://api.kashier.io/merchant/installments/plans?mid=yourMerchantID&amount=productPrice¤cy=EGP&fiId=banknSystemID |
| Method | GET |
curl -X 'GET'
'https://test-api.kashier.io/merchant/installments/plans?mid=MID-0000-000&amount=10000¤cy=EGP&fiId=FI-13'Full parameter and response reference → Get plans for specific bank.
Query parameters
| Parameter | Required | Notes |
|---|---|---|
mid | Yes | Your merchant ID. |
amount | Yes | The product price. |
currency | Yes | Must be EGP. Any other value is rejected with a hard 400 and the cause EGP.currency.is.required.in.installment — bank installments are EGP-only. |
fiId or cardBin | Exactly one | fiId is the Bank system ID from Step 1. cardBin is an accepted alternative: pass the customer's card BIN and Kashier resolves the bank for you. Sending both, or neither, is rejected with financial.institution.system.id.or.the.card.bin.is.required. |
clientType | No | Sending POS returns a camelCase response shape that also carries interestAmount per plan, instead of the default Title Case online shape. |
The response renames the Step 1 minimum: what Step 1 calls minimunInstallmentAmount is
returned here as Minimum installment amount.
Step 3: Pay with a plan
Once you have a Merchant Plan ID (e.g. INSPLAN-53) from Step 2, pay with it by adding installments.planId to a normal card payment request. This is the same POST /v3/orders request used for any card payment — the plan is validated before the card is charged.
| Endpoint | Value |
|---|---|
| URL | https://test-fep.kashier.io/v3/orders/ |
| Method | POST |
Whenever you are ready for production, use the following production API endpoint URL instead.
| Endpoint | Value |
|---|---|
| URL | https://fep.kashier.io/v3/orders/ |
| Method | POST |
curl -X 'POST' 'https://test-fep.kashier.io/v3/orders/' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-H 'Kashier-Hash: your_generated_hash' \
-d '{
"apiOperation": "PAY",
"installments": {
"planId": "INSPLAN-53"
},
"paymentMethod": {
"type": "CARD",
"card": {
"number": "5484571234560000",
"expiry": {
"month": "05",
"year": "26"
},
"nameOnCard": "TEST",
"securityCode": "100"
}
},
"order": {
"reference": "PM-89451648984",
"amount": "10000",
"currency": "EGP",
"description": ""
},
"interactionSource": "ECOMMERCE",
"reconciliation": {
"webhookUrl": "https://your-call-back-url.com",
"merchantRedirect": "https://your-call-back-url.com",
"redirect": true
},
"customer": {
"reference": "24"
},
"merchantId": "MID-0000-000"
}'Body parameters
| Parameter | Description |
|---|---|
installments.planId (string) | The Merchant Plan ID from Step 2 (e.g. INSPLAN-53). Matched against the plan copy enabled for your account. Omit installments entirely for a regular (non-installment) card payment. |
paymentAgreement | Set by Kashier, not by you. Omit installments and the request is treated as regular; send installments and it becomes installment. |
How the plan is validated
When installments is present, the payment is treated as an installment agreement (as opposed to a regular card charge), and the plan is validated before the card is charged:
installments.planIdmust match a known master plan. This check runs in every mode, test included.- The plan must be active.
- The card's BIN must fall inside the plan's
binRanges(the same ranges returned asSupported BINsin Step 2). - The plan must actually be provisioned and active for your merchant account.
If any check fails, the request is rejected before the card is charged, with one of the error codes below.
Validate the card BIN against Supported BINs in your own UI before submitting, so the customer is not shown a plan their card cannot use.
What test mode does and doesn't skip
Only the active-plan and BIN-range checks are gated on live mode — checks 2 and 3
above don't run in test. The master-plan lookup in check 1 still runs, so an unknown
planId returns PLAN_NOT_EXIST in test just as it does live. If your merchant copy
of a valid plan is missing, test mode synthesizes a default copy with zero fees and
planFinancing: true, so a test payment can succeed on a plan that would be rejected
live.
Pay-time errors
| Code | Meaning | Fix |
|---|---|---|
PLAN_NOT_EXIST | No plan matches the planId you sent, or your account has no copy of it. | Re-read the plan list from Step 2 and send a Merchant Plan ID from the current response. |
PLAN_NOT_ACTIVE | The plan exists but is not active. | Pick another plan, or ask Kashier support to activate it for your account. |
INVALID_BIN_RANGE | The card BIN is outside the plan's supported ranges. | Ask the customer for a card from the bank that owns the plan, or offer a different plan. |
INVALID_MERCHANT_PLAN | The plan does not belong to your merchant account. | Use only plans returned for your own mid. |
Response
Once validation passes, the normal card payment flow runs unchanged — including 3DS, capture, and the response shape. See Customized card form for the full response structure, and 3D Secure handling for the 3DS redirect flow.
You can find how much the customer will pay monthly for every plan in the Installment amount per month parameter of the Step 2 response.
BNPL installment providers
Beyond bank card installments (Steps 1–3 above), Kashier supports several standalone BNPL (buy-now-pay-later) providers. Each is its own paymentMethod.type, with its own dedicated payment flow — none of them are paid via the installments.planId card path.
| Provider | paymentMethod.type | Provider type(s) |
|---|---|---|
| valU | valu | valu (online), valupos (POS) |
| Octo | octo | octo |
| Souhoola | souhoola | souhoola |
| Contact | contact | contact, contact_pos |
| Mogo | mogo | mogo, mogo_pos |
| Tru | tru | tru |
| Forsa | forsa | forsa, forsa_pos |
Availability
Of these, three are surfaced as availability flags on the Step 1 banks response — allowValu, allowOcto, and allowSouhoola. Mogo, Tru, Forsa, and Contact don't have a documented availability flag of their own on that response; whether one of them is usable for a given merchant depends on that merchant's own provisioning rather than a flag here.
Contact
Contact (paymentMethod.type: "contact", provider contact online / contact_pos on POS) is a BNPL provider, not a cash or kiosk method. It's initiated with get_categories / validate_balance and then progresses through tenure selection, OTP, pay, and refund (including a dedicated otp_refund step).