> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.crisscross.money/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.crisscross.money/_mcp/server.

# BNPL Direct Integration

> Initiate a BNPL payment with the CrissCross API and handle the redirect into the instalment flow yourself.

### Overview

BNPL from your own server is a **redirect flow**, and it uses the same `authState` pattern as every other CrissCross method that needs the customer to go somewhere. There is no BNPL-specific endpoint and no SDK.

The shape is: create a session, initiate the payment, send the customer to the URL you get back, and wait for the webhook.

### Pre-requisites

* BNPL enabled on your account, with a settlement option agreed. See [Buy Now, Pay Later](/payment-method-bnpl#settlement-options).
* A session created with `integrationType: "direct"` and an HTTPS `redirectUrl`.
* The session amount within your BNPL limits, and a `ZAR` / `ZAF` session.

### The flow

#### Create a checkout session

```bash
curl -X POST https://api.crisscross.money/v1/checkout/session \
     -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{
  "merchantId": "YOUR_MERCHANT_ID",
  "merchantReference": "ORDER67890",
  "amount": 450000,
  "currency": "ZAR",
  "integrationType": "direct",
  "redirectUrl": "https://merchant.com/redirect",
  "payerDetails": {
    "emailAddress": "siyanda.mthembu@example.com",
    "location": "ZAF",
    "fullName": "Siyanda Mthembu",
    "phoneNumber": "0723456789"
  }
}'
```

`amount` is in minor units — the example is R4 500.00, a basket size where an instalment plan is worth offering.

#### Confirm BNPL is eligible

Do not offer BNPL in your UI without checking. Eligibility depends on your configuration and on the session's amount, currency and payer location:

```bash
curl -G https://api.crisscross.money/v1/payment/available-methods \
     -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
     -d sessionId={sessionId}
```

Offer BNPL only if an entry with `"type": "bnpl"` is present.

#### Initiate the payment

```bash
curl -X POST https://api.crisscross.money/v1/payment \
     -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{
  "paymentMethodId": "bnpl",
  "sessionId": "01951c8a-7c3d-7e1f-9d4a-2b3c4d5e6f70",
  "paymentDetails": {
    "type": "bnpl",
    "payerEmail": "siyanda.mthembu@example.com",
    "payerMobileNumber": "0723456789"
  }
}'
```

| Field                              | Required | Notes                                                |
| ---------------------------------- | -------- | ---------------------------------------------------- |
| `paymentMethodId`                  | yes      | Always the literal string `"bnpl"`                   |
| `paymentDetails.type`              | yes      | Always `"bnpl"`                                      |
| `paymentDetails.payerEmail`        | yes      | Used to identify the customer in the instalment flow |
| `paymentDetails.payerMobileNumber` | no       | Speeds up the flow when supplied                     |

You do not send the instalment term. The customer chooses it, between two and six months, inside the flow.

#### Redirect the customer

BNPL always returns `PENDING` with a redirect `authState` — there is no synchronous success, because the customer has not chosen a plan yet:

```json
{
  "transactionId": "9f3e4b2c-1a6d-4e88-9d3a-ff1234567890",
  "status": "PENDING",
  "message": "Authorization required",
  "authState": {
    "type": "redirect",
    "redirectUrl": "https://bnpl.crisscross.money/plan/9f3e4b2c-1a6d-4e88-9d3a-ff1234567890"
  }
}
```

Send the customer to `authState.redirectUrl` as returned. Do not rebuild it, embed it in an iframe, or open it in a background tab — the flow collects card details and must run as a top-level navigation.

Store `transactionId` against your order before redirecting. It is how you match the webhook.

#### Handle the return

The customer comes back to the session's `redirectUrl` with `?status=completed`, `?status=failed` or `?status=cancelled`.

This is a **display** signal only. `?status=completed` means the customer finished the flow, not that the payment is settled — and `?status=cancelled` is the ordinary outcome of a customer who was not approved or who declined the terms, which is not an error. See [When a customer is not approved](/payment-method-bnpl#when-a-customer-is-not-approved).

#### Confirm with the webhook

The webhook is authoritative. Match on `transactionId`, `sessionId` or `merchantReference`, verify its signature, and only then fulfil. The payload carries `paymentMethodId: "bnpl"` and the instalment term the customer chose. See [Webhook Events](/webhook-events).

A customer who abandons the flow entirely still produces a webhook when the session expires.

### Cancelling before completion

A BNPL payment that has not been completed can be cancelled — for example if the customer returns to your site and empties their basket:

```bash
curl -X POST https://api.crisscross.money/v1/payment/{transactionId}/cancel \
     -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```

Cancelling produces a webhook. A payment the customer has already completed cannot be cancelled — refund it instead.

### Polling

Prefer the webhook. If you need to check state directly — reconciling after an outage, or driving an order status page — read the transaction rather than polling in a tight loop:

```bash
curl -G https://api.crisscross.money/v1/payment/{transactionId} \
     -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```

A customer can sit in the instalment flow for several minutes, so a `PENDING` BNPL transaction is normal and not a sign of a problem.

### Things that will bite you

* **There is no synchronous success.** Any BNPL initiation that returns anything other than `PENDING` with a redirect is a failure to initiate, not a completed payment.
* **`?status=cancelled` is expected traffic**, not an incident. Affordability declines arrive this way.
* **Do not iframe the redirect.** It collects card details and needs a top-level navigation.
* **Settlement is not one entry per order** under instalment settlement. Reconcile on the transaction. See [Settlement Reporting](/settlement-reporting).

### Additional resources

* **[Buy Now, Pay Later](/payment-method-bnpl)** — settlement options, supported workflows, refunds and reconciliation.
* **[Full and Partial Refunds](/full-and-partial-refunds)** — refunding a BNPL payment.
* **[Webhook Events](/webhook-events)** — the authoritative payment outcome.