> ## Documentation Index
> Fetch the complete documentation index at: https://docs.payfonte.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Direct Charge Processing Flows

> Understand Direct Charge response types across processing, redirect, bankTransfer, pre-OTP, and OTP provider flows.

When you call the Direct Charge API, the initial response tells you how the customer should continue or what your backend should wait for. Most Direct Charge flows follow one of these response types:

* `processing` (USSD/STK prompt flow)
* `redirect` (provider-hosted completion flow)
* `bankTransfer` (customer must transfer to returned account details)
* `pre-otp` (customer code required before request)
* `otp` (customer must enter an OTP returned after request initiation)

## 1) Processing Flow (USSD/STK Prompt)

Customer receives authorization prompt on mobile device and confirms with PIN.

### What happens

1. You initiate direct charge.
2. Provider sends STK push/USSD prompt to customer.
3. Customer authorizes on device.
4. Transaction remains pending until provider final response.

### How to detect

`data.action` is `processing`.

```json theme={null}
{
  "data": {
    "action": "processing",
    "sessionId": "1031-4120-a98f-9357692945",
    "provider": "safaricom-kenya",
    "channel": "mobile-money",
    "reference": "DDC20250812042317DIFMW",
    "amount": 1000,
    "status": "pending",
    "charge": 5,
    "statusDescription": "Awaiting Provider's Feedback"
  },
  "statusCode": 201
}
```

### Merchant handling

* Show pending state to customer.
* Do not fulfill on initial response.
* Wait for webhook or verify by reference.

## 2) Redirect Flow

Provider returns a link; customer must complete payment on provider page/app.

### What happens

1. You initiate direct charge.
2. API responds with redirect URL.
3. Customer completes payment on provider channel.
4. Customer may return to your app/site afterward.

### How to detect

`data.action` is `redirect` and URL is typically in `data.data.link`.

```json theme={null}
{
  "data": {
    "action": "redirect",
    "sessionId": "v1nadjww8lwfxxd7giumi3dyik7pzaxrxqmyvdeuunvixo25jhqf4o6wzuxhjdzg",
    "provider": "orange-ivory-coast",
    "channel": "mobile-money",
    "reference": "DDC20250812042546ICXFC",
    "amount": 10000,
    "status": "pending",
    "charge": 150,
    "statusDescription": "Awaiting Provider's Feedback",
    "data": {
      "link": "https://mpayment.orange-money.com/sx/mpayment/abstract/...",
      "message": "Click link to complete your payment",
      "reference": "DDC20250812042546ICXFC"
    }
  },
  "statusCode": 201
}
```

### Merchant handling

* Redirect user to `data.data.link`.
* On return, still verify final status server-side.
* Do not mark success from redirect alone.

## 3) Bank Transfer Flow

Payfonte returns bank account details; the customer must make a bank transfer to complete payment.

### What happens

1. You initiate direct charge with a bank transfer provider.
2. API responds with account details for the customer payment.
3. You display the account details to the customer.
4. Customer sends the transfer from their banking app or bank channel.
5. Transaction remains pending until provider confirmation.

### How to detect

`data.action` is `bankTransfer`. Account details are returned in `data.data`.

```json theme={null}
{
  "data": {
    "action": "bankTransfer",
    "sessionId": "BT-20250812043010-9D7M2",
    "provider": "bank-transfer-nigeria",
    "channel": "bank-transfer",
    "reference": "ORDER-1002",
    "amount": 10000,
    "status": "pending",
    "charge": 100,
    "statusDescription": "Awaiting customer bank transfer",
    "data": {
      "accountName": "PAYFONTE / Karis Clothing",
      "accountNumber": "0123456789",
      "bankName": "Wema Bank",
      "bankCode": "035",
      "amount": 10000,
      "reference": "ORDER-1002",
      "expiresAt": "2025-08-12T04:45:10.000Z"
    }
  },
  "statusCode": 201
}
```

### Merchant handling

* Display the returned account details clearly to the customer.
* Include bank name, account number, account name, amount, reference, and expiry when present.
* Keep the payment pending until webhook or verification confirms final status.
* Do not fulfill on proof of transfer alone.

## 4) Pre-OTP Flow

Some providers require customer to generate a provider code/OTP before you send the charge request.

### What happens

1. Customer generates code via provider USSD.
2. Customer shares code with merchant.
3. Merchant sends `customerInput.customerCode`.
4. Provider processes charge.

### Common USSD codes

