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

# Create a transaction

> Endpoint POST /pay/v01/straight/checkout-invoice/create — parameters, examples per validation mode, and response.

This endpoint initiates a payment directly from your interface. You provide the customer's phone number and, depending on the [validation mode](/en/payment-api/direct-payin/validation-modes) of the operator, either the OTP or an empty field. LigdiCash returns a token to store and triggers the validation process on the operator's side.

```
POST https://app.ligdicash.com/pay/v01/straight/checkout-invoice/create
```

<Note>
  The LigdiCash Wallet uses distinct endpoints (`/pay/v02/debitotp` and `/pay/v02/debitwallet/withotp`). See the [LigdiCash Wallet page](/en/payment-api/direct-payin/operators/ligdicash-wallet) for its specific integration.
</Note>

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

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

## Body

<ParamField body="commande" type="object" required>
  Root object of the request.

  <Expandable title="commande fields" defaultOpen={true}>
    <ParamField body="invoice" type="object" required>
      Transaction details.

      <Expandable title="invoice fields" defaultOpen={true}>
        <ParamField body="items" type="array" required>
          List of items. Can be empty (`[]`) — in that case, only `total_amount` is taken into account.

          <Expandable title="Fields of an item">
            <ParamField body="name" type="string" required>Item name.</ParamField>
            <ParamField body="description" type="string">Item description.</ParamField>
            <ParamField body="quantity" type="integer" required>Quantity.</ParamField>
            <ParamField body="unit_price" type="integer" required>Unit price in XOF.</ParamField>
            <ParamField body="total_price" type="integer" required>Line total (`unit_price × quantity`) in XOF.</ParamField>
          </Expandable>
        </ParamField>

        <ParamField body="total_amount" type="integer" required>
          Total amount in XOF (integer, no decimals).
        </ParamField>

        <ParamField body="devise" type="string" required>
          Currency. Always `XOF`.
        </ParamField>

        <ParamField body="description" type="string" required>
          Order description.
        </ParamField>

        <ParamField body="customer" type="string" required>
          Customer's mobile money phone number, without `+` or spaces. Format: `22670XXXXXXX`.
        </ParamField>

        <ParamField body="customer_firstname" type="string">
          Customer's first name.
        </ParamField>

        <ParamField body="customer_lastname" type="string">
          Customer's last name.
        </ParamField>

        <ParamField body="customer_email" type="string">
          Customer's email.
        </ParamField>

        <ParamField body="external_id" type="string" required>
          Must always be empty (`""`).
        </ParamField>

        <ParamField body="otp" type="string" required>
          OTP code, depending on the operator's validation mode:

          * **USSD OTP**: OTP generated by the customer through their USSD menu, to be filled before the call.
          * **USSD Push**, **Guided USSD**, **SMS OTP (1st request)**: leave empty (`""`).
          * **SMS OTP (2nd request)**: OTP received by the customer by SMS.
        </ParamField>
      </Expandable>
    </ParamField>

    <ParamField body="store" type="object" required>
      Information about your store.

      <Expandable title="store fields" defaultOpen={true}>
        <ParamField body="name" type="string" required>Name of your store or application.</ParamField>
        <ParamField body="website_url" type="string" required>URL of your website.</ParamField>
      </Expandable>
    </ParamField>

    <ParamField body="actions" type="object" required>
      Return and notification URLs.

      <Expandable title="actions fields" defaultOpen={true}>
        <ParamField body="cancel_url" type="string" required>Leave empty (`""`).</ParamField>
        <ParamField body="return_url" type="string" required>Leave empty (`""`).</ParamField>

        <ParamField body="callback_url" type="string" required>
          URL of your backend endpoint for status notifications. Must be publicly accessible.
        </ParamField>
      </Expandable>
    </ParamField>

    <ParamField body="custom_data" type="object">
      Free-form object for your metadata. LigdiCash returns it to you in the callback. Use it to pass your `transaction_id`.
    </ParamField>
  </Expandable>
</ParamField>

## Request examples

The examples below show two cases depending on the validation mode. Only the `otp` field changes.

