Getting started
To integrate, you will use:
- API key: sent on every call, in the
Authorizationheader. 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.completedwebhook: tells you the order was paid; confirm withGET /orders/{id}(webhook).
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.
- 1Create the API key
On the 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.
- 2Send the headers
Authorizationgoes with every call.POSTandPATCHalso needContent-Type: application/jsonand a UTF-8 JSON body, even when it is{}. When creating orders and refunds, includeIdempotency-Key: see Amounts and idempotency.Every callAuthorization: Bearer <API_KEY>POST and PATCHContent-Type: application/json - 3Get a quote (optional)
A quote creates nothing. Use it to check the key and see the conversion amounts.
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{ "source_currency": "BRL", "source_amount_cents": "10000", "target_currency": "CNY", "target_amount_cents": "12500" } - 4Create your first order
POST /orderswith a newIdempotency-Keycreates a real order. Send the payer topayment.url: that is where they pay. Without payment, the order expires atexpires_at, 48 hours after creation.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{ "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.
- 1Quote (optional)
GET /quotetells 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. - 2Create the order
POST /orderswith both currencies and one of the two amounts: how much the payer pays or how much you receive. The response includespayment.url, the payment link, andpayment.pix_copy_paste, the Pix code the payer can paste into their banking app. - 3Send the payer to the payment link
Redirect the payer to
payment.urlor send them the link. After paying, they go back automatically, after 5 seconds, to the return URL set on the 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. - 4Track the order
Register a webhook:
order.completedtells you when the order was paid, andGET /orders/{id}confirms its current state. - 5Refund if needed
POST /orders/{id}/refundswith 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 withGET /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
processingfor 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-Keyper 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.
/quoteQuote
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.
| Parameter | Where | Required |
|---|---|---|
source_currency | query | Yes |
target_currency | query | Yes |
source_amount_cents | query | Conditional |
target_amount_cents | query | Conditional |
curl --request GET "https://bytemax.exchange/api/v1/quote?source_currency=BRL&target_currency=CNY&source_amount_cents=10000" \
--header "Authorization: Bearer <API_KEY>"{
"source_currency": "BRL",
"source_amount_cents": "10000",
"target_currency": "CNY",
"target_amount_cents": "12500"
}/ordersCreate order
Creates the order and returns the payment link. Requires Idempotency-Key.
| Parameter | Where | Required |
|---|---|---|
Idempotency-Key | header | Yes |
source_currencystringRequired: Yes- Currency the payer pays. Currently only
BRL. target_currencystringRequired: Yes- Currency you receive:
CNYorUSD. It must match your wallet currency. source_amount_centsstringRequired: Conditional- Amount the payer pays, in BRL cents.
target_amount_centsstringRequired: Conditional- Amount you receive, in CNY or USD cents.
| 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.
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"}'{
"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"
}/orders/{id}Get order
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.
| Parameter | Where | Required |
|---|---|---|
id | path | Yes |
curl --request GET "https://bytemax.exchange/api/v1/orders/ord_example" \
--header "Authorization: Bearer <API_KEY>"{
"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"
}/orders/{id}/refundsCreate refund
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.
| Parameter | Where | Required |
|---|---|---|
id | path | Yes |
Idempotency-Key | header | Yes |
target_amount_centsstringRequired: 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_centsin the response).
| 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). |
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"}'{
"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"
}/orders/{id}/refunds/{refund_id}Get refund
Current state of a refund requested by your account, through the API or the dashboard.
| Parameter | Where | Required |
|---|---|---|
id | path | Yes |
refund_id | path | Yes |
curl --request GET "https://bytemax.exchange/api/v1/orders/ord_example/refunds/9007199254741001" \
--header "Authorization: Bearer <API_KEY>"{
"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.
{
"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_MISMATCHHTTP 409- The target currency must match your account's balance currency.
UNAUTHORIZEDHTTP 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_ALLOWEDHTTP 403- The call came from an IP outside your allowed IP list. Add your server's address on the API page.
USER_BLOCKEDHTTP 403- Your account is blocked or has been closed. Contact support.
KYC_KYB_REQUIREDHTTP 403- Your account cannot create orders yet. Complete identity verification in your dashboard. If you are already approved, contact support.
INVALID_INPUTHTTP 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). Themessagesays what to fix. Amounts are strings of digits greater than zero, such as"10000". JSON_REQUIREDHTTP 415- Send
Content-Type: application/jsonon everyPOSTandPATCH, even when the body is{}. ORDER_MINIMUM_NOT_METHTTP 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_EXCEEDEDHTTP 400- The payer would pay more than the current Pix maximum, stated in the
message. Create the order again with a lower amount; the sameIdempotency-Keycan be used. IDEMPOTENCY_CONFLICTHTTP 409- This key was already used with a different body. Use a new key for a new operation.
CONFLICTHTTP 409- An order creation with this key is still running. Wait a few seconds and repeat with the same
Idempotency-Key. ORDER_NOT_FOUNDHTTP 404- No order with this ID in your account. Expired orders are removed 6 months after they were created.
ORDER_NOT_REFUNDABLEHTTP 409- The order has not been paid yet, expired or was canceled. Only
completedorders can be refunded. REFUND_NOT_FOUNDHTTP 404- No refund with this ID for this order. Only refunds requested by your account appear.
REFUND_AMOUNT_NOT_AVAILABLEHTTP 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_RATIOHTTP 400- The amount is too small to become a refund in BRL.
REFUND_IN_PROGRESSHTTP 409- Another refund of this order has not finished. Wait for it to reach a final state.
INSUFFICIENT_BALANCEHTTP 400- Your CNY or USD balance does not cover the refund.
PAYMENT_METHOD_RETIREDHTTP 410- The order was paid through a method that is no longer supported. Contact support to refund it.
NOT_FOUNDHTTP 404- The address or the method does not exist in the API. There is no operation to list or cancel orders.
PAYLOAD_TOO_LARGEHTTP 413- The body is larger than 1 MB.
SECURITY_BLOCKEDHTTP 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 theX-Request-Id. RATE_LIMIT_EXCEEDEDHTTP 429- Call limit exceeded. Wait for the time in
Retry-After. SERVICE_UNAVAILABLEHTTP 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_ERRORHTTP 500- Unexpected failure. Retry after a few seconds with the same
Idempotency-Key. If it persists, contact support with theX-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/1.1 429 Too Many Requests
Retry-After: 60
RateLimit-Policy: 300;w=60
RateLimit-Limit: 300
RateLimit-Remaining: 0
RateLimit-Reset: 60Integration summary
The path of a paid order, start to finish:
- 1Create the order
POST /orderswith a newIdempotency-Keyfor the purchase. - 2Save the
idStore the order
idwith the purchase in your system. - 3Redirect the payer to
payment.urlOr show
payment.pix_copy_pastein your checkout. - 4Receive
order.completedOn your webhook, verify the signature and store the event
id. - 5Query
GET /orders/{id}The event only notifies you; the query returns the current state.
- 6Fulfill the purchase if
statusiscompletedFulfill it once per order, even if the event arrives again.
Questions about the integration? Contact support.
