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

# Payer une Facture

> Payer l'une des factures trouvées par une découverte

## Vue d'Ensemble

Paie une seule facture issue d'une découverte `READY`. Vous choisissez un `billId` parmi les `bills[]` de cette transaction ; la même transaction porte ensuite le paiement jusqu'à un état final.

<Warning>
  **`200` est un accusé de réception, pas un résultat.** Cela signifie que le paiement a été accepté et qu'il est désormais en cours d'acheminement. Le fait que l'argent ait réellement été déplacé n'est connaissable que par le `status` de la transaction — interrogez-la jusqu'à ce qu'elle atteigne `SUCCESS`, `FAILED` ou `REFUNDED`.
</Warning>

C'est l'appel qui déplace de l'argent. Tout ce dont vous avez besoin de votre côté — l'enregistrement de la commande, le montant, l'autorisation de votre client — doit déjà être persisté avant de l'envoyer.

## Corps de la Requête

<ParamField body="transactionId" type="string" required>
  La découverte sur laquelle payer. Doit être une chaîne hexadécimale minuscule de 24 caractères, et la transaction doit être actuellement `READY`.
</ParamField>

<ParamField body="billId" type="string" required>
  Le `billId` d'une entrée des `bills[]` de cette transaction. Maximum 100 caractères.

  Copiez-le depuis la réponse — ne le construisez pas.
</ParamField>

<ParamField body="ref" type="string" required>
  Une **nouvelle** référence pour ce paiement. Maximum 100 caractères, et unique parmi vos transactions en cours pour ce partenaire.

  Elle doit être différente de la `ref` que vous avez utilisée pour la découverte ; réutiliser cette valeur répond `403 DUPLICATED_REF`.
</ParamField>

<Note>
  La transaction conserve la `ref` avec laquelle elle a été créée. C'est cette `ref` de découverte d'origine que cet endpoint renvoie, que [Obtenir une Transaction par Référence](/fr/api-reference/bill-payment/check-by-ref) recherche, et qui apparaît désormais sur la transaction.
</Note>

## Réponse

<ResponseField name="success" type="boolean" required>
  `true` lorsque le paiement a été accepté.
</ResponseField>

<ResponseField name="data" type="object" required>
  <Expandable title="properties">
    <ResponseField name="transactionId" type="string" required>
      La même transaction, portant désormais le paiement.
    </ResponseField>

    <ResponseField name="ref" type="string" required>
      La `ref` de découverte de la transaction.
    </ResponseField>

    <ResponseField name="status" type="string" required>
      Toujours `PROCESSING` à ce stade.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="meta" type="object" required>
  <Expandable title="properties">
    <ResponseField name="timestamp" type="string" required>
      Heure de la réponse, ISO 8601 UTC.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="requestId" type="string" required>
  Identifiant de corrélation, également envoyé dans l'en-tête de réponse `X-Request-Id`.
</ResponseField>

## Exemples

<CodeGroup>
  ```bash cURL theme={null}
  curl https://billapi.oneclickdz.com/v3/bills/pay \
    -X POST \
    -H "Content-Type: application/json" \
    -H "X-Access-Token: YOUR_API_KEY" \
    -d '{
      "transactionId": "68b2f4c1a7d3e9f204c81a55",
      "billId": "sbx_bill_68b2f4c1a7d3e9f204c81a55_0",
      "ref": "pay-inv-2026-0042"
    }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch("https://billapi.oneclickdz.com/v3/bills/pay", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-Access-Token": process.env.ONECLICKDZ_API_KEY,
    },
    body: JSON.stringify({
      transactionId: "68b2f4c1a7d3e9f204c81a55",
      billId: "sbx_bill_68b2f4c1a7d3e9f204c81a55_0",
      ref: "pay-inv-2026-0042",
    }),
  });

  const body = await response.json();

  if (!body.success) {
    throw new Error(`${body.error.code}: ${body.error.message}`);
  }

  // Accepted — in flight. Poll until the status is final.
  console.log(body.data.status); // "PROCESSING"
  ```

  ```python Python theme={null}
  import os
  import requests

  response = requests.post(
      'https://billapi.oneclickdz.com/v3/bills/pay',
      headers={
          'Content-Type': 'application/json',
          'X-Access-Token': os.getenv('ONECLICKDZ_API_KEY')
      },
      json={
          'transactionId': '68b2f4c1a7d3e9f204c81a55',
          'billId': 'sbx_bill_68b2f4c1a7d3e9f204c81a55_0',
          'ref': 'pay-inv-2026-0042'
      }
  )

  body = response.json()

  if not body['success']:
      raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")

  # Accepted — in flight. Poll until the status is final.
  print(body['data']['status'])  # "PROCESSING"
  ```

  ```php PHP theme={null}
  <?php
  $payload = [
      'transactionId' => '68b2f4c1a7d3e9f204c81a55',
      'billId'        => 'sbx_bill_68b2f4c1a7d3e9f204c81a55_0',
      'ref'           => 'pay-inv-2026-0042'
  ];

  $ch = curl_init('https://billapi.oneclickdz.com/v3/bills/pay');
  curl_setopt($ch, CURLOPT_POST, true);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_HTTPHEADER, [
      'Content-Type: application/json',
      'X-Access-Token: ' . getenv('ONECLICKDZ_API_KEY')
  ]);
  curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));

  $body = json_decode(curl_exec($ch), true);
  curl_close($ch);

  if (!$body['success']) {
      throw new Exception($body['error']['code'] . ': ' . $body['error']['message']);
  }

  // Accepted — in flight. Poll until the status is final.
  echo $body['data']['status']; // "PROCESSING"
  ?>
  ```
