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

# Python SDK

> Install and use the LigdiCash Python SDK in your Django, Flask, FastAPI backends or server scripts.

The LigdiCash Python SDK exposes three main objects — `Invoice`, `Withdrawal`, and `get_transaction` — covering every payment flow. Unlike the other SDKs, initialization uses module-level globals, not a class instance.

## Installation

```bash theme={null}
pip install ligdicash
```

**Requirements**: Python ≥ 3.0. The `requests` dependency is installed automatically.

## Initialization

```python Python theme={null}
import ligdicash

ligdicash.api_key   = "{API_KEY}"
ligdicash.auth_token = "{AUTH_TOKEN}"
ligdicash.platform  = "live"
```

Get your `api_key` and `auth_token` from the [LigdiCash dashboard](https://dashboard.ligdicash.com) by creating an API project.

***

## Hosted payin

The customer is redirected to the LigdiCash-hosted payment page. This is the recommended flow for online stores.

```python Python theme={null}
import ligdicash

# 1. Describe the invoice
invoice = ligdicash.Invoice(
    currency="xof",
    description="Order #ORD-20240512",
    customer_firstname="Amadou",
    customer_lastname="Ouedraogo",
    customer_email="amadou@example.com",
    store_name="MySuperStore",
    store_website_url="https://mysuperstore.com",
)

# 2. Add items
invoice.add_item(name="Kente shirt", description="Size M", quantity=2, unit_price=15000)
invoice.add_item(name="Shipping fee", description="", quantity=1, unit_price=1500)

# 3. Start the payment
response = invoice.pay_with_redirection(
    return_url="https://mysuperstore.com/order/success",
    cancel_url="https://mysuperstore.com/order/cancel",
    callback_url="https://backend.mysuperstore.com/ligdicash/callback",
    custom_data={"transaction_id": "ORD-20240512"},
)

# 4. Redirect the customer
payment_url = response.response_text
redirect_user(payment_url)
```

<Warning>
  Never open `payment_url` in an iframe — LigdiCash blocks it. Redirect in the same tab, a new tab, or a popup. On native mobile, use a WebView.
</Warning>

<Tip>
  Always leave `customer` empty in hosted payin (this is the default). If you pass a number, LigdiCash filters the payment page to show only the operators tied to that number.
</Tip>

***

## Direct payin

The customer pays directly from your interface. You must collect their phone number and, depending on the operator, their OTP code.

```python Python theme={null}
import ligdicash

# 1. Describe the invoice (same as hosted payin)
invoice = ligdicash.Invoice(
    currency="xof",
    description="Order #ORD-20240512",
    customer_firstname="Amadou",
    customer_lastname="Ouedraogo",
    customer_email="amadou@example.com",
    store_name="MySuperStore",
    store_website_url="https://mysuperstore.com",
)
invoice.add_item(name="Kente shirt", description="Size M", quantity=2, unit_price=15000)

# 2. Start the payment (with OTP provided by the customer)
response = invoice.pay_without_redirection(
    otp="123456",             # OTP code entered by the customer
    customer="22670123456",   # Customer phone number, no + or spaces
    callback_url="https://backend.mysuperstore.com/ligdicash/callback",
    custom_data={"transaction_id": "ORD-20240512"},
)

# 3. Store the token for later verification
token = response.token
```

<Note>
  The OTP mode varies by operator. For example, with a USSD operator, the customer generates the OTP on their phone **before** you submit. For an approval-mode operator (e.g. Moov Africa), send `otp=""` — the customer approves directly in their app. See the [operator page](/en/payment-api/direct-payin/introduction) for details.
</Note>

***

## Payout

Send money to a customer — refund, salary, payout.

### To the customer's LigdiCash wallet

```python Python theme={null}
import ligdicash

withdrawal = ligdicash.Withdrawal(
    amount=5000,
    description="Refund for order ORD-20240510",
    customer="22670123456",
)

response = withdrawal.send(
    type="client",
    to_wallet=False,   # False = automatic transfer to the linked mobile money account
    callback_url="https://backend.mysuperstore.com/ligdicash/callback-payout",
    custom_data={"transaction_id": "REFUND-20240512"},
)

token = response.token
```

### Directly to mobile money

```python Python theme={null}
response = withdrawal.send(
    type="merchant",   # Direct payout, no intermediate wallet
    callback_url="https://backend.mysuperstore.com/ligdicash/callback-payout",
    custom_data={"transaction_id": "PAY-20240512"},
)
```

<Note>
  `type="client"` uses the `POST /pay/v01/withdrawal/create` endpoint (via the LigdiCash wallet). `type="merchant"` uses `POST /pay/v01/straight/payout` (direct mobile money, slower). See [Payout — Introduction](/en/payment-api/payout/introduction).
</Note>

***

## Status verification

Call `get_transaction` with the token stored at **creation** (not the callback token, which is different).

```python Python theme={null}
import ligdicash

token = "eyJ0eXAiOiJ..."   # Token returned at creation

# Payin
transaction = ligdicash.get_transaction(token, "payin")

# Client payout (withdrawal/create)
# transaction = ligdicash.get_transaction(token, "client_payout")

# Merchant payout (straight/payout)
# transaction = ligdicash.get_transaction(token, "merchant_payout")

if transaction.status == "completed":
    # Deliver the order / validate the payment
    pass
elif transaction.status == "pending":
    # Payment in progress — retry in a few seconds
    pass
else:
    # Payment failed or cancelled
    pass
```

**Fields available on `transaction`:**

| Attribute       | Type   | Description                               |
| --------------- | ------ | ----------------------------------------- |
| `status`        | `str`  | `"completed"`, `"pending"`, `"cancelled"` |
| `response_code` | `str`  | `"00"` success, `"01"` failure            |
| `amount`        | `int`  | Transaction amount                        |
| `operator_id`   | `str`  | Operator identifier                       |
| `operator_name` | `str`  | Operator name                             |
| `customer`      | `str`  | Customer phone number                     |
| `token`         | `str`  | Transaction token                         |
| `custom_data`   | `dict` | Custom data sent at creation              |
| `wiki`          | `list` | Links to the endpoint's error codes       |

<Warning>
  Never deliver an order solely based on an incoming callback. Always call `get_transaction` with the token stored at creation to confirm the status on the LigdiCash server side. See [Callback security](/en/payment-api/callback/security).
</Warning>

***

## Error handling

Every error inherits from `ligdicash.LigdicashError` and exposes `.code` and `.message`.

```python Python theme={null}
import ligdicash

try:
    response = invoice.pay_with_redirection(
        return_url="https://mysuperstore.com/success",
        cancel_url="https://mysuperstore.com/cancel",
        callback_url="https://backend.mysuperstore.com/callback",
        custom_data={"transaction_id": "ORD-20240512"},
    )
except ligdicash.AuthenticationError as e:
    # Invalid API key or authentication token
    print(e.message)
except ligdicash.MerchantPayinDisabledError as e:
    # Payin not enabled for this project
    print(e.message)
except ligdicash.InvalidAmountError as e:
    # Amount outside the [20; 1,000,000] CFA francs range
    print(e.message)
except ligdicash.LigdicashError as e:
    # Any other LigdiCash error
    print(f"{e.code}: {e.message}")
```

**Available error classes:**

| Class                                 | Raised when                               |
| ------------------------------------- | ----------------------------------------- |
| `AuthenticationError`                 | `api_key` or `auth_token` invalid         |
| `ApplicationAuthenticationError`      | Application not authenticated             |
| `MerchantPayinDisabledError`          | Payin not enabled on the project          |
| `MerchantPayoutDisabledError`         | Payout not enabled on the project         |
| `MerchantBalanceLowError`             | Merchant balance too low                  |
| `CustomerDoesNotExistError`           | Customer not registered on the platform   |
| `InvalidAmountError`                  | Amount outside the \[20; 1,000,000] range |
| `InvalidTokenError`                   | Invalid or missing token                  |
| `InvoiceNotFoundError`                | Invoice not found                         |
| `TransactionAlreadyExistError`        | Transaction already created               |
| `RecipientOperatorNotIdentifiedError` | Recipient's operator not identified       |
| `FeatureNotTestableError`             | Feature unavailable in `"test"` mode      |

***

## Useful links

* [Hosted payin — Introduction](/en/payment-api/hosted-payin/introduction)
* [Direct payin — Authentication modes](/en/payment-api/direct-payin/validation-modes)
* [Payout — Introduction](/en/payment-api/payout/introduction)
* [Callback security](/en/payment-api/callback/security)
* [transaction\_id pattern](/en/concepts/transaction-id-pattern)
* [ligdicash PyPI package](https://pypi.org/project/ligdicash/)
