> For the complete documentation index, see [llms.txt](https://docs.fonbnk.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.fonbnk.com/server-to-server/integration-guide/transfer-types-explanation.md).

# Transfer types explanation

Once an order is created the user has to pay. `order.deposit.transferInstructions.type` says how, and each type carries different data:

* <mark style="color:yellow;">**manual**</mark> – the user makes the transfer themselves from the details we give. Carries `transferDetails`.
* <mark style="color:yellow;">**redirect**</mark> – the user finishes on a third-party payment page. Carries `paymentUrl`.
* <mark style="color:yellow;">**stk\_push**</mark> – the user gets a prompt on their phone and approves it with their PIN. Carries the intermediate-action fields below. If the prompt does not arrive, call [Trigger order intermediate action](/server-to-server/api-endpoints/trigger-order-intermediate-action.md) to send another.
* <mark style="color:yellow;">**otp\_stk\_push**</mark> – same as `stk_push`, but first the user verifies their phone number with a code sent by SMS or WhatsApp. Submit that code to [Trigger order intermediate action](/server-to-server/api-endpoints/trigger-order-intermediate-action.md); the prompt follows. Adds `fieldsForIntermediateAction` and `otpChannel`.
* <mark style="color:yellow;">**ussd**</mark> – the user dials a code on their handset. Carries `ussdCode`.

{% hint style="info" %}
**Which of the five you will actually meet.** `manual`, `stk_push` and `redirect` are all live — and the type follows the provider, not the channel, so Ivorian mobile money is `redirect` today while Kenyan mobile money is `stk_push`. `otp_stk_push` sits on a single offer that is held back from ordinary offer search, so you only reach it by pinning `deposit.transferType` on [Create quote](/server-to-server/api-endpoints/create-quote.md). No live offer serves `ussd` at the moment.

Branch on the `type` you are given rather than on the channel, and handle all five: the mapping changes as providers are added.
{% endhint %}

The intermediate-action fields on `stk_push` and `otp_stk_push`:

| Field                                      | What it tells you                                   |
| ------------------------------------------ | --------------------------------------------------- |
| `isIntermediateActionAvailable`            | whether you may call the endpoint at all            |
| `intermediateActionMaxAttempts`            | the total budget                                    |
| `intermediateActionAttempts`               | how many have been used                             |
| `intermediateActionNextAttemptAvailableAt` | the earliest time you may try again                 |
| `intermediateActionTimeoutMs`              | how long to wait before treating an attempt as lost |
| `intermediateActionButtonText`             | a ready-made label for your retry button            |
| `intermediateActionExecuted`               | whether the action has already gone through         |

Full field lists are on [Types](/server-to-server/types.md).

### Example of the manual transfer

A fiat (bank) → crypto order created through [Create order](/server-to-server/api-endpoints/create-order.md). The <mark style="color:yellow;">order.deposit.transferInstructions</mark> could look like this:

{% code overflow="wrap" %}

```json
{
  "type": "manual",
  "instructionsText": "Transfer the NGN to the agent's bank account.",
  "warningText": "Important: Only transfer funds from a bank account you specified previously. Send the exact NGN amount. Use the displayed account for this transaction only.",
  "transferDetails": [
    {
      "id": "recipientBankName",
      "label": "Bank name",
      "value": "PROVIDUS BANK"
    },
    {
      "id": "recipientBankAccountNumber",
      "label": "Bank account number",
      "value": "9670555843"
    },
    {
      "id": "recipientBankAccountName",
      "label": "Bank account name",
      "value": "Start Button Limited(Checkout)"
    },
    {
      "id": "bankTransferNarration",
      "label": "Bank transfer narration",
      "description": "TRANSFER WITHOUT NARRATION WILL BE IGNORED BY THE SYSTEM.",
      "value": "shc-pshr4upg8s"
    },
    {
      "id": "amountToSend",
      "label": "Amount to send",
      "value": "14800"
    }
  ],
  "fieldsToConfirmOrder": []
}
```

{% endcode %}

Which says:

* The type is <mark style="color:yellow;">manual</mark>, so the user makes the transfer themselves.
* They must send <mark style="color:yellow;">14800</mark> NGN to account 9670555843 with the narration <mark style="color:yellow;">shc-pshr4upg8s</mark>. Both the amount and the narration have to match, and the money has to come from the account they gave you.
* The `recipient*` details are the agent's account, not the account the user gave you.
* `fieldsToConfirmOrder` is empty, so [Confirm order](/server-to-server/api-endpoints/confirm-order.md) needs only the order ID.

### Example of the stk\_push transfer

A fiat (mobile money) → crypto order:

```json
{
  "type": "stk_push",
  "instructionsText": "You’ll be prompted with a USSD dialog to proceed the transfer. If the transfer is unsuccessful or you don’t receive the USSD dialog, please retry the transfer",
  "warningText": "",
  "intermediateActionButtonText": "Retry USSD prompt initialization",
  "intermediateActionMaxAttempts": 3,
  "intermediateActionAttempts": 1,
  "intermediateActionNextAttemptAvailableAt": "2025-12-01T11:54:49.260Z",
  "intermediateActionTimeoutMs": 60000,
  "isIntermediateActionAvailable": true,
  "transferDetails": [
    {
      "id": "amountToSend",
      "label": "Amount to send",
      "value": "635"
    }
  ],
  "fieldsToConfirmOrder": []
}
```

Which says:

* The user should already have a prompt on their phone asking them to send 635.
* One of three attempts is used. If nothing arrived, you can send another after <mark style="color:yellow;">2025-12-01T11:54:49.260Z</mark> — two more times — by calling [Trigger order intermediate action](/server-to-server/api-endpoints/trigger-order-intermediate-action.md) with just the order ID.
* Do not spend the last attempt on a whim: calling once the budget is exhausted expires the order.

### Example of the otp\_stk\_push transfer

A fiat (mobile money) → crypto order where the phone number has to be verified first. You will only see this on an order created from a quote that pinned `transferType: "otp_stk_push"`:

{% code overflow="wrap" %}

```json
{
  "type": "otp_stk_push",
  "instructionsText": "Enter the OTP code received via WhatsApp to initiate the transaction and you’ll be prompted with a USSD dialog to proceed the transfer. If the transfer is unsuccessful or you don’t receive the USSD dialog, please retry the transfer",
  "warningText": "",
  "intermediateActionButtonText": "Verify OTP code",
  "intermediateActionMaxAttempts": 3,
  "intermediateActionAttempts": 1,
  "intermediateActionNextAttemptAvailableAt": "1970-01-01T00:00:00.000Z",
  "intermediateActionTimeoutMs": 30000,
  "isIntermediateActionAvailable": true,
  "transferDetails": [
    {
      "id": "amountToSend",
      "label": "Amount to send",
      "value": "310000"
    }
  ],
  "fieldsToConfirmOrder": [],
  "fieldsForIntermediateAction": [
    {
      "key": "otpCode",
      "label": "OTP code",
      "type": "number",
      "required": true
    }
  ],
  "intermediateActionRequired": true,
  "intermediateActionExecuted": false,
  "otpChannel": "whatsapp"
}
```

{% endcode %}

Which says:

* We already sent the code over <mark style="color:yellow;">whatsapp</mark>. Ask the user for it. `otpChannel` can also be `sms`, `ussd` or `email`.
* Post it as <mark style="color:yellow;">otpCode</mark> to [Trigger order intermediate action](/server-to-server/api-endpoints/trigger-order-intermediate-action.md). The USSD prompt follows.
* `intermediateActionNextAttemptAvailableAt` is the epoch, so you may call immediately. `intermediateActionExecuted` is `false`, so nothing has been submitted yet.

### Example of the redirect transfer

Redirect is not a bank-only shape: Ivorian mobile money and the Senegalese, Ivorian and Gambian digital wallets are all redirect channels today.

{% code overflow="wrap" %}

```json
{
  "type": "redirect",
  "paymentUrl": "https://partner.example.com/pay/9c1f2e...",
  "redirectedToPaymentUrl": false,
  "intermediateActionButtonText": "Continue to payment",
  "instructionsText": "You will be redirected to our partner to finish the payment.",
  "warningText": "",
  "transferDetails": [
    {
      "id": "amountToSend",
      "label": "Amount to send",
      "value": "50000"
    }
  ],
  "fieldsToConfirmOrder": []
}
```

{% endcode %}

Send the user to `paymentUrl`. Some redirect offers also ask you for a `redirectUrl` in `fieldsToCreateOrder` — the page to bring them back to when they finish.

### Example of the ussd transfer

The shape is implemented but no live offer serves it right now, so treat this as future-proofing rather than something to test against:

{% code overflow="wrap" %}

```json
{
  "type": "ussd",
  "ussdCode": "*234*1*9670555843*14800#",
  "instructionsText": "Dial the code below on your phone to complete the transfer.",
  "transferDetails": [
    {
      "id": "amountToSend",
      "label": "Amount to send",
      "value": "14800"
    }
  ],
  "fieldsToConfirmOrder": []
}
```

{% endcode %}

Show `ussdCode` and let the user dial it. No prompt arrives — they start the transfer themselves from the handset.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.fonbnk.com/server-to-server/integration-guide/transfer-types-explanation.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
