> For the complete documentation index, see [llms.txt](https://qosic.gitbook.io/qospay/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://qosic.gitbook.io/qospay/merchant-api/payments/transfers-and-bill-payments.md).

# transfers and bill payments

Le même endpoint gère deux types d’opérations configurés :

* Un opérateur `CollectionAndFundsTransfer` crée une transaction `FundTransfer`.
* Un opérateur `BillsPayment` crée une transaction `BillsPayment`.

Ne déterminez pas le type à partir de votre propre liste codée en dur ; utilisez `providerServiceType` retourné par la découverte des opérateurs.

## Exemple de transfert bancaire

```http
POST /api/v1/payment/funds-transfer/initiate HTTP/1.1
Host: api.example.com
Authorization: Bearer <access-token>
Accept: application/json
Content-Type: application/json

{
  "accountNumber": "0123456789",
  "accountName": "JOHN DOE",
  "msisdn": "2348012345678",
  "countryCode": "NG",
  "operatorId": "SAYSWITCH",
  "amount": "5000.00",
  "narration": "Invoice 1042 payout",
  "transRef": "FT-20260810-000001",
  "productCode": "058",
  "emailId": "john@example.com",
  "extendedProperties": null,
  "currencyCode": "NGN"
}
```

```bash
curl --request POST "https://api.example.com/api/v1/payment/funds-transfer/initiate" \
  --header "Authorization: Bearer ${QOS_ACCESS_TOKEN}" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --data '{
    "accountNumber": "0123456789",
    "accountName": "JOHN DOE",
    "msisdn": "2348012345678",
    "countryCode": "234",
    "operatorId": "NGPAY",
    "amount": "5000.00",
    "narration": "Invoice 1042 payout",
    "transRef": "FT-20260810-000001",
    "productCode": "058",
    "emailId": "john@example.com",
    "extendedProperties": null,
    "currencyCode": "NGN"
  }'
```

## Exemple de paiement de facture

```json
{
  "accountNumber": "12345678901",
  "accountName": "ADA OKAFOR",
  "msisdn": "2348012345678",
  "countryCode": "NG",
  "operatorId": "ELECTRICITY",
  "amount": "5000.00",
  "narration": "Prepaid meter purchase",
  "transRef": "BILL-20260810-000001",
  "productCode": "ELEC_PREPAID",
  "emailId": "ada@example.com",
  "extendedProperties": "{\"meterNumber\":\"12345678901\",\"meterType\":\"PREPAID\"}",
  "currencyCode": "NGN"
}
```

`extendedProperties` est une chaîne. Lorsqu’un opérateur exige des valeurs supplémentaires structurées, sérialisez l’objet JSON requis par le provider dans cette chaîne, comme dans l’exemple ci-dessus.

### Champs de la requête

| Champ                | Obligatoire                                             | Description                                                                                                                  |
| -------------------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `accountNumber`      | Conditionnel                                            | Compte de destination, compteur ou compte client. Au moins ce champ ou `msisdn` doit être non nul.                           |
| `accountName`        | Selon le provider                                       | Nom validé du bénéficiaire ou du client. Requis par le parcours actuel de transfert bancaire Sayswitch.                      |
| `msisdn`             | Conditionnel                                            | Numéro mobile de l’abonné/destinataire. Au moins ce champ ou `accountNumber` doit être non nul.                              |
| `countryCode`        | Oui                                                     | Pays retourné par la découverte des opérateurs.                                                                              |
| `operatorId`         | Oui                                                     | Opérateur retourné par la découverte.                                                                                        |
| `amount`             | Oui                                                     | Chaîne décimale positive sans séparateur ni symbole de devise.                                                               |
| `narration`          | Selon le provider                                       | Motif lisible de l’opération. Requis par le parcours actuel de transfert bancaire Sayswitch. Évitez les données sensibles.   |
| `transRef`           | Oui                                                     | Référence unique de transaction marchand.                                                                                    |
| `productCode`        | Selon le provider                                       | Code banque ou produit obtenu via la découverte des produits. Requis par le parcours actuel de transfert bancaire Sayswitch. |
| `emailId`            | Non                                                     | E-mail client utilisé par les providers compatibles.                                                                         |
| `extendedProperties` | Selon le provider                                       | Chaîne JSON sérialisée contenant les valeurs spécifiques à l’opérateur.                                                      |
| `currencyCode`       | Conditionnel lors de la validation, toujours recommandé | Requis pour les opérateurs de collecte/transfert et validé lorsqu’il est fourni. Envoyez toujours la devise découverte.      |

{% hint style="warning" %}
Le DTO traite une chaîne vide différemment de `null` lors de la validation de la destination. Envoyez une vraie valeur dans le champ de destination requis ; n’envoyez pas les deux champs sous forme de chaînes vides.
{% endhint %}

## Réponse réussie — HTTP 200

```json
{
  "data": {
    "code": "00",
    "message": "Transfer successful",
    "status": "SUCCESSFUL",
    "transRef": "FT-20260810-000001",
    "providerReference": "PRV-93284723",
    "amount": "5000.00",
    "accountNumber": "0123456789",
    "msisdn": "2348012345678",
    "accountName": "JOHN DOE",
    "narration": "Invoice 1042 payout",
    "responseData": "{\"sessionId\":\"000123456789\",\"status\":\"SUCCESSFUL\"}",
    "providerHttpStatusCode": 200
  },
  "message": "Success",
  "success": true,
  "responseCode": "00"
}
```

`responseData` est une chaîne et peut contenir du JSON provider sérialisé. Conservez-la à des fins de diagnostic, mais basez le rapprochement sur `transRef`, `providerReference` et l’endpoint de statut.

{% hint style="warning" %}
Le wallet marchand est débité avant l’appel au provider. En cas d’échec provider certain, l’API tente une annulation automatique. Lorsque le résultat final du provider ne peut pas être déterminé, la transaction peut passer à `REVERSAL_REVIEW_REQUIRED`. Ne réessayez jamais ce paiement métier avec une nouvelle référence tant que la transaction d’origine n’est pas résolue.
{% endhint %}