</CodeGroup>

### Réponse de Succès

```json theme={null}
{
  "success": true,
  "data": {
    "transactionId": "68b2f4c1a7d3e9f204c81a55",
    "ref": "disc-inv-2026-0042",
    "status": "PROCESSING"
  },
  "meta": {
    "timestamp": "2026-08-31T10:15:38.410Z"
  },
  "requestId": "req_9f3a1c72e0b84d51aB3xZq07"
}
```

Une fois que la transaction atteint `SUCCESS`, [Obtenir une Transaction par ID](/fr/api-reference/bill-payment/check-by-id) retourne `operationId` et `receiptUrl` aux côtés de `selectedBill` et `total`.

## Réponses d'Erreur

<AccordionGroup>
  <Accordion title="400 — Erreur de validation">
    **Le corps ne correspondait pas au schéma.**

    ```json theme={null}
    {
      "success": false,
      "error": {
        "code": "ERR_VALIDATION",
        "message": "transactionId must be 24 characters long",
        "details": ["transactionId must be 24 characters long"]
      },
      "requestId": "req_9f3a1c72e0b84d51aB3xZq07"
    }
    ```

    Causes courantes : un `transactionId` qui ne fait pas 24 caractères hexadécimaux, un `billId` manquant, une `ref` manquante, ou une `ref` de plus de 100 caractères.

    **Que faire :** corrigez la requête. Ne la réessayez jamais telle quelle.
  </Accordion>

  <Accordion title="401 — Jeton d'accès manquant ou invalide">
    **La clé était absente ou a été rejetée.**

    ```json theme={null}
    {
      "success": false,
      "error": {
        "code": "INVALID_ACCESS_TOKEN",
        "message": "The provided access token is invalid."
      },
      "requestId": "req_9f3a1c72e0b84d51aB3xZq07"
    }
    ```

    **Que faire :** vérifiez la clé avec [Valider la Clé API](/fr/api-reference/bill-payment/validate-key). Rien n'a été débité.
  </Accordion>

  <Accordion title="403 — Référence en double">
    **La `ref` est déjà utilisée pour ce partenaire.**

    ```json theme={null}
    {
      "success": false,
      "error": {
        "code": "DUPLICATED_REF",
        "message": "A transaction with this ref already exists for this partner."
      },
      "requestId": "req_9f3a1c72e0b84d51aB3xZq07"
    }
    ```

    La cause la plus fréquente est la réutilisation de la `ref` de découverte pour le paiement. Envoyez une valeur distincte, par exemple `pay-` devant votre identifiant de commande.

    **Que faire :** avant de réessayer, vérifiez l'état actuel de la transaction avec [Obtenir une Transaction par ID](/fr/api-reference/bill-payment/check-by-id). Si elle est déjà `PROCESSING`, votre paiement est bien passé et il n'y a rien à renvoyer.
  </Accordion>

  <Accordion title="404 — Introuvable ou non payable">
    **La transaction n'existe pas pour votre compte, ou elle n'est pas dans un état payable, ou ce `billId` ne fait pas partie de ses factures.**

    ```json theme={null}
    {
      "success": false,
      "error": {
        "code": "NOT_FOUND",
        "message": "Transaction is not in a payable state, or the bill was not found."
      },
      "requestId": "req_9f3a1c72e0b84d51aB3xZq07"
    }
    ```

    Ces trois cas répondent tous `404` — y compris une transaction qui appartient à un autre partenaire, de sorte que l'API ne confirme jamais l'existence de la transaction de quelqu'un d'autre.

    **Que faire :** relisez la transaction. Si son `status` n'est plus `READY`, le paiement a déjà été démarré ; interrogez-la au lieu d'en envoyer un autre.
  </Accordion>

  <Accordion title="409 — Facture déjà payée">
    **Cette facture précise a déjà été payée.**

    ```json theme={null}
    {
      "success": false,
      "error": {
        "code": "BILL_ALREADY_PAID",
        "message": "This bill has already been paid."
      },
      "requestId": "req_9f3a1c72e0b84d51aB3xZq07"
    }
    ```

    **Que faire :** traitez-le comme un résultat positif que vous détenez déjà. Retrouvez la transaction payée dans [Lister les Transactions](/fr/api-reference/bill-payment/list-transactions) et utilisez son reçu. Ne facturez pas deux fois votre client.
  </Accordion>

  <Accordion title="409 — Paiement en cours">
    **Un autre paiement pour la même facture n'est pas terminé.**

    ```json theme={null}
    {
      "success": false,
      "error": {
        "code": "PAYMENT_IN_PROGRESS",
        "message": "A payment for this bill is currently in progress."
      },
      "requestId": "req_9f3a1c72e0b84d51aB3xZq07"
    }
    ```

    **Que faire :** interrogez la transaction déjà en cours. Renvoyer cet appel ne la fera pas se terminer plus tôt.
  </Accordion>

  <Accordion title="503 — Partenaire indisponible">
    **Le facturier est injoignable, ou est actuellement désactivé.**

    ```json theme={null}
    {
      "success": false,
      "error": {
        "code": "PARTNER_UNAVAILABLE",
        "message": "Partner temporarily unavailable — please try again later."
      },
      "requestId": "req_9f3a1c72e0b84d51aB3xZq07"
    }
    ```

    **Que faire :** rien n'a été débité. La découverte est toujours `READY`, vous pouvez donc payer le même `billId` plus tard — avec la même `ref`, qui n'a jamais été consommée.
  </Accordion>

  <Accordion title="503 — Authentification indisponible">
    **Nous n'avons pas pu vérifier votre clé à temps. Votre clé n'est pas en cause.**

    ```json theme={null}
    {
      "success": false,
      "error": {
        "code": "AUTH_UNAVAILABLE",
        "message": "Authentication is temporarily unavailable. Please retry shortly."
      },
      "requestId": "req_9f3a1c72e0b84d51aB3xZq07"
    }
    ```

    **Que faire :** attendez le `Retry-After` (5 secondes) et réessayez la même requête. La requête n'a jamais atteint le chemin de paiement, il est donc sans risque de la réessayer.
  </Accordion>

  <Accordion title="503 — Service indisponible">
    **L'API Bill Payment est en maintenance planifiée.**

    ```json theme={null}
    {
      "success": false,
      "error": {
        "code": "SERVICE_UNAVAILABLE",
        "message": "The service is temporarily unavailable. Please retry shortly."
      },
      "requestId": "req_9f3a1c72e0b84d51aB3xZq07"
    }
    ```

    **Que faire :** respectez `Retry-After` et réessayez.
  </Accordion>

  <Accordion title="500 — Erreur interne">
    **Quelque chose a échoué de notre côté.**

    ```json theme={null}
    {
      "success": false,
      "error": {
        "code": "INTERNAL_ERROR",
        "message": "An unexpected error occurred."
      },
      "requestId": "req_9f3a1c72e0b84d51aB3xZq07"
    }
    ```

    **Que faire :** **ne renvoyez pas le paiement.** Lisez d'abord la transaction — si elle est `PROCESSING`, le paiement est en cours. Contactez le support avec le `requestId` si l'état n'est pas clair.
  </Accordion>
