> 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/php/guides/accept-payments.md).

# Accept crypto payments

Accept incoming crypto payments in PHP 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

```php
use CryptoChief\Processing\Chain;
use CryptoChief\Processing\Dto\Asset;
use CryptoChief\Processing\Dto\CreatePayInRequest;

$inv = $client->payIns()->create(new CreatePayInRequest(
    orderId:     'invoice-1001',
    userId:      'u-7',
    mode:        'crypto',
    amountCrypto: '10.0',
    asset:       new Asset(network: Chain::TronMainnet->value, coin: 'USDT'),
    urlCallback: 'https://your.app/webhooks/payin',
));

echo "pay to: {$inv->toAddress}\n";
echo "payment link: {$inv->paymentLink}\n";
```

## Fiat mode

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

```php
$inv = $client->payIns()->create(new CreatePayInRequest(
    orderId:     'invoice-1002',
    userId:      'u-7',
    mode:        'fiat',
    amountFiat:  '49.99',
    currency:    'USD',
    urlCallback: '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:

```php
use CryptoChief\Processing\Dto\SelectAssetRequest;

$paid = $client->payIns()->selectAsset(new SelectAssetRequest(
    uuid:    $inv->uuid,
    coin:    'USDT',
    network: Chain::TronMainnet->value,
));
echo "pay to: {$paid->toAddress} {$paid->amountCrypto} {$paid->paymentCoin}\n";
```

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

Build your own asset picker from `$client->blockchain()->contractsAvailable()` — what **this project** has enabled — and not from the platform-wide catalogue, which lists assets you cannot yet be paid in. See [Supported chains](/processing/php/concepts/chains.md#ask-the-platform-instead-of-the-enum).

## Mainnet or testnet

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

```php
use CryptoChief\Processing\Environment;

$inv = $client->payIns()->create(new CreatePayInRequest(
    orderId: 'invoice-1003',
    userId: 'user-1',
    mode: 'fiat',
    environment: Environment::Testnet->value,
    amountFiat: '49.99',
    currency: 'USD',
));
```

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" %}
`CreatePayInRequest` also accepts `masterWalletAddress`, 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. `SelectAssetRequest` carries the same field, and a value there overrides one given at create.
{% endhint %}

## Track the order

```php
$order = $client->payIns()->info($inv->uuid);
if ($order->status === 'paid') {
    // fulfill the order
}
```

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

Starting from a deposit address rather than an order — a payer who sent funds and can only tell you where — ask [`$client->wallets()->payInHistory()`](/processing/php/guides/wallets.md#find-the-orders-behind-an-address) instead. It returns the same `PayInHistoryResponse`, narrowed to that one address.

## Order lifecycle

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