> For the complete documentation index, see [llms.txt](https://docs-sdk.crypto-chief.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs-sdk.crypto-chief.com/processing/python/guides/accept-payments.md).

# Accept crypto payments

Accept incoming crypto payments in Python by creating PayIn orders (invoices).

A **PayIn** is an incoming-payment order (an invoice). Create one, show the customer the deposit address or payment link, and receive a webhook when it's paid.

There are two modes:

* **`crypto`** — fix the exact coin, network, and amount upfront.
* **`fiat`** — price the order in fiat and let the customer pick the asset at payment time.

## Crypto mode

```python
from cryptochief import Chain, CreatePayInRequest, PayInMode, Asset

inv = await client.pay_ins.create(CreatePayInRequest(
    order_id="invoice-1001",
    user_id="u-7",
    mode=PayInMode.CRYPTO,
    amount_crypto="10.0",
    asset=Asset(coin="USDT", network=Chain.TRON_MAINNET),
    url_callback="https://your.app/webhooks/payin",
))

print("pay to:", inv.to_address)
print("payment link:", inv.payment_link)
```

## Fiat mode

Price in fiat; the customer chooses the coin/network when they pay.

```python
inv = await client.pay_ins.create(CreatePayInRequest(
    order_id="invoice-1002",
    user_id="u-7",
    mode=PayInMode.FIAT,
    amount_fiat="49.99",
    currency="USD",
    url_callback="https://your.app/webhooks/payin",
))
# inv.status == "waiting_asset_select"; inv.coins lists the offered options.
```

When the customer picks an asset, commit it to get the address and final crypto amount:

```python
from cryptochief import SelectAssetRequest

paid = await client.pay_ins.select_asset(SelectAssetRequest(
    uuid=inv.uuid,
    coin="USDT",
    network=Chain.TRON_MAINNET,
))
print("pay to:", paid.to_address, paid.amount_crypto, paid.payment_coin)
```

{% hint style="info" %}
Restrict which coins are offered in fiat mode with the `assets` allow/exclude policy. Use `accuracy_payment_percent` to tolerate small under/over-payments and `lifetime_sec` to set an expiry.
{% endhint %}

`currency` takes any ISO 4217 code `client.currencies.fiats()` lists, and `client.currencies.cryptos()` is every ticker the platform has a rate for — see [what the platform can put a price on](/processing/python/concepts/chains.md#what-the-platform-can-put-a-price-on). Neither is the list of assets you can be paid in: that is `client.blockchain.contracts_available()`.

## Mainnet or testnet

An order belongs to one environment: the real chains, or the test ones. Set `environment` to `mainnet` or `testnet` on create.

```python
from cryptochief import CreatePayInRequest, Environment, PayInMode

inv = await client.pay_ins.create(
    CreatePayInRequest(
        order_id="invoice-1003",
        user_id="user-1",
        mode=PayInMode.FIAT,
        amount_fiat="49.99",
        currency="USD",
        environment=Environment.TESTNET,
    )
)
```

It changes nothing when the request names a concrete network — that is your choice. It matters exactly where the **platform** picks the asset: fiat mode, and a network of `ANY`. Without it, an unconstrained pick could put a real payment on a test network.

Omit it and the project's own default applies. A project may be allowed one environment or both; asking for testnet on a project that does not permit it is refused with `TESTNET_NOT_ALLOWED` rather than quietly served on mainnet, and a value that is neither environment is `ENVIRONMENT_INVALID` rather than a silent fallback.

{% hint style="info" %}
The same request accepts `master_wallet_address`, which pins the order's deposit wallet to one of your project's master wallets — the address these funds are ultimately swept to. The order's chain family must match the master wallet's. `select-asset` accepts it too, and a value there overrides one given at create.
{% endhint %}

## Track the order

```python
order = await client.pay_ins.info(inv.uuid)
if order.status == "paid":
    ...  # fulfill the order
```

You can also `cancel`, `reset_asset` (revert to asset selection), `wait_for` a terminal state, and page through `history`. Prefer reacting to the `invoice.*` [webhook](/processing/python/guides/webhooks.md) over polling.

## Order lifecycle

`waiting_asset_select` → `pending` → `processing` → **`paid`** (terminal). Terminal failures are `cancel` and `expired`.
