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

# Vérifier le statut d'une transaction

> Endpoint GET /pay/v01/redirect/checkout-invoice/confirm — comment vérifier qu'une facture a bien été payée après redirection ou callback.

L'endpoint `confirm` permet de vérifier le statut d'une facture à partir du `token` obtenu à la création. Appelez-le depuis votre **backend** — après la redirection vers `return_url`, ou depuis votre handler de callback avant d'honorer la commande.

```
GET https://app.ligdicash.com/pay/v01/redirect/checkout-invoice/confirm
```

## Headers

<ParamField header="Apikey" type="string" required>
  La clé API de votre projet LigdiCash.
</ParamField>

<ParamField header="Authorization" type="string" required>
  Votre API TOKEN précédé de `Bearer `. Exemple : `Bearer eyJ0eXAiOiJKV1Qi...`
</ParamField>

<ParamField header="Accept" type="string" required>
  Doit être `application/json`.
</ParamField>

## Paramètres

<ParamField query="token" type="string" required>
  Le token retourné par l'endpoint `create` au moment de la création de la facture.
</ParamField>

<Warning>
  Le `token` reçu dans le payload du callback est **différent** du token de création. Les deux permettent d'appeler `confirm`, mais seul le token de création vous permet de faire la réconciliation avec votre commande côté marchand.
</Warning>

