# ByteMax API

Receive BRL Pix payments into your CNY or USD wallet. The currency is fixed when you open your profile. Track orders and refunds through HTTPS calls with JSON.

- Base URL: https://bytemax.exchange/api/v1
- [Download OpenAPI 3.1](https://bytemax.exchange/api-v1.openapi.json)
- [Documentation page](https://bytemax.exchange/en/docs/api)

## Getting started

To integrate, you will use:

- API key: sent on every call, in the `Authorization` header.
- `Idempotency-Key`: use one key per operation. If you need to repeat the same operation after a network failure or a 5xx, reuse the same key (Amounts and idempotency).
- `payment.url`: the payment link you send the payer to.
- `order.completed` webhook: tells you the order was paid; confirm with `GET /orders/{id}` ([webhook](https://bytemax.exchange/en/docs/webhooks)).

Every order has two sides:

| Fields | Meaning | Currency |
| --- | --- | --- |
| `source_*` | What the payer pays | `BRL` |
| `target_*` | What you receive | `CNY` / `USD` |

Four steps to your first order.

1. **Create the API key**
   On the [API](https://bytemax.exchange/en/api) page of your dashboard, create the key and store it on your server: it is shown only once and gives access to your whole account. Recommended: turn on the allowed IP list with the addresses of the servers that will call the API. While the list is off, any IP can use the key.

2. **Send the headers**
   `Authorization` goes with every call. `POST` and `PATCH` also need `Content-Type: application/json` and a UTF-8 JSON body, even when it is `{}`. When creating orders and refunds, include `Idempotency-Key`: see Amounts and idempotency.

   **Every call**

   ```http
   Authorization: Bearer <API_KEY>
   ```

   **POST and PATCH**

   ```http
   Content-Type: application/json
   ```

3. **Get a quote (optional)**
   A quote creates nothing. Use it to check the key and see the conversion amounts.

   ```bash
   curl --request GET "https://bytemax.exchange/api/v1/quote?source_currency=BRL&target_currency=CNY&source_amount_cents=10000" \
     --header "Authorization: Bearer <API_KEY>"
   ```

   **Response 200**

   ```json
   {
     "source_currency": "BRL",
     "source_amount_cents": "10000",
     "target_currency": "CNY",
     "target_amount_cents": "12500"
   }
   ```

4. **Create your first order**
   `POST /orders` with a new `Idempotency-Key` creates a real order. Send the payer to `payment.url`: that is where they pay. Without payment, the order expires at `expires_at`, 48 hours after creation.

   ```bash
   curl --request POST "https://bytemax.exchange/api/v1/orders" \
     --header "Authorization: Bearer <API_KEY>" \
     --header "Idempotency-Key: order-8412" \
     --header "Content-Type: application/json" \
     --data '{"source_currency":"BRL","source_amount_cents":"10000","target_currency":"CNY"}'
   ```

   **Response 201**

   ```json
   {
     "id": "ord_example",
     "status": "pending_payment",
     "source_currency": "BRL",
     "source_amount_cents": "10000",
     "target_currency": "CNY",
     "target_amount_cents": "12500",
     "refunded_source_amount_cents": "0",
     "blocked_source_amount_cents": "0",
     "payment": {
       "url": "https://bytemax.exchange/pt-br/payment/0123456789abcdef0123456789abcdef",
       "pix_copy_paste": "00020101021226820014br.gov.bcb.pix2560pix.example/qr/v2/0123456789abcdef0123456789abcdef5204000053039865406100.005802BR5907BYTEMAX6009SAO PAULO62070503***6304ABCD"
     },
     "created_at": "2026-09-10T13:05:00.000Z",
     "expires_at": "2026-09-12T13:05:00.000Z"
   }
   ```

## Payment flow

An order starts waiting for payment and ends completed (paid), expired or canceled. Track it with a webhook or by querying it.

1. **Quote (optional)**
   `GET /quote` tells you how much the payer pays and how much you receive. It is only a preview: the order uses the quote from the moment it is created, and only then are the Pix minimum and maximum checked.

2. **Create the order**
   `POST /orders` with both currencies and one of the two amounts: how much the payer pays or how much you receive. The response includes `payment.url`, the payment link, and `payment.pix_copy_paste`, the Pix code the payer can paste into their banking app.

3. **Send the payer to the payment link**
   Redirect the payer to `payment.url` or send them the link. After paying, they go back automatically, after 5 seconds, to the return URL set on the [API](https://bytemax.exchange/en/api) page of your dashboard; the payment page's "Back to merchant" link opens the same address. Without that URL, they go back to the site they came from.

4. **Track the order**
   Register a [webhook](https://bytemax.exchange/en/docs/webhooks): `order.completed` tells you when the order was paid, and `GET /orders/{id}` confirms its current state.

5. **Refund if needed**
   `POST /orders/{id}/refunds` with how much of what you received you want to return, in CNY or USD. That amount leaves your balance, and ByteMax works out how much the payer gets back in BRL, in the same proportion as the order: returning half the amount received returns half the reais paid. If the response is 202, the refund is still processing: follow it with `GET /orders/{id}/refunds/{refund_id}` and do not create another one.

### Order states

- `pending_payment`: Waiting for payment. The Pix code can be paid until `expires_at`, 48 hours after creation.
- `completed`: Paid. The CNY or USD amount is already in your balance. Final state.
- `expired`: Not paid by `expires_at`. Final state.
- `canceled`: Canceled by ByteMax, for example when a payment could not be accepted and was returned to the payer. Final state.

### Refund states

- `processing`: In progress. Query it until it reaches a final state. A refund that stays `processing` for a long time is being reviewed by ByteMax: contact support.
- `succeeded`: Completed. Final state.
- `failed`: The refund could not be completed. The CNY or USD amount returns to your balance. Final state.

## Amounts and idempotency

### Amounts and IDs

Every amount is a positive integer string in cents, without leading zeros, a sign, decimal point or scientific notation. BRL, CNY and USD use 2 decimals: "20000" means 200 units of the stated currency. Send exactly one amount: `source_amount_cents` or `target_amount_cents`.

The minimum and the Pix maximum are checked when the order is created, not by the quote. The payer must pay at least R$ 30.00 (`ORDER_MINIMUM_NOT_MET`). The maximum paid by Pix follows the exchange rate: above it the API responds `PIX_RECEIPT_LIMIT_EXCEEDED` and the `message` states the current maximum in BRL. On any call, the amount you send may not exceed `"100000000"` (1,000,000.00).

Every ID is a string too: store and compare it as text, never convert it to a number. A refund ID such as `"9007199254741001"` can exceed the largest integer JavaScript represents exactly.

### Idempotency

- Use one `Idempotency-Key` per operation: each new order or refund has its own.
- To repeat the same operation after a network failure or a 5xx response, reuse the same key with the same body. The API returns the order or refund already created, in its current state, without creating another.
- Store the key together with the purchase in your system.

A key has 1 to 80 characters among letters, digits, `.`, `_`, `:` and `-`. Do not use keys that differ only in upper and lower case. Keys do not expire, and order keys also cover orders created through the previous API. On a repeat, the order comes back with 200; the refund with 202 while it is processing and 200 afterwards.

Special cases: the same key with a different body returns 409 `IDEMPOTENCY_CONFLICT`. A refusal before the key is reserved does not hold it. After reservation for an order creation, a charge or persistence failure can leave the key processing even when no order was created. After a network failure or a 5xx, repeat the same intent with the same key; do not send a different body or change the key to try again. While creation with the key is processing, a repeat returns 409 `CONFLICT`.

## Reference

Five operations. The examples use `<API_KEY>` and fictional IDs.

### Quote

`GET /quote`

Returns the amounts of a conversion without creating anything. The quote is not reserved and does not check the Pix minimum and maximum: a quoted amount can still be refused when the order is created. Send both currencies and one of the two amounts in the query.

**Parameters**

| Parameter | Where | Required |
| --- | --- | --- |
| `source_currency` | query | Yes |
| `target_currency` | query | Yes |
| `source_amount_cents` | query | Conditional |
| `target_amount_cents` | query | Conditional |

**Request**

```bash
curl --request GET "https://bytemax.exchange/api/v1/quote?source_currency=BRL&target_currency=CNY&source_amount_cents=10000" \
  --header "Authorization: Bearer <API_KEY>"
```

**Response 200**

```json
{
  "source_currency": "BRL",
  "source_amount_cents": "10000",
  "target_currency": "CNY",
  "target_amount_cents": "12500"
}
```

### Create order

`POST /orders`

Creates the order and returns the payment link. Requires `Idempotency-Key`.

**Parameters**

| Parameter | Where | Required |
| --- | --- | --- |
| `Idempotency-Key` | header | Yes |

**JSON body**

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `source_currency` | `string` | Yes | Currency the payer pays. Currently only `BRL`. |
| `target_currency` | `string` | Yes | Currency you receive: `CNY` or `USD`. It must match your wallet currency. |
| `source_amount_cents` | `string` | Conditional | Amount the payer pays, in BRL cents. |
| `target_amount_cents` | `string` | Conditional | Amount you receive, in CNY or USD cents. |

Send exactly one of `source_amount_cents` and `target_amount_cents`. The order calculates the other.

**Request**

```bash
curl --request POST "https://bytemax.exchange/api/v1/orders" \
  --header "Authorization: Bearer <API_KEY>" \
  --header "Idempotency-Key: order-8412" \
  --header "Content-Type: application/json" \
  --data '{"source_currency":"BRL","source_amount_cents":"10000","target_currency":"CNY"}'
```

**Response 201**

```json
{
  "id": "ord_example",
  "status": "pending_payment",
  "source_currency": "BRL",
  "source_amount_cents": "10000",
  "target_currency": "CNY",
  "target_amount_cents": "12500",
  "refunded_source_amount_cents": "0",
  "blocked_source_amount_cents": "0",
  "payment": {
    "url": "https://bytemax.exchange/pt-br/payment/0123456789abcdef0123456789abcdef",
    "pix_copy_paste": "00020101021226820014br.gov.bcb.pix2560pix.example/qr/v2/0123456789abcdef0123456789abcdef5204000053039865406100.005802BR5907BYTEMAX6009SAO PAULO62070503***6304ABCD"
  },
  "created_at": "2026-09-10T13:05:00.000Z",
  "expires_at": "2026-09-12T13:05:00.000Z"
}
```

### Get order

`GET /orders/{id}`

Current state and amounts of the order. `refunded_source_amount_cents` is how much was already returned to the payer, and `blocked_source_amount_cents` how much is held by disputes, both in BRL cents. `expires_at` is the end of the time to pay, 48 hours after `created_at`: an order still `pending_payment` at that moment can no longer be paid and becomes `expired`. The field stays on the order afterwards; to know whether it was paid, read `status`.

**Parameters**

| Parameter | Where | Required |
| --- | --- | --- |
| `id` | path | Yes |

**Request**

```bash
curl --request GET "https://bytemax.exchange/api/v1/orders/ord_example" \
  --header "Authorization: Bearer <API_KEY>"
```

**Response 200**

```json
{
  "id": "ord_example",
  "status": "pending_payment",
  "source_currency": "BRL",
  "source_amount_cents": "10000",
  "target_currency": "CNY",
  "target_amount_cents": "12500",
  "refunded_source_amount_cents": "0",
  "blocked_source_amount_cents": "0",
  "payment": {
    "url": "https://bytemax.exchange/pt-br/payment/0123456789abcdef0123456789abcdef",
    "pix_copy_paste": "00020101021226820014br.gov.bcb.pix2560pix.example/qr/v2/0123456789abcdef0123456789abcdef5204000053039865406100.005802BR5907BYTEMAX6009SAO PAULO62070503***6304ABCD"
  },
  "created_at": "2026-09-10T13:05:00.000Z",
  "expires_at": "2026-09-12T13:05:00.000Z"
}
```

### Create refund

`POST /orders/{id}/refunds`

Refunds part or all of the amount received, in CNY or USD cents. Requires `Idempotency-Key`. Only `completed` orders can be refunded, one refund at a time, and your CNY or USD balance must cover the amount. Responds 202 while the refund is processing and 200 when it has already finished: check `status`.

**Parameters**

| Parameter | Where | Required |
| --- | --- | --- |
| `id` | path | Yes |
| `Idempotency-Key` | header | Yes |

**JSON body**

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `target_amount_cents` | `string` | Yes | Amount to refund, in CNY or USD cents, taken from your balance. The payer receives in BRL the same proportion of what they paid, rounded to the cent (`source_amount_cents` in the response). |

**Request**

```bash
curl --request POST "https://bytemax.exchange/api/v1/orders/ord_example/refunds" \
  --header "Authorization: Bearer <API_KEY>" \
  --header "Idempotency-Key: refund-8412-1" \
  --header "Content-Type: application/json" \
  --data '{"target_amount_cents":"2500"}'
```

**Response 202**

```json
{
  "id": "9007199254741001",
  "order_id": "ord_example",
  "status": "processing",
  "source_currency": "BRL",
  "source_amount_cents": "2000",
  "target_currency": "CNY",
  "target_amount_cents": "2500",
  "created_at": "2026-09-10T13:05:00.000Z",
  "updated_at": "2026-09-10T13:05:00.000Z"
}
```

### Get refund

`GET /orders/{id}/refunds/{refund_id}`

Current state of a refund requested by your account, through the API or the dashboard.

**Parameters**

| Parameter | Where | Required |
| --- | --- | --- |
| `id` | path | Yes |
| `refund_id` | path | Yes |

**Request**

```bash
curl --request GET "https://bytemax.exchange/api/v1/orders/ord_example/refunds/9007199254741001" \
  --header "Authorization: Bearer <API_KEY>"
```

**Response 200**

```json
{
  "id": "9007199254741001",
  "order_id": "ord_example",
  "status": "processing",
  "source_currency": "BRL",
  "source_amount_cents": "2000",
  "target_currency": "CNY",
  "target_amount_cents": "2500",
  "created_at": "2026-09-10T13:05:00.000Z",
  "updated_at": "2026-09-10T13:05:00.000Z"
}
```

## Errors and limits

Every error response includes `code` and `message`. Program against `code`: `message` is text for your logs and may change. Keep the `X-Request-Id` response header: it identifies the call when you contact support. Unknown fields and repeated parameters are rejected with 400. During maintenance or an outage the response may come without `code`: treat any 5xx, or a body that is not JSON, as a temporary failure.

```json
{
  "code": "INVALID_INPUT",
  "message": "Use source_currency BRL and the supplier wallet currency, CNY or USD."
}
```

### HTTP status

| HTTP status | When it happens |
| --- | --- |
| 400 | Invalid data, an amount outside the limits or an unsupported currency pair. |
| 401 | API key missing or invalid. |
| 403 | The IP address is not on your allowlist, or your account is not authorized for this operation. |
| 404 | Order, refund, webhook or event not found, or an address that does not exist in the API. |
| 409 | The request conflicts with the current state: an idempotency key reused with a different body or still in use, an order that cannot be refunded yet, a refund still in progress or a webhook with the same URL. |
| 410 | The order was paid through a method that is no longer supported and cannot be refunded through the API. |
| 413 | Body larger than 1 MB. |
| 415 | `POST` or `PATCH` without `Content-Type: application/json`, even when the body is `{}`. |
| 429 | Call limit exceeded. Wait for the time in `Retry-After` and retry. |
| 500 | Unexpected failure. Retry after a few seconds; when creating, with the same `Idempotency-Key`. |
| 503 | Service unavailable. Retry after a few seconds, increasing the wait on each attempt. |

### Error codes

The most common codes. Others may appear: treat an unknown code with a 4xx status as a refusal that will not pass on retry, and with a 5xx status as temporary.

- `WALLET_CURRENCY_MISMATCH` (HTTP 409): The target currency must match your account's balance currency.
- `UNAUTHORIZED` (HTTP 401): API key missing, malformed or no longer valid. Check the `Authorization: Bearer <API_KEY>` header; if you created a new key, the previous one stopped working.
- `API_IP_NOT_ALLOWED` (HTTP 403): The call came from an IP outside your allowed IP list. Add your server's address on the [API](https://bytemax.exchange/en/api) page.
- `USER_BLOCKED` (HTTP 403): Your account is blocked or has been closed. [Contact support](https://bytemax.exchange/en/support).
- `KYC_KYB_REQUIRED` (HTTP 403): Your account cannot create orders yet. Complete identity verification in your dashboard. If you are already approved, contact support.
- `INVALID_INPUT` (HTTP 400): The request is malformed: a field, parameter or header is missing, unknown, repeated or invalid; the body is not JSON; the pair is not BRL → CNY or USD; or the amount exceeds `"100000000"` (1,000,000.00). The `message` says what to fix. Amounts are strings of digits greater than zero, such as `"10000"`.
- `JSON_REQUIRED` (HTTP 415): Send `Content-Type: application/json` on every `POST` and `PATCH`, even when the body is `{}`.
- `ORDER_MINIMUM_NOT_MET` (HTTP 400): The payer would pay less than the minimum of R$ 30.00. It also applies when you send only the CNY or USD amount.
- `PIX_RECEIPT_LIMIT_EXCEEDED` (HTTP 400): The payer would pay more than the current Pix maximum, stated in the `message`. Create the order again with a lower amount; the same `Idempotency-Key` can be used.
- `IDEMPOTENCY_CONFLICT` (HTTP 409): This key was already used with a different body. Use a new key for a new operation.
- `CONFLICT` (HTTP 409): An order creation with this key is still running. Wait a few seconds and repeat with the same `Idempotency-Key`.
- `ORDER_NOT_FOUND` (HTTP 404): No order with this ID in your account. Expired orders are removed 6 months after they were created.
- `ORDER_NOT_REFUNDABLE` (HTTP 409): The order has not been paid yet, expired or was canceled. Only `completed` orders can be refunded.
- `REFUND_NOT_FOUND` (HTTP 404): No refund with this ID for this order. Only refunds requested by your account appear.
- `REFUND_AMOUNT_NOT_AVAILABLE` (HTTP 400): The amount is higher than what can still be refunded: part of the order was already refunded or is held by a dispute.
- `REFUND_INVALID_AMOUNT_OR_RATIO` (HTTP 400): The amount is too small to become a refund in BRL.
- `REFUND_IN_PROGRESS` (HTTP 409): Another refund of this order has not finished. Wait for it to reach a final state.
- `INSUFFICIENT_BALANCE` (HTTP 400): Your CNY or USD balance does not cover the refund.
- `PAYMENT_METHOD_RETIRED` (HTTP 410): The order was paid through a method that is no longer supported. Contact support to refund it.
- `NOT_FOUND` (HTTP 404): The address or the method does not exist in the API. There is no operation to list or cancel orders.
- `PAYLOAD_TOO_LARGE` (HTTP 413): The body is larger than 1 MB.
- `SECURITY_BLOCKED` (HTTP 403): The security filter refused the request because of an unusual sequence in the URL or in the body. Repeating the same request right away gets 429 `RATE_LIMIT_EXCEEDED`. If your data is legitimate, contact support with the `X-Request-Id`.
- `RATE_LIMIT_EXCEEDED` (HTTP 429): Call limit exceeded. Wait for the time in `Retry-After`.
- `SERVICE_UNAVAILABLE` (HTTP 503): A service needed by the operation is temporarily unavailable, or conversions are paused. Retry after a few seconds, increasing the wait, with the same `Idempotency-Key`.
- `INTERNAL_ERROR` (HTTP 500): Unexpected failure. Retry after a few seconds with the same `Idempotency-Key`. If it persists, contact support with the `X-Request-Id`.

### Call limit

Each IP address can make up to 300 requests per minute to ByteMax, counting the API and the website together. `GET /quote` accepts 300 calls per minute per account, and refund creation 30 per minute per account, counting refunds requested in the dashboard. On 429, wait the number of seconds in `Retry-After` before retrying. Quote and refund responses also report the account limit in the `RateLimit-*` headers below; `RateLimit-Reset` is the number of seconds until the window restarts. To track orders, use webhooks instead of polling every few seconds.

```http
HTTP/1.1 429 Too Many Requests
Retry-After: 60
RateLimit-Policy: 300;w=60
RateLimit-Limit: 300
RateLimit-Remaining: 0
RateLimit-Reset: 60
```

## Integration summary

The path of a paid order, start to finish:

1. **Create the order**
   `POST /orders` with a new `Idempotency-Key` for the purchase.

2. **Save the `id`**
   Store the order `id` with the purchase in your system.

3. **Redirect the payer to `payment.url`**
   Or show `payment.pix_copy_paste` in your checkout.

4. **Receive `order.completed`**
   On your [webhook](https://bytemax.exchange/en/docs/webhooks), verify the signature and store the event `id`.

5. **Query `GET /orders/{id}`**
   The event only notifies you; the query returns the current state.

6. **Fulfill the purchase if `status` is `completed`**
   Fulfill it once per order, even if the event arrives again.

Questions about the integration? [Contact support](https://bytemax.exchange/en/support).
