> ## 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.

# Verify a transaction's status

> Endpoint GET /pay/v01/redirect/checkout-invoice/confirm — how to verify that an invoice was paid, after a redirect or a callback.

The `confirm` endpoint lets you verify the status of an invoice from the `token` obtained at creation. Call it from your **backend** — after the redirect to `return_url`, or from your callback handler before fulfilling the order.

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

## Headers

<ParamField header="Apikey" type="string" required>
  The API key of your LigdiCash project.
</ParamField>

<ParamField header="Authorization" type="string" required>
  Your API TOKEN prefixed with `Bearer `. Example: `Bearer eyJ0eXAiOiJKV1Qi...`
</ParamField>

<ParamField header="Accept" type="string" required>
  Must be `application/json`.
</ParamField>

## Parameters

<ParamField query="invoiceToken" type="string" required>
  The token returned by the `create` endpoint when the invoice was created.
</ParamField>

<Warning>
  The `token` received in the callback payload is **different** from the creation token. Both let you call `confirm`, but only the creation token lets you reconcile with your merchant-side order.
</Warning>

## Request example

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

  ```javascript Node.js theme={null}
  const token = "eyJ0eXAiOiJKV1Qi..."; // token stored at creation

  const response = await fetch(
    `https://app.ligdicash.com/pay/v01/redirect/checkout-invoice/confirm/?invoiceToken=${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 stored at creation

  $ch = curl_init(
    "https://app.ligdicash.com/pay/v01/redirect/checkout-invoice/confirm/?invoiceToken=" . 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>

## Response fields

<ResponseField name="response_code" type="string">
  `"00"` if the API call succeeded, `"01"` on a technical error. This field indicates the success of the `confirm` request, not the payment outcome — use `status` for that.
</ResponseField>

<ResponseField name="status" type="string">
  Payment status. See the table below.
</ResponseField>

<ResponseField name="token" type="string">
  May be empty in the `confirm` response.
</ResponseField>

<ResponseField name="response_text" type="string">
  Complementary message or error sub-code in the form `Echec (CodeXX)`. Consult `wiki` for the description. Empty if no error.
</ResponseField>

<ResponseField name="description" type="string">
  Free-form description of the transaction. Can be empty.
</ResponseField>

<ResponseField name="operator_id" type="string">
  Numeric identifier of the operator used for the payment. Example: `"14"` for Moov CI. Empty if the status is `pending`.
</ResponseField>

<ResponseField name="operator_name" type="string">
  Operator name. Example: `"MOOV CI"`. Empty if the status is `pending`.
</ResponseField>

<ResponseField name="customer" type="string | null">
  Phone number of the payer in the format `226XXXXXXXXX`. May be `null` if the payment is still pending.
</ResponseField>

<ResponseField name="montant" type="integer">
  Transaction amount in XOF.
</ResponseField>

<ResponseField name="amount" type="integer">
  Same as `montant`. Both fields are always present and hold the same value.
</ResponseField>

<ResponseField name="date" type="string">
  Date and time of the transaction in the format `YYYY-MM-DD HH:MM:SS+TZ`. Example: `"2026-04-15 11:19:28+00"`.
</ResponseField>

<ResponseField name="external_id" type="string">
  Concatenation of `valueof_customdata` values whose key (`keyof_customdata`) contains `"id"`, separated by `;`. Matches the value of your `transaction_id` if you follow the recommended pattern.
</ResponseField>

<ResponseField name="oreference" type="string">
  Operator reference. Can be empty.
</ResponseField>

<ResponseField name="request_id" type="string">
  Unique request identifier on the LigdiCash side. Useful for support.
</ResponseField>

<ResponseField name="custom_data" type="array">
  Your metadata as sent at creation, enriched by LigdiCash (which adds entries like `logfile`). Each entry contains:

  <Expandable title="Fields of a custom_data entry">
    <ResponseField name="keyof_customdata" type="string">The key. Example: `"transaction_id"`. LigdiCash adds its own entries (`logfile`).</ResponseField>
    <ResponseField name="valueof_customdata" type="string">The associated value.</ResponseField>
    <ResponseField name="datecreation_customdata" type="string">Creation date of the entry in the format `YYYY-MM-DD HH:MM:SS.microseconds`.</ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="customer_details" type="object">
  Customer information entered during payment.

  <Expandable title="customer_details fields">
    <ResponseField name="firstname" type="string">First name.</ResponseField>
    <ResponseField name="lastname" type="string">Last name.</ResponseField>
    <ResponseField name="email" type="string">Email. Can be empty.</ResponseField>
    <ResponseField name="phone" type="string">Phone number. Can be empty if status is `pending`.</ResponseField>
    <ResponseField name="details" type="string">Additional information. Can be empty.</ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="wiki" type="string">
  URL to the documentation of error codes for this endpoint. Consult when `response_code` is `"01"`.
</ResponseField>

## `status` values

| `status`       | Meaning                                          | Recommended action                      |
| -------------- | ------------------------------------------------ | --------------------------------------- |
| `completed`    | Payment confirmed                                | Fulfill the order                       |
| `pending`      | Awaiting operator confirmation                   | Wait, recheck, or wait for the callback |
| `notcompleted` | Payment did not go through (cancelled or failed) | Offer to retry                          |

## Response example

<CodeGroup>
  ```json Success (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 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 Not completed 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 API error 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>

## Reading `custom_data` in the response

`custom_data` returns an array of your metadata enriched by LigdiCash (which adds entries like `logfile`). To retrieve your `transaction_id`:

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

<Tip>
  See [Parsing custom\_data](/en/payment-api/callback/parse-custom-data) for the full processing, including cases where `custom_data` is an empty array or an empty string.
</Tip>

## When to call `confirm`

**1. After the redirect to `return_url`**

From your frontend, trigger a call to your backend, which calls `confirm` with the stored token. Never call `confirm` directly from the browser — your API keys would be exposed.

**2. In your callback handler**

Before fulfilling an order following a callback, always re-verify the status with `confirm`. A forged payload could be sent by anyone who knows your endpoint URL.

## Polling pattern

If the callback is unavailable or slow to arrive, poll `confirm` at regular intervals:

```javascript JavaScript theme={null}
async function waitForConfirmation(token, { interval = 4000, maxAttempts = 10 } = {}) {
  for (let i = 0; i < maxAttempts; i++) {
    const data = await callConfirm(token);

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

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

<Note>
  Polling is a safety net, not the primary strategy. Always prefer the callback. See [Polling vs callback](/en/payment-api/status-verification/polling-vs-callback) for trade-offs.
</Note>

## Related pages

* [Redirect the customer](/en/payment-api/hosted-payin/redirect-customer) — getting the creation token
* [Callback — security](/en/payment-api/callback/security) — why always re-verify
* [Parsing custom\_data](/en/payment-api/callback/parse-custom-data) — reading metadata safely
* [Polling vs callback](/en/payment-api/status-verification/polling-vs-callback) — choosing the right strategy
* [Response codes and statuses](/en/concepts/response-codes-and-statuses) — full reference