* Orange Ivory Coast: `#144*82#`
* Orange Senegal: `#144#391#`
* Orange Burkina Faso: `*144*4*6*Amount*PIN#`
* Orange Mali: `#144#37#`

### Sample request

```json theme={null}
{
  "reference": "ORDER-1002",
  "amount": 50000,
  "provider": "orange-senegal",
  "webhook": "https://yourapp.com/webhooks/payfonte",
  "narration": "Direct charge test",
  "customerInput": {
    "phoneNumber": "786175702",
    "customerCode": "758610"
  }
}
```

### Merchant handling

* Collect OTP/customer code explicitly.
* Validate format before API call.
* Continue with normal webhook/verification completion flow.

## 5) OTP Flow

Some providers send an OTP to the customer after you initiate the Direct Charge request. Your application must collect that OTP from the customer and submit it to the confirmation API.

### What happens

1. You initiate direct charge.
2. API responds with `action` as `otp`.
3. Customer receives an OTP by SMS or provider channel.
4. You display an interface where the customer can enter the OTP.
5. Your backend submits the OTP with the transaction `reference`.
6. Transaction remains pending until provider final response.

### How to detect

`data.action` is `otp`. OTP instructions are returned in `data.data.message`, and `data.data.numberOfDigits` may tell you the expected OTP length.

```json theme={null}
{
  "data": {
    "action": "otp",
    "sessionId": "DDC20260702112401ZIWGF",
    "provider": "qmoney-gambia",
    "reference": "DDC20260702112401ZIWGF",
    "amount": 1000,
    "currency": "GMD",
    "totalAmount": 1000,
    "status": "pending",
    "charge": 0,
    "data": {
      "message": "You will receive an OTP via SMS on your phone number 3141106. Please provide the OTP to continue this payment.",
      "numberOfDigits": 6
    },
    "statusDescription": "Awaiting Customer Input"
  },
  "statusCode": 201
}
```

### Submit customer OTP

```bash theme={null}
curl --request POST \
  --url https://sandbox-api.payfonte.com/payments/v1/payments/confirm \
  --header 'client-id: <client-id>' \
  --header 'client-secret: <client-secret>' \
  --header 'content-type: application/json' \
  --data '{
    "reference": "DDC20260702112401ZIWGF",
    "customerInput": {
      "otp": "445985"
    }
  }'
```

### Confirmation response

```json theme={null}
{
  "statusCode": 201,
  "data": {
    "action": "processing",
    "sessionId": "cos-1z3x983b01300",
    "provider": "qmoney-gambia",
    "reference": "DDC20260702115234PTIFG",
    "providersReference": "PIX_44241170102532681668",
    "amount": 1000,
    "totalAmount": 1000,
    "charge": 0,
    "status": "pending",
    "data": {
      "message": "OTP submitted successfully. Payment confirmation is processing."
    },
    "statusDescription": "Awaiting Provider's Feedback"
  }
}
```

### Merchant handling

* Build a customer-facing OTP entry interface when `data.action` is `otp`.
* Use `data.data.numberOfDigits` to guide validation when it is present.
* Submit the OTP from your backend to `POST /payments/v1/payments/confirm`.
* Keep the payment pending until webhook or verification confirms final status.

## Flow Decision Summary

| Action                    | Customer next step                         | Merchant next step                                |
| ------------------------- | ------------------------------------------ | ------------------------------------------------- |
| `processing`              | Approve on device (USSD/STK)               | Wait for webhook/verify                           |
| `redirect`                | Complete payment on provider page          | Redirect + wait for webhook/verify                |
| `bankTransfer`            | Transfer to the returned account details   | Display account details + wait for webhook/verify |
| `pre-otp` request pattern | Generate and share code first              | Send code in `customerInput.customerCode`         |
| `otp`                     | Enter OTP received by SMS/provider channel | Collect OTP + submit confirmation request         |

## Important Rules

<Warning>
  Amount values must be integers in minor units. Decimals are not supported.
</Warning>

See [Amount Specification](/en/guides/introductions/amount-specification).

## Related Docs

<CardGroup cols={3}>
  <Card title="Direct Charge API" icon="bolt" href="/en/guides/collections/direct-charge-api">
    Endpoint usage and request field definitions.
  </Card>

  <Card title="Example Payloads" icon="code" href="/en/guides/collections/direct-charge/examples">
    Provider-specific payload templates.
  </Card>

  <Card title="Webhooks" icon="bell" href="/en/guides/collections/webhook">
    Confirm final transaction outcome asynchronously.
  </Card>
</CardGroup>
