> For the complete documentation index, see [llms.txt](https://docs.bitnbox.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.bitnbox.com/guides/quick-start.md).

# Quick Start

Accept crypto payments with the Bitnbox API — from registration to your first confirmed payment in under 1 hour.

**What you'll need before starting:**

* A server to receive webhooks
* Google Authenticator app
* curl or Postman for testing

{% stepper %}
{% step %}

### Register & set up account

Create a merchant account at [app.bitnbox.com](https://app.bitnbox.com/) and complete KYC verification. You can explore Test Mode right away — 2FA is only needed when generating an API key.

1. Sign up at [app.bitnbox.com ](https://app.bitnbox.com/sign-in)with your business email
2. Complete KYC — upload required business documents
3. Go to **Account → Settings → Security** and connect Google Authenticator
4. Scan the QR code in the app and enter the 6-digit code to confirm
   {% endstep %}

{% step %}

### Generate your API key

The API key authenticates all your requests and signs webhook callbacks via HMAC-SHA256. Store it securely — it's shown only once.

1. Go to **Merchant Account → Settings → API Settings → API Key**
2. Click **Create**
3. Confirm with your Google Authenticator code
4. **Copy the key immediately** — it won't be shown again

Include the key in every API request:

```http
x-api-key: YOUR-API-KEY
```

{% hint style="warning" %}
2FA confirmation is required at the moment of key generation. Generating a new key immediately invalidates the previous one — all active integrations will stop working. Store the key in a password manager.
{% endhint %}

{% hint style="info" %}
The same API key is used to verify webhook signatures — keep it private and never expose it in frontend code.
{% endhint %}

For full details on key security and rotation, see API Key Set Up.
{% endstep %}

{% step %}

### Enable Test Mode

Test Mode lets you run the full payment flow without spending real crypto. Use test networks (e.g. Sepolia for ETH-based tokens) and get free test tokens via faucets linked in the guide below.

1. In the dashboard, toggle **Test Mode** on (Account → Settings → General)
2. Use `network: "sepolia"` and `currency: "usdt"` for ETH-based tests
3. Get free test tokens — see Test Mode guide for faucet links and instructions

{% hint style="success" %}
All test transactions appear in your dashboard under **Transaction History** — they won't affect your real balance.
{% endhint %}
{% endstep %}

{% step %}

### Create your first payment

Call `POST /v1/payment` to create a payment invoice. Bitnbox validates the parameters, generates a wallet address, and returns a `payAddress` and optional `checkoutUrl`.

**Request:**

```bash
curl --request POST \
  --url https://api.bitnbox.com/v1/payment \
  --header 'Content-Type: application/json' \
  --header 'x-api-key: YOUR-API-KEY' \
  --data '{
    "amount": 50,
    "currency": "usdt",
    "network": "sepolia",
    "method": "direct",
    "orderId": "ORDER-001",
    "customerIp": "192.168.1.1",
    "processingFeeByUser": false,
    "webhookUrl": "https://your-server.com/webhook"
  }'
```

**Key parameters:**

| Parameter             | Required | Notes                                               |
| --------------------- | -------- | --------------------------------------------------- |
| `amount`              | yes      | Minimum 5.00 USD                                    |
| `currency`            | yes      | e.g. `usdt`, `usdc` — see API Glossary              |
| `network`             | yes      | e.g. `sepolia` (test), `tron`, `eth`                |
| `orderId`             | optional | Your internal order ID for reconciliation           |
| `webhookUrl`          | optional | Overrides the global webhook URL for this payment   |
| `processingFeeByUser` | optional | `false` = merchant pays fee, `true` = customer pays |

**Successful response (201):**

```json
{
  "orderId": "ORDER-001",
  "status": "waiting",
  "paymentId": "11bf97b6-9b27-1b21-9177-ec1e1581219c",
  "payAddress": "0xaf38220a2f436bc6bd3b5a7cb67afc4dfb47f7ae",
  "payAmount": 50,
  "currency": "usdt",
  "network": "sepolia",
  "checkoutUrl": "https://pay.bitnbox.com?paymentId=11bf97b6...",
  "payQrCodeUri": "data:image/png;base64,iVBOR...",
  "expiredAt": "2025-06-30T14:42:24.154Z"
}
```

{% hint style="info" %}
Show `payAddress` + `payQrCodeUri` to your customer directly (headless checkout), or redirect to `checkoutUrl` for the hosted Bitnbox payment page. The wallet address is reserved for 3 hours by default.
{% endhint %}
{% endstep %}

{% step %}

### Handle webhook callback

When a payment status changes, Bitnbox sends a POST request to your `webhookUrl`. Always verify the `x-signature` header before processing.

**Webhook delivery:** Sequential per transaction. Next webhook sent only after previous receives HTTP 200. Up to 12 retries with exponential backoff (2, 4, 8, 16... minutes).

**Signature verification (Node.js):**

```javascript
const crypto = require('crypto');

function verifySignature(apiKey, rawBody, signatureHeader) {
  const computed = crypto
    .createHmac('sha256', apiKey)
    .update(rawBody)
    .digest('hex');
  return computed === signatureHeader;
}

app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-signature'];
  const isValid = verifySignature(process.env.BITNBOX_API_KEY, req.body, signature);

  if (!isValid) {
    return res.status(401).send('Invalid signature');
  }

  const { data, meta } = JSON.parse(req.body);

  if (meta.event === 'payment' && data.status === 'paid') {
    // Fulfill order: data.orderId, data.merchantAmount
  }

  res.status(200).send('OK');
});
```

{% hint style="warning" %}
Always use the **raw request body** before JSON parsing for signature computation.
{% endhint %}
{% endstep %}

{% step %}

### Check payment status

Use webhooks as the primary method. As a fallback, query the payment status directly:

```bash
curl --request GET \
  --url https://api.bitnbox.com/v1/payment/{paymentId}/status \
  --header 'x-api-key: YOUR-API-KEY'
```

**Payment status reference:**

| Status       | Meaning                                                    | Action                             |
| ------------ | ---------------------------------------------------------- | ---------------------------------- |
| `waiting`    | Invoice created, waiting for customer to send funds        | Show `payAddress` • QR to customer |
| `confirming` | Transaction detected on blockchain, awaiting confirmations | Show "Processing..." to customer   |
| `settling`   | AML/KYT check in progress before crediting balance         | Wait — do not fulfill yet          |
| `paid`       | Payment confirmed, funds credited to your balance          | ✅ Fulfill the order                |
| `locked`     | Transaction flagged by AML/KYT                             | ⛔ Do not fulfill. Contact support  |
| `expired`    | Address reservation timed out, no payment received         | Create a new payment if needed     |

{% hint style="success" %}
Only fulfill orders on `paid` status. The `merchantAmount` field in the webhook shows your actual amount after the 0.5% processing fee.
{% endhint %}

{% hint style="warning" %}
If you receive `locked` status — do not fulfill the order. Contact Bitnbox support for individual case review.
{% endhint %}

{% hint style="info" %}
See Payment Statuses reference for the full status list with transition rules.
{% endhint %}
{% endstep %}
{% endstepper %}

## What's next?

* [Full API Reference:](/bitnbox-pay-api-reference/create-payment.md) all endpoints, parameters, and response schemas
* [Webhooks Set Up](/guides/webhooks-set-up.md): payload structure and signature verification
* [Transaction Statuses:](/payments/transaction-statuses.md) all possible statuses for Payment (pay-in) and Payout transactions
* [Edge Cases:](/payments/edge-cases.md) underpayments, overpayments, wrong network