</AccordionGroup>

## Ce que vous payez

Chaque facture d'une découverte porte ses propres champs monétaires.

| Champ    | Signification                                         |
| -------- | ----------------------------------------------------- |
| `amount` | Ce qui est dû au facturier, en DZD                    |
| `fee`    | Les frais de service OneClickDz pour le payer, en DZD |
| `total`  | `amount + fee` — le montant débité de votre solde     |

Les frais sont un pourcentage du montant, borné entre un minimum et un maximum, **défini par facturier** :

| Facturier         | Pourcentage | Minimum | Maximum |
| ----------------- | ----------- | ------- | ------- |
| `ADE`             | 0,5 %       | 30 DZD  | 60 DZD  |
| `SONELGAZ`        | 0,5 %       | 30 DZD  | 60 DZD  |
| `Algérie Télécom` | 0,5 %       | 10 DZD  | 50 DZD  |

Comme 0,5 % d'une facture courante reste largement sous le minimum, la plupart des paiements sont facturés exactement au minimum. Ces valeurs relèvent de la configuration et peuvent être ajustées : lisez donc `fee` depuis la réponse plutôt que de le recalculer. `total` apparaît sur la transaction une fois qu'une facture a été sélectionnée.

Pour la facture ADE de 443,39 DZD ci-dessus : 0,5 % vaut 2,22, soit moins que le minimum de 30 DZD, donc `fee` vaut 30,00 et `total` vaut 473,39.

