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

# Accept crypto payments

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

```go
inv, err := c.PayIns.Create(ctx, &cryptochief.CreatePayInRequest{
    OrderID:      "invoice-1001",
    UserID:       "u-7",
    Mode:         cryptochief.PayInModeCrypto,
    AmountCrypto: "10.0",
    Asset: &cryptochief.Asset{
        Coin:    "USDT",
        Network: cryptochief.ChainTronMainnet,
    },
    URLCallback: "https://your.app/webhooks/payin",
})
if err != nil {
    log.Fatal(err)
}

fmt.Println("pay to:", inv.ToAddress)
fmt.Println("payment link:", inv.PaymentLink)
```

## Fiat mode

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

```go
inv, _ := c.PayIns.Create(ctx, &cryptochief.CreatePayInRequest{
    OrderID:     "invoice-1002",
    Mode:        cryptochief.PayInModeFiat,
    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:

```go
paid, _ := c.PayIns.SelectAsset(ctx, &cryptochief.SelectAssetRequest{
    UUID:    inv.UUID,
    Coin:    "USDT",
    Network: cryptochief.ChainTronMainnet,
})
fmt.Println("pay to:", paid.ToAddress, paid.AmountCrypto, paid.PaymentCoin)
```

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

## Mainnet or testnet

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

```go
inv, _ := c.PayIns.Create(ctx, &cryptochief.CreatePayInRequest{
    OrderID:     "invoice-1003",
    Mode:        cryptochief.PayInModeFiat,
    AmountFiat:  "49.99",
    Currency:    "USD",
    Environment: cryptochief.EnvironmentTestnet,
})
```

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.

## Pin the master wallet

`MasterWalletAddress` decides which of your master wallets this order's deposit is ultimately swept to. Without it the platform picks, and on a project with more than one master that is the oldest of the chain family rather than the one you had in mind.

```go
inv, _ := c.PayIns.Create(ctx, &cryptochief.CreatePayInRequest{
    OrderID:             "invoice-1004",
    UserID:              "u-7",
    Mode:                cryptochief.PayInModeCrypto,
    AmountCrypto:        "10.0",
    Asset:               &cryptochief.Asset{Coin: "USDT", Network: cryptochief.ChainTronMainnet},
    MasterWalletAddress: masterAddress,
    URLCallback:         "https://your.app/webhooks/payin",
})
```

The master has to match the payment network's chain family; an invalid or foreign one is refused with `400` rather than resolved. Pinning one also narrows a multi-asset order to that family's assets, so a fiat-mode order pinned to a TRON master offers TRON assets only. `SelectAsset` carries the same field, and a value there overrides one given at create — which is how an order whose network is unknown until the customer picks still lands on the master you want.

{% hint style="info" %}
Memo/tag families such as XRPL honour the preference too: one shared tagged deposit wallet per master, with orders told apart by their destination tag. It is validated but not applied when you supply `ToAddress`, because that flow mints no deposit wallet.
{% endhint %}

## Track the order

```go
order, _ := c.PayIns.Info(ctx, inv.UUID)
if order.Succeeded() { // status == "paid"
    // fulfill the order
}
```

You can also `Cancel`, `ResetAsset` (revert to asset selection), and page through `History`. Prefer reacting to the `invoice.*` [webhook](/processing/go/guides/webhooks.md) over polling.

When all you have is the deposit address — a payer who paid and cannot name the order — `c.Wallets.PayInHistory` returns the same records for one address. See [The pay-ins one address received](/processing/go/guides/wallets.md#the-pay-ins-one-address-received).

## Order lifecycle

`waiting_asset_select` → `pending` → `processing` → **`paid`** (terminal). Terminal failures are `cancel` and `expired`. Check with `order.IsTerminal()` / `order.Succeeded()`.