<CodeGroup>
  ```bash cURL — USSD OTP (otp filled) theme={null}
  curl -X POST https://app.ligdicash.com/pay/v01/straight/checkout-invoice/create \
    -H "Apikey: {API_KEY}" \
    -H "Authorization: Bearer {API_TOKEN}" \
    -H "Accept: application/json" \
    -H "Content-Type: application/json" \
    -d '{
      "commande": {
        "invoice": {
          "items": [],
          "total_amount": 5000,
          "devise": "XOF",
          "description": "Pro Subscription — January 2025",
          "customer": "22670000000",
          "customer_firstname": "Amadou",
          "customer_lastname": "Diallo",
          "customer_email": "amadou@example.com",
          "external_id": "",
          "otp": "123456"
        },
        "store": {
          "name": "MyApp",
          "website_url": "https://myapp.com"
        },
        "actions": {
          "cancel_url": "",
          "return_url": "",
          "callback_url": "https://myapp.com/api/callback/ligdicash"
        },
        "custom_data": {
          "transaction_id": "ORD-2025-00042"
        }
      }
    }'
  ```

  ```bash cURL — USSD Push / Guided USSD / SMS OTP 1st request (otp empty) theme={null}
  curl -X POST https://app.ligdicash.com/pay/v01/straight/checkout-invoice/create \
    -H "Apikey: {API_KEY}" \
    -H "Authorization: Bearer {API_TOKEN}" \
    -H "Accept: application/json" \
    -H "Content-Type: application/json" \
    -d '{
      "commande": {
        "invoice": {
          "items": [],
          "total_amount": 5000,
          "devise": "XOF",
          "description": "Pro Subscription — January 2025",
          "customer": "22670000000",
          "customer_firstname": "Amadou",
          "customer_lastname": "Diallo",
          "customer_email": "amadou@example.com",
          "external_id": "",
          "otp": ""
        },
        "store": {
          "name": "MyApp",
          "website_url": "https://myapp.com"
        },
        "actions": {
          "cancel_url": "",
          "return_url": "",
          "callback_url": "https://myapp.com/api/callback/ligdicash"
        },
        "custom_data": {
          "transaction_id": "ORD-2025-00042"
        }
      }
    }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch(
    "https://app.ligdicash.com/pay/v01/straight/checkout-invoice/create",
    {
      method: "POST",
      headers: {
        Apikey: process.env.LIGDICASH_API_KEY,
        Authorization: `Bearer ${process.env.LIGDICASH_API_TOKEN}`,
        Accept: "application/json",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        commande: {
          invoice: {
            items: [],
            total_amount: 5000,
            devise: "XOF",
            description: "Pro Subscription — January 2025",
            customer: "22670000000",
            customer_firstname: "Amadou",
            customer_lastname: "Diallo",
            customer_email: "amadou@example.com",
            external_id: "",
            otp: "", // or the OTP collected for the USSD OTP mode
          },
          store: { name: "MyApp", website_url: "https://myapp.com" },
          actions: {
            cancel_url: "",
            return_url: "",
            callback_url: "https://myapp.com/api/callback/ligdicash",
          },
          custom_data: { transaction_id: "ORD-2025-00042" },
        },
      }),
    }
  );

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

  ```php PHP theme={null}
  $otp = ""; // or the OTP collected for the USSD OTP mode

  $payload = [
    "commande" => [
      "invoice" => [
        "items" => [],
        "total_amount" => 5000,
        "devise" => "XOF",
        "description" => "Pro Subscription — January 2025",
        "customer" => "22670000000",
        "customer_firstname" => "Amadou",
        "customer_lastname" => "Diallo",
        "customer_email" => "amadou@example.com",
        "external_id" => "",
        "otp" => $otp,
      ],
      "store" => ["name" => "MyApp", "website_url" => "https://myapp.com"],
      "actions" => [
        "cancel_url" => "",
        "return_url" => "",
        "callback_url" => "https://myapp.com/api/callback/ligdicash",
      ],
      "custom_data" => ["transaction_id" => "ORD-2025-00042"],
    ],
  ];

  $ch = curl_init("https://app.ligdicash.com/pay/v01/straight/checkout-invoice/create");
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_POST, true);
  curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
  curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Apikey: " . $_ENV["LIGDICASH_API_KEY"],
    "Authorization: Bearer " . $_ENV["LIGDICASH_API_TOKEN"],
    "Accept: application/json",
    "Content-Type: application/json",
  ]);

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

## Response

<ResponseField name="response_code" type="string">
  `"00"` if the transaction was created successfully, `"01"` on error.
</ResponseField>

<ResponseField name="token" type="string">
  Identifier of the transaction on the LigdiCash side. **Store it in your database immediately** — required to call the `confirm` endpoint and re-verify the status.
</ResponseField>

<ResponseField name="response_text" type="string">
  On success: `"Votre requête est en cours de traitement"`. On failure: the error sub-code in the form `Echec (CodeXX)`.
</ResponseField>

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

## Response example

<CodeGroup>
  ```json Success theme={null}
  {
    "response_code": "00",
    "token": "eyJ0eXAiOiJKV1Qi...",
    "response_text": "Votre requête est en cours de traitement",
    "wiki": "https://client.ligdicash.com/wiki/createInvoice"
  }
  ```

  ```json Failure theme={null}
  {
    "response_code": "01",
    "token": "",
    "response_text": "Echec (Code00)",
    "wiki": "https://client.ligdicash.com/wiki/createInvoice"
  }
  ```
</CodeGroup>

<Warning>
  Store the `token` returned at creation. This is the one you will use to call `confirm` and check the final status — never rely on the token in the callback payload.
</Warning>

## Related pages

* [Validation modes](/en/payment-api/direct-payin/validation-modes) — choosing the `otp` value depending on the operator
* [Verify the status](/en/payment-api/direct-payin/verify-status) — calling `confirm` with the creation token
* [The transaction\_id pattern](/en/concepts/transaction-id-pattern) — best practices for `custom_data`
