# Create Payin

> Versão em Markdown da documentação pública da API v1 da Bifrost Crypto, para agentes de IA e geradores de código. Mesmo conteúdo das páginas HTML, gerado da mesma fonte, sem navegação nem estilo.
>
> Versão HTML: https://bifrostcrypto.com/pt-BR/docs/create-payin-single
> Arquivos relacionados: [ai.md](https://bifrostcrypto.com/ai/pt-BR.md) · [Postman](https://bifrostcrypto.com/postman-collection.json) · [OpenAPI](https://bifrostcrypto.com/openapi.json) · [llms.txt](https://bifrostcrypto.com/llms.txt)
> Outros idiomas: [English](https://bifrostcrypto.com/ai/en/create-payin-single.md) · [Español](https://bifrostcrypto.com/ai/es/create-payin-single.md) · [Français](https://bifrostcrypto.com/ai/fr/create-payin-single.md)
> API v1 · contrato alterado pela última vez em 2026-10-10

`POST https://bridge.bifrostcrypto.com/v1/payin`

Escopo exigido: `payin:write` (chave nova sem lista é somente leitura)

> A referência da API está em inglês. Os guias, a autenticação, os webhooks e os códigos de erro estão em português.

Creates a single deposit and answers 200 OK with a wallet address for the customer to send funds to.

The payin becomes completed when the amount received reaches minimum_payment percent of crypto_amount (minimum_payment is set per account and returned by check-payin and GET /v1/summary), which may be less than the full amount: confirm received_amount before delivering. The success body is one object under data, not a batch summary. crypto_amount in the response is cut (not rounded) to the token's decimals, with trailing zeros removed ("50.00" comes back as "50"). fiat_amount is the value you sent; when you did not send one it is crypto_amount × price with 8 decimals, or null if no price is available. The response has no expires_at: read it from check-payin. This endpoint has no Idempotency-Key: reference_id is what prevents a second payin. If a request times out, resend it with the same reference_id; a duplicate_reference_id answer means the first one was created, and GET /v1/list-payin?reference_id=… returns it. The error codes are listed under Errors.

## Headers

| Key | Value | Description |
| --- | --- | --- |
| `X-Bifrost-Invoke` | `{{api_key}}` | Private API key |
| `Content-Type` | `application/json` | - |

## Body Parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `crypto_currency` | `string` | required | Token symbol, case-sensitive (USDT, not usdt). It must be enabled on your account and active for deposits on the chosen network; otherwise invalid_parameters (details.fields.crypto_currency), unsupported_token_or_deposits_disabled or token_network_mismatch. |
| `process_by` | `string` | required | Which amount drives the deposit: crypto_amount or fiat_amount. |
| `reference_id` | `string` | required | Your reference for this deposit, 1 to 255 characters, trimmed. Must be unique on your account; a repeat returns duplicate_reference_id. |
| `network` | `string` | required | One of: Bitcoin, Ethereum, BinanceSmartChain, Tron, Solana, Ripple, Cardano, Dogecoin, Polygon, Avalanche, ArbitrumOne, Celo, Optimism, Arbitrum, Cronos, Base, BitcoinCash, BitcoinSV, BitcoinGold, Monero, OpBnb, Xlayer, Litecoin, TON. Case-insensitive here (binancesmartchain works), and the aliases in Network aliases are also accepted (erc20, bsc, trc20...); the payin is stored and returned with the canonical name. A network without active deposits returns invalid_network_or_deposits_disabled. |
| `webhook_url` | `string` | required | Callback URL for status updates. Up to 756 characters, https://, no user:password in the URL, on a standard port, and the host must resolve to a public IPv4 address. A refused URL returns 400 invalid_parameters with details.field webhook_url and details.reason unsafe_url. |
| `fiat_currency` | `string` | - | Fiat code from the accepted fiats, case-insensitive. Required when process_by is fiat_amount (fiat_currency_required). When omitted, your account's preferred currency is used, then USD. |
| `crypto_amount` | `string` | - | Required when process_by is crypto_amount (crypto_amount_required). Greater than 0, digits on both sides of an optional dot (".5" and "5." are refused). Extra decimals beyond the token's precision are cut. Ignored and recalculated when process_by is fiat_amount. A JSON number is accepted; a string is recommended. |
| `fiat_amount` | `string` | - | Required when process_by is fiat_amount (fiat_amount_required); same format as crypto_amount. When process_by is crypto_amount and you also send fiat_amount, crypto_amount must be within ±30% of fiat_amount ÷ current price, or the request fails with crypto_amount_does_not_correspond_to_fiat_amount_provided (or 503 price_not_available_for_validation without a price). |
| `customer_info` | `string` | - | Your customer identifier. Up to 200 characters, no whitespace. |
| `expires_at` | `number` | - | Lifetime of the deposit in seconds, integer from 1 to 86400. Default 14400 (4 hours). The resulting date is returned as expires_at (Y-m-d H:i:s) by check-payin and list-payin. |
| `memo` | `string` | - | Required for tokens configured to need a memo, such as TON (memo_required otherwise). Numeric string of 8 to 15 digits; this format is checked whenever memo is sent, and the value is ignored on tokens that do not use one. |

## Request Body

```json
{
  "crypto_currency": "USDT",
  "fiat_currency": "USD",
  "crypto_amount": "50.00",
  "process_by": "crypto_amount",
  "reference_id": "invoice_67890",
  "network": "BinanceSmartChain",
  "webhook_url": "https://your-site.com/webhook-deposit",
  "customer_info": "customer456",
  "expires_at": 14400
}
```

## cURL Example

```bash
curl -X POST "https://bridge.bifrostcrypto.com/v1/payin" \
  -H "X-Bifrost-Invoke: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "crypto_currency": "USDT",
  "fiat_currency": "USD",
  "crypto_amount": "50.00",
  "process_by": "crypto_amount",
  "reference_id": "invoice_67890",
  "network": "BinanceSmartChain",
  "webhook_url": "https://your-site.com/webhook-deposit",
  "customer_info": "customer456",
  "expires_at": 14400
}'
```

## Response Example

```json
{
  "message": "deposit_created_successfully",
  "data": {
    "reference_id": "invoice_67890",
    "internal_reference": "f531c319-6957-45c6-a154-d4944ca3eee3",
    "wallet": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0",
    "crypto_amount": "50",
    "fiat_amount": "50.00000000",
    "crypto_currency": "USDT",
    "fiat_currency": "USD",
    "network": "BinanceSmartChain",
    "status": "created"
  }
}
```

## Network aliases

On create, network also accepts these aliases. Case, spaces, hyphens and underscores are ignored (ERC-20, erc_20 and erc20 are the same). Responses, webhooks and listings always return the canonical name. bnb means BinanceSmartChain (for opBNB send OpBnb) and arb means Arbitrum (for ArbitrumOne send ArbitrumOne).

| Network | Aliases |
| --- | --- |
| `Ethereum` | `eth, eth-mainnet, erc20` |
| `Tron` | `trx, trc20` |
| `BinanceSmartChain` | `bnb, bsc, bep20, bnbchain, bnb-smart-chain` |
| `Arbitrum` | `arb, arbitrum-evm` |
| `Polygon` | `matic, pol, polygon-pos` |
| `Optimism` | `op, op-mainnet` |
| `Avalanche` | `avax, avaxc, avalanche-c` |
| `Solana` | `sol` |
| `Bitcoin` | `btc` |
| `Litecoin` | `ltc` |
| `Monero` | `xmr` |
| `Xlayer` | `okb` |

## Errors

Every error has the shape error.code, error.message and, when useful, error.details. Authentication, scope and rate-limit errors (401, 403, 429) apply to every endpoint and are described under Authentication.

| Status | Code | When | What to do |
| --- | --- | --- | --- |
| `400` | `invalid_parameters` | A field failed validation (details.fields), the body is empty (details.reason invalid_or_empty_data), a batch was sent (batch_not_allowed_use_single_object) or webhook_url is not allowed (details.reason unsafe_url). | Fix the request before sending it again. |
| `400` | `json_parse_exception` | The body is not valid JSON. | Fix the request before sending it again. |
| `400` | `duplicate_reference_id` | A payin with this reference_id already exists. | If it was a resend after a timeout, fetch it with GET /v1/list-payin?reference_id=… |
| `400` | `crypto_amount_required · fiat_amount_required · fiat_currency_required` | The amount or currency required by process_by is missing. | Fix the request before sending it again. |
| `400` | `memo_required` | The token needs a memo. | Fix the request before sending it again. |
| `400` | `invalid_network_or_deposits_disabled · unsupported_token_or_deposits_disabled · token_network_mismatch · token_not_supported_or_inactive` | The token or network does not accept deposits for your account. | Choose another token or network. |
| `400` | `amount_out_of_limits · value_below_minimum · value_above_maximum` | The amount is outside the token limits; details carries them. | Fix the request before sending it again. |
| `400` | `crypto_amount_does_not_correspond_to_fiat_amount_provided` | crypto_amount and fiat_amount differ by more than 30% at the current price. | Fix the request before sending it again. |
| `404` | `record_not_found` | The account setup is incomplete. | Contact support. |
| `500` | `internal_error · error_fetching_active_currencies · token_type_not_found · receipt_creation_failed · database_transaction_failed` | Failure on our side. | Retry later with the same reference_id. |
| `502` | `external_processor_error` | The deposit address could not be created right now. | Retry later with the same reference_id. |
| `503` | `no_processor_configured · no_wallet_available · price_not_available_for_conversion · price_not_available_for_validation · service_unavailable` | Temporarily unavailable. | Retry later with the same reference_id. |

## Outras respostas

Respostas que não são o caminho feliz e ainda assim precisam de tratamento na sua integração.

### 400 · Duplicate reference_id

A refused deposit answers with a single error object. There is no summary or results array on this endpoint. If this answer comes from resending after a timeout, the first request created the payin: fetch it with GET /v1/list-payin?reference_id=….

```json
{
  "error": {
    "code": "duplicate_reference_id",
    "message": "A payin with this reference_id already exists"
  }
}
```

### 400 · Invalid parameters

Field validation failures are listed in details.fields. A batch of 2 or more items returns the same code with details.reason batch_not_allowed_use_single_object; an empty body with invalid_or_empty_data; an unsafe webhook_url with details.field webhook_url and details.reason unsafe_url.

```json
{
  "error": {
    "code": "invalid_parameters",
    "message": "Invalid parameters provided",
    "details": {
      "fields": {
        "crypto_currency": "The crypto_currency field must be one of: USDT,BTC,ETH."
      }
    }
  }
}
```

### 400 · Amount outside the token limits

With process_by crypto_amount the code is amount_out_of_limits. With process_by fiat_amount it is value_below_minimum or value_above_maximum, with details reason, crypto_currency, fiat_currency, fiat_amount, crypto_amount, min_crypto, max_crypto, min_fiat and max_fiat.

```json
{
  "error": {
    "code": "amount_out_of_limits",
    "message": "Amount is outside the allowed limits",
    "details": {
      "message": "Amount below minimum limit",
      "crypto_amount": "0.5",
      "crypto_currency": "USDT",
      "min_allowed": "1.000000000000000000",
      "max_allowed": "unlimited",
      "process_by": "crypto_amount"
    }
  }
}
```

### 503 · Temporarily unavailable

Our side could not serve the deposit right now. Nothing was created; retry later with the same reference_id. 500 and 502 follow the same rule. The codes are listed in the Errors table.

```json
{
  "error": {
    "code": "no_wallet_available",
    "message": "No deposit address is available right now"
  }
}
```