## Exemple de requête

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://app.ligdicash.com/pay/v01/redirect/checkout-invoice/confirm?token={TOKEN}" \
    -H "Apikey: {API_KEY}" \
    -H "Authorization: Bearer {API_TOKEN}" \
    -H "Accept: application/json"
  ```

  ```javascript Node.js theme={null}
  const token = "eyJ0eXAiOiJKV1Qi..."; // token stocké à la création

  const response = await fetch(
    `https://app.ligdicash.com/pay/v01/redirect/checkout-invoice/confirm?token=${token}`,
    {
      method: "GET",
      headers: {
        Apikey: process.env.LIGDICASH_API_KEY,
        Authorization: `Bearer ${process.env.LIGDICASH_API_TOKEN}`,
        Accept: "application/json",
      },
    }
  );

  const data = await response.json();
  ```

  ```php PHP theme={null}
  $token = "eyJ0eXAiOiJKV1Qi..."; // token stocké à la création

  $ch = curl_init(
    "https://app.ligdicash.com/pay/v01/redirect/checkout-invoice/confirm?token=" . urlencode($token)
  );
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Apikey: " . $_ENV["LIGDICASH_API_KEY"],
    "Authorization: Bearer " . $_ENV["LIGDICASH_API_TOKEN"],
    "Accept: application/json",
  ]);

  $data = json_decode(curl_exec($ch), true);
  curl_close($ch);
  ```
</CodeGroup>

## Champs de réponse

<ResponseField name="response_code" type="string">
  `"00"` si l'appel API a abouti, `"01"` en cas d'erreur technique. Ce champ indique le succès de la requête `confirm`, pas le résultat du paiement — utilisez `status` pour cela.
</ResponseField>

<ResponseField name="status" type="string">
  Statut du paiement. Voir le tableau ci-dessous.
</ResponseField>

<ResponseField name="token" type="string">
  Peut être vide dans la réponse `confirm`.
</ResponseField>

<ResponseField name="response_text" type="string">
  Message complémentaire ou sous-code d'erreur au format `Echec (CodeXX)`. Consulter `wiki` pour la description. Vide si aucune erreur.
</ResponseField>

<ResponseField name="description" type="string">
  Description libre de la transaction. Peut être vide.
</ResponseField>

<ResponseField name="operator_id" type="string">
  Identifiant numérique de l'opérateur utilisé pour le paiement. Exemple : `"14"` pour Moov CI. Vide si le statut est `pending`.
</ResponseField>

<ResponseField name="operator_name" type="string">
  Nom de l'opérateur. Exemple : `"MOOV CI"`. Vide si le statut est `pending`.
</ResponseField>

<ResponseField name="customer" type="string | null">
  Numéro de téléphone du payeur au format `226XXXXXXXXX`. Peut être `null` si le paiement est encore en attente.
</ResponseField>

<ResponseField name="montant" type="integer">
  Montant de la transaction en XOF.
</ResponseField>

<ResponseField name="amount" type="integer">
  Identique à `montant`. Les deux champs sont toujours présents et ont la même valeur.
</ResponseField>

<ResponseField name="date" type="string">
  Date et heure de la transaction au format `YYYY-MM-DD HH:MM:SS+TZ`. Exemple : `"2026-04-15 11:19:28+00"`.
</ResponseField>

<ResponseField name="external_id" type="string">
  Concaténation des `valueof_customdata` dont la clé (`keyof_customdata`) contient `"id"`, séparés par `;`. Correspond à la valeur de votre `transaction_id` si vous suivez le pattern recommandé.
</ResponseField>

<ResponseField name="oreference" type="string">
  Référence opérateur. Peut être vide.
</ResponseField>

<ResponseField name="request_id" type="string">
  Identifiant unique de la requête côté LigdiCash. Utile pour le support.
</ResponseField>

<ResponseField name="custom_data" type="array">
  Vos métadonnées telles que transmises à la création, enrichies par LigdiCash (qui y ajoute notamment `logfile`). Chaque entrée contient :

  <Expandable title="Champs d'une entrée custom_data">
    <ResponseField name="keyof_customdata" type="string">La clé. Exemple : `"transaction_id"`. LigdiCash y ajoute ses propres entrées (`logfile`).</ResponseField>
    <ResponseField name="valueof_customdata" type="string">La valeur associée.</ResponseField>
    <ResponseField name="datecreation_customdata" type="string">Date de création de l'entrée au format `YYYY-MM-DD HH:MM:SS.microseconds`.</ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="customer_details" type="object">
  Informations du client saisies lors du paiement.

  <Expandable title="Champs de customer_details">
    <ResponseField name="firstname" type="string">Prénom.</ResponseField>
    <ResponseField name="lastname" type="string">Nom.</ResponseField>
    <ResponseField name="email" type="string">Email. Peut être vide.</ResponseField>
    <ResponseField name="phone" type="string">Numéro de téléphone. Peut être vide si statut `pending`.</ResponseField>
    <ResponseField name="details" type="string">Informations complémentaires. Peut être vide.</ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="wiki" type="string">
  URL vers la documentation des codes d'erreur de cet endpoint. À consulter quand `response_code` vaut `"01"`.
</ResponseField>

## Valeurs de `status`

| `status`       | Signification                          | Action recommandée                         |
| -------------- | -------------------------------------- | ------------------------------------------ |
| `completed`    | Paiement confirmé                      | Honorer la commande                        |
| `pending`      | En attente de confirmation opérateur   | Patienter, recheck ou attendre le callback |
| `notcompleted` | Paiement non abouti (annulé ou échoué) | Proposer de réessayer                      |

## Exemple de réponse

<CodeGroup>
  ```json Succès (completed) theme={null}
  {
    "response_code": "00",
    "token": "",
    "response_text": "",
    "description": "",
    "custom_data": [
      {
        "keyof_customdata": "transaction_id",
        "valueof_customdata": "BPBF-1776251968907",
        "datecreation_customdata": "2026-04-15 11:19:28.977757"
      },
      {
        "keyof_customdata": "logfile",
        "valueof_customdata": "2026041511192869df7440ed917",
        "datecreation_customdata": "2026-04-15 11:19:28.977757"
      }
    ],
    "status": "completed",
    "operator_id": "14",
    "operator_name": "MOOV CI",
    "customer": "2250171584035",
    "wiki": "https://client.ligdicash.com/wiki/confirmInvoice",
    "montant": 100,
    "amount": 100,
    "date": "2026-04-15 11:19:28+00",
    "external_id": "BPBF-1776251968907",
    "oreference": "",
    "customer_details": {
      "firstname": "ClémenceIlaria",
      "lastname": "Ouedraogo",
      "email": "clemenceilaria369@gmail.com",
      "phone": "2250171584035",
      "details": ""
    },
    "request_id": "P2771491712026"
  }
  ```

  ```json En attente (pending) theme={null}
  {
    "response_code": "00",
    "token": "",
    "response_text": "",
    "description": "",
    "custom_data": [
      {
        "keyof_customdata": "transaction_id",
        "valueof_customdata": "BPBF-1776876662551",
        "datecreation_customdata": "2026-04-22 16:51:02.660483"
      },
      {
        "keyof_customdata": "logfile",
        "valueof_customdata": "2026042216510269e8fc76a0292",
        "datecreation_customdata": "2026-04-22 16:51:02.660483"
      }
    ],
    "status": "pending",
    "operator_id": "",
    "operator_name": "",
    "customer": null,
    "wiki": "https://client.ligdicash.com/wiki/confirmInvoice",
    "montant": 100,
    "amount": 100,
    "date": "2026-04-22 16:51:02+00",
    "external_id": "BPBF-1776876662551",
    "oreference": "",
    "customer_details": {
      "firstname": "Ousmane",
      "lastname": "Konaté",
      "email": "",
      "phone": "",
      "details": ""
    },
    "request_id": "P2773475652026"
  }
  ```

  ```json Non abouti (notcompleted) theme={null}
  {
    "response_code": "00",
    "token": "",
    "response_text": "",
    "description": "",
    "custom_data": [
      {
        "keyof_customdata": "transaction_id",
        "valueof_customdata": "BPBF-1776876662551",
        "datecreation_customdata": "2026-04-22 16:51:02.660483"
      }
    ],
    "status": "notcompleted",
    "operator_id": "",
    "operator_name": "",
    "customer": null,
    "wiki": "https://client.ligdicash.com/wiki/confirmInvoice",
    "montant": 100,
    "amount": 100,
    "date": "2026-04-22 16:51:02+00",
    "external_id": "BPBF-1776876662551",
    "oreference": "",
    "customer_details": {
      "firstname": "",
      "lastname": "",
      "email": "",
      "phone": "",
      "details": ""
    },
    "request_id": "P2773475652026"
  }
  ```

  ```json Erreur API theme={null}
  {
    "response_code": "01",
    "token": "",
    "response_text": "Echec (Code01)",
    "description": "",
    "custom_data": [],
    "status": "",
    "operator_id": "",
    "operator_name": "",
    "customer": null,
    "wiki": "https://client.ligdicash.com/wiki/confirmInvoice",
    "montant": 0,
    "amount": 0,
    "date": "",
    "external_id": "",
    "oreference": "",
    "customer_details": {
      "firstname": "",
      "lastname": "",
      "email": "",
      "phone": "",
      "details": ""
    },
    "request_id": ""
  }
  ```
</CodeGroup>

## Lire `custom_data` dans la réponse

`custom_data` retourne un tableau de vos métadonnées enrichi par LigdiCash (qui y ajoute notamment `logfile`). Pour retrouver votre `transaction_id` :

```javascript JavaScript theme={null}
const entry = data.custom_data.find(
  (item) => item.keyof_customdata === "transaction_id"
);
const transactionId = entry?.valueof_customdata;
```

<Tip>
  Consultez [Parser custom\_data](/api-paiement/callback/parser-custom-data) pour le traitement complet, notamment les cas où `custom_data` est un tableau vide ou une chaîne vide.
</Tip>

## Quand appeler `confirm` ?

**1. Après la redirection vers `return_url`**

Depuis votre frontend, déclenchez un appel à votre backend, qui appelle `confirm` avec le token stocké. N'appelez jamais `confirm` directement depuis le navigateur — vos clés API seraient exposées.

**2. Dans votre handler de callback**

Avant d'honorer une commande suite à un callback, re-vérifiez toujours le statut avec `confirm`. Un faux payload peut être envoyé par n'importe qui connaissant l'URL de votre endpoint.

## Pattern de polling

Si le callback n'est pas disponible ou tarde à arriver, interrogez `confirm` à intervalles réguliers :

```javascript JavaScript theme={null}
async function attendreConfirmation(token, { intervalle = 4000, maxTentatives = 10 } = {}) {
  for (let i = 0; i < maxTentatives; i++) {
    const data = await appellerConfirm(token);

    if (data.status === "completed") return { success: true, data };
    if (data.status === "notcompleted") return { success: false, data };

    await new Promise((r) => setTimeout(r, intervalle));
  }
  return { success: false, reason: "timeout" };
}
```

<Note>
  Le polling est un filet de sécurité, pas la stratégie principale. Privilégiez toujours le callback. Consultez [Polling vs callback](/api-paiement/verification-statut/polling-vs-callback) pour les arbitrages.
</Note>

## Pages associées

* [Rediriger le client](/api-paiement/payin-redirect/rediriger-client) — obtenir le token de création
* [Callback — sécurisation](/api-paiement/callback/securisation) — pourquoi toujours re-vérifier
* [Parser custom\_data](/api-paiement/callback/parser-custom-data) — lire les métadonnées en toute sécurité
* [Polling vs callback](/api-paiement/verification-statut/polling-vs-callback) — choisir la bonne stratégie
* [Codes de réponse et statuts](/concepts/codes-reponse-statuts) — référence complète