## Avant d'appeler

<Steps>
  <Step title="Persistez d'abord votre propre enregistrement">
    Écrivez votre commande — client, `transactionId`, `billId`, `amount`, `fee`, `total` et la `ref` que vous êtes sur le point d'utiliser — avant que la requête ne quitte votre processus. Si la réponse est perdue, cet enregistrement est le moyen de retrouver le paiement.
  </Step>

  <Step title="Confirmez le montant avec votre client">
    `amount` et `fee` proviennent de la découverte. Affichez le `total` que vous allez débiter, pas une estimation.
  </Step>

  <Step title="Envoyez le paiement">
    Un seul appel, avec une `ref` nouvelle pour ce partenaire.
  </Step>

  <Step title="Interrogez jusqu'à l'état final">
    `SUCCESS`, `FAILED` ou `REFUNDED`. Traitez `UNKNOWN` comme « continuez à interroger », jamais comme un échec.

    → [Interrogation du statut](/fr/bill-payment-guides/4-status-polling)
  </Step>
</Steps>

## Les protections qui vous protègent

Trois règles empêchent le même argent de bouger deux fois. Toutes les trois répondent avant que quoi que ce soit ne soit débité.

| Protection          | Réponse                   | Signification                                                             |
| ------------------- | ------------------------- | ------------------------------------------------------------------------- |
| Référence en double | `403 DUPLICATED_REF`      | Cette `ref` appartient déjà à une transaction en cours pour ce partenaire |
| Déjà payée          | `409 BILL_ALREADY_PAID`   | Cette facture a déjà été payée avec succès                                |
| Paiement en vol     | `409 PAYMENT_IN_PROGRESS` | Un autre paiement pour cette facture n'est pas terminé                    |

<Warning>
  Aucune de ces trois réponses n'est une raison de réessayer avec une `ref` différente. Chacune signifie que le travail est soit déjà fait, soit déjà en cours — recherchez-le plutôt que de le renvoyer.
</Warning>

## Bonnes Pratiques

<CardGroup cols={2}>
  <Card title="Écrivez avant d'envoyer" icon="database">
    Persistez l'enregistrement de votre commande, y compris la `ref`, avant la requête. Une réponse perdue est alors récupérable.
  </Card>

  <Card title="Une ref par appel" icon="fingerprint">
    Utilisez une `ref` distincte pour la découverte et pour le paiement. `disc-` et `pay-` devant votre identifiant de commande suffisent.
  </Card>

  <Card title="Ne renvoyez jamais après un délai d'attente" icon="triangle-exclamation">
    Lisez d'abord la transaction. Un délai d'attente réseau ne signifie pas que le paiement n'a pas eu lieu.
  </Card>

  <Card title="Facturez à partir de total" icon="calculator">
    Débitez à votre client le `total` retourné par l'API, jamais un montant que vous avez calculé vous-même.
  </Card>
</CardGroup>

## Endpoints Associés

<CardGroup cols={3}>
  <Card title="Découvrir les Factures" icon="magnifying-glass-dollar" href="/fr/api-reference/bill-payment/discover-bills">
    Trouver ce qui est payable
  </Card>

  <Card title="Obtenir une Transaction par ID" icon="id-card" href="/fr/api-reference/bill-payment/check-by-id">
    Interroger le résultat
  </Card>

  <Card title="Télécharger le Reçu" icon="file-arrow-down" href="/fr/api-reference/bill-payment/get-receipt">
    Preuve de paiement
  </Card>

  <Card title="Obtenir une Transaction par Référence" icon="tag" href="/fr/api-reference/bill-payment/check-by-ref">
    Récupérer une réponse perdue
  </Card>

  <Card title="Payer les Factures" icon="money-bill-transfer" href="/fr/bill-payment-guides/3-paying-bills">
    Le guide complet
  </Card>

  <Card title="Interrogation du Statut" icon="arrows-rotate" href="/fr/bill-payment-guides/4-status-polling">
    Un interrogateur prêt pour la production
  </Card>
</CardGroup>
