Testing your integration
There is no sandbox. The API at https://quinix.byteconnect.us runs on mainnet.
You can test two things without moving money:
- Check your API key: what the key is, which casinos it can act on, and where each casino's webhooks go.
- Send a test webhook: one signed sample event, delivered to the casino's configured webhook URL.
Everything else needs a real deposit. See the mainnet walkthrough.
Every deposit address is a real mainnet address. Every deposit moves real crypto. Every return sends real crypto to the address you give. Test with small amounts and with wallets you control.
Check your API key
GET /casino/integration/key describes the key you call it with. It never returns secrets.
curl https://quinix.byteconnect.us/casino/integration/key \
-H "X-API-Key: $API_KEY"
Response for an affiliate-wide key:
{
"key": {
"id": 77,
"name": "production",
"mode": "live",
"scope": "admin",
"expires_at": "2027-09-01T00:00:00.000Z"
},
"affiliate": {
"id": 42,
"name": "Example Partner"
},
"entity_scope": null,
"entities": [
{
"id": 1234,
"name": "Example Casino",
"external_code": "your-casino-code",
"status": "enabled",
"webhook": {
"url": "https://casino.example.com/webhooks/byteconnect",
"signed": true,
"source": "entity_override"
}
},
{
"id": 1235,
"name": "Second Casino",
"external_code": null,
"status": "disabled",
"webhook": {
"url": "https://partner.example.com/webhooks/byteconnect",
"signed": true,
"source": "api_key"
}
}
]
}
A key locked to one casino returns that casino in entity_scope and lists only that casino in entities:
{
"key": {
"id": 77,
"name": "production",
"mode": "live",
"scope": "admin",
"expires_at": "2027-09-01T00:00:00.000Z"
},
"affiliate": {
"id": 42,
"name": "Example Partner"
},
"entity_scope": {
"id": 1234,
"name": "Example Casino"
},
"entities": [
{
"id": 1234,
"name": "Example Casino",
"external_code": "your-casino-code",
"status": "enabled",
"webhook": {
"url": "https://casino.example.com/webhooks/byteconnect",
"signed": true,
"source": "entity_override"
}
}
]
}
| Field | Type | Description |
|---|---|---|
key.id | number | The key's id. Quote it to ByteFederal when asking about the key. |
key.name | string or null | The key's label. |
key.mode | "live" or "test" | See Test mode. |
key.scope | "admin" or "terminal" | Casino endpoints need admin. A terminal key gets 403 on this endpoint too. |
key.expires_at | string or null | ISO 8601 UTC. null means the key does not expire. |
affiliate | object | Your partner account: id and name. |
entity_scope | object or null | The one casino the key is locked to (id, name), or null for an affiliate-wide key. |
entities[] | array | Every casino the key can act on, in any status, ordered by id. |
entities[].id | number | The entity_id to send in requests. |
entities[].name | string | The casino's name. |
entities[].external_code | string or null | The code that appears as entity_external_code in webhook payloads. |
entities[].status | string | enabled or disabled. Deposits can only be created for an enabled casino. |
entities[].webhook | object or null | Where this casino's webhooks are delivered. null means no webhook URL is configured and no webhooks are sent. |
entities[].webhook.url | string | The delivery URL. |
entities[].webhook.signed | boolean | true when deliveries carry X-Webhook-Signature. false means they are sent unsigned. |
entities[].webhook.source | string | entity_override: the casino's own webhook setting. api_key: the webhook URL on an active API key that covers this casino. A key locked to this casino wins over an affiliate-wide key. It is not necessarily the key you called with. |
Look for three things:
- The casino you expect is listed, with
status: "enabled". webhook.urlis where you expect events to arrive: the casino's own endpoint (entity_override) or BurraPay's (api_key).webhook.signedistrue.
Send a test webhook
POST /casino/integration/test-webhook sends one sample event to the webhook URL configured for a casino and reports how your endpoint answered.
curl -X POST https://quinix.byteconnect.us/casino/integration/test-webhook \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{"entity_id": 1234, "event": "deposit.accepted"}'
| Field | Type | Required | Description |
|---|---|---|---|
entity_id | integer | Yes | The casino whose configured webhook URL receives the event. Any status, so you can test before the casino is enabled. |
event | string | Yes | The event to send. |
Valid event values: deposit.received, deposit.confirmed, kyt_complete, ofac_complete, double_spend_alert, deposit.accepted, deposit.returned, deposit.frozen, transaction.pending, transaction.succeed, transaction.underpaid, transaction.overpaid, transaction.confirmed, transaction.timedout, transaction.cancelled, transaction.refund, transaction.settled. See Webhook events for each one.
How the test differs from a real event:
- The URL and signing secret come from ByteFederal's configuration for the casino. You cannot send a test event to any other URL.
- The payload is signed exactly like a real event.
- The payload carries
"test": true, anddeposit_idandtransaction_idare0. No real deposit has id0. - The request carries the header
X-Webhook-Test: true. - Nothing is stored and nothing is retried. One call sends one request.
- The request times out after 30 seconds, the same as real deliveries.
- Redirects are not followed, the same as real deliveries.
The endpoint returns HTTP 200 whenever it made the delivery attempt, whatever your endpoint answered. Read delivered.
Response fields
| Field | Type | Description |
|---|---|---|
event | string | The event that was sent. |
url | string | Where it was sent. |
signed | boolean | Whether the request carried X-Webhook-Signature. |
signature | string or null | The X-Webhook-Signature value sent, or null if unsigned. |
delivered | boolean | true when your endpoint answered with a 2xx status. |
status_code | number or null | Your endpoint's HTTP status. null if no response arrived. |
duration_ms | number | How long the attempt took. |
response_excerpt | string or null | The first 500 characters of your endpoint's response body. null if no response arrived. |
error | string or null | Why no response arrived (timeout, connection failure). null when a response arrived. |
payload | object | The event payload that was sent. |
Delivered
Your endpoint answered 2xx:
{
"event": "deposit.accepted",
"url": "https://casino.example.com/webhooks/byteconnect",
"signed": true,
"signature": "704828d06759f1551858ece3c83e8cb4b036d9b0d8368576dc67b30e1b9d953c",
"delivered": true,
"status_code": 200,
"duration_ms": 184,
"response_excerpt": "{\"received\":true}",
"error": null,
"payload": {
"event": "deposit.accepted",
"deposit_id": 0,
"transaction_id": 0,
"entity_id": 1234,
"entity_external_code": "your-casino-code",
"currency": "BTC",
"address": "bc1qsampleaddressdonotsendfunds000000000",
"crypto_amount": 0.00104359,
"usd_amount": 101.75,
"confirmed_crypto": 0.00104359,
"gambler_ref": "sample-player-001",
"decision": "accepted",
"decision_at": "2026-09-23T14:00:00.000Z",
"no_conf": false,
"instant": false,
"instant_downgraded": false,
"machine_id": null,
"acceptable": false,
"timestamp": 1790172000,
"player_amount": 100,
"charges": [
{
"beneficiary": "BF",
"kind": "SPREAD",
"paid_by": "PLAYER",
"percent": 0.025,
"amount_usd": 2.608975,
"amount_crypto": 0.00002609
},
{
"beneficiary": "AFFILIATE",
"kind": "FEE",
"paid_by": "PLAYER",
"percent": 0.0175,
"amount_usd": 1.75,
"amount_crypto": 0.00001795
}
],
"fee": 0,
"fee_usd": 0,
"bf_fee_usd": 0,
"bf_spread_usd": 2.608975,
"affiliate_fee_usd": 1.75,
"adjusted": false,
"crypto_rate": "97500.0000000000",
"entity_net_usd": 100,
"affiliate_net_usd": 100,
"test": true
}
}
The remaining examples leave out payload. It is always present.
Your endpoint answered with an error
Any status outside 2xx, including a redirect, sets delivered: false:
{
"event": "deposit.accepted",
"url": "https://casino.example.com/webhooks/byteconnect",
"signed": true,
"signature": "704828d06759f1551858ece3c83e8cb4b036d9b0d8368576dc67b30e1b9d953c",
"delivered": false,
"status_code": 500,
"duration_ms": 97,
"response_excerpt": "upstream handler crashed",
"error": null
}
A 3xx status means your URL redirects. Real deliveries do not follow redirects either, so they fail the same way. Ask ByteFederal to configure the final URL.
No response: timeout or connection failure
{
"event": "deposit.accepted",
"url": "https://casino.example.com/webhooks/byteconnect",
"signed": true,
"signature": "704828d06759f1551858ece3c83e8cb4b036d9b0d8368576dc67b30e1b9d953c",
"delivered": false,
"status_code": null,
"duration_ms": 30001,
"response_excerpt": null,
"error": "The operation timed out."
}
error describes the failure, for example The operation timed out. or a connection error. Do not match on its text.
Webhook URL is not a public address
The test webhook only contacts public addresses. If the configured URL is an IP literal in a private, loopback or link-local range, or its hostname resolves to one, nothing is sent. The result has delivered: false, status_code: null, and an error saying the URL points to or resolves to a non-public address. Ask ByteFederal or BurraPay to set a public https:// URL.
No webhook configured
If neither the casino nor any active API key that covers it has a webhook URL, nothing is sent:
{
"detail": "No webhook URL is configured for this entity"
}
The status is 409. Ask ByteFederal to set the webhook URL.
For every other error this endpoint returns, see Errors.
Rate limit
The endpoint allows 10 calls per 60-second window per API key. The 11th call returns 429 with a Retry-After header. See Errors.
What your endpoint receives
POST /webhooks/byteconnect HTTP/1.1
Content-Type: application/json
X-Webhook-Signature: 704828d06759f1551858ece3c83e8cb4b036d9b0d8368576dc67b30e1b9d953c
X-Webhook-Test: true
The body is the payload JSON. Use a test webhook to prove three things about your endpoint:
- It verifies the signature. Compute HMAC-SHA256 over the raw request body with the casino's webhook secret, hex-encode it, and compare with
X-Webhook-Signature. See Webhooks. - It ignores test events. An event with
"test": true(or theX-Webhook-Test: trueheader) must not credit a player, change a balance or touch a real deposit. Answer 2xx and stop. - It answers fast with 2xx. Real deliveries are retried when you answer anything else.
The payload object in the test-webhook response is not byte-for-byte the body that was signed. The signed body has its keys in sorted order. Recompute the signature from the raw bytes your endpoint received, never from a re-serialized object.
Test mode
ByteFederal can mark an API key or a casino as test mode. GET /casino/integration/key shows the key's mode. It does not show the casino's mode; ask ByteFederal to confirm it.
A deposit is recorded as test data when either the key that created it or its casino is in test mode.
What test mode changes:
- The deposit is left out of bank settlement. The casino is not paid for it.
- ByteFederal's internal notices about the deposit are marked as test.
What test mode does not change:
- The address is a real mainnet address, and the crypto sent to it is real.
- Player KYC runs for real. The player gets a real SMS.
- OFAC and KYT screening run for real.
- Webhooks are sent as normal. Their payloads do not say the deposit is test data, and they do not carry
"test": true. - The player gets a real receipt after accept.
- A return sends real crypto to the address you give.
Test mode only changes accounting. Funds sent to a test-mode deposit are real, and funds returned from one are gone from ByteFederal's wallets.
Mainnet walkthrough
This walkthrough takes one player through KYC, one deposit through accept, and a second deposit through return. It uses real crypto.
You need:
- An
adminAPI key for the casino. - A phone you control, to receive the KYC link.
- A wallet with a small amount of BTC, LTC or ETH.
- A second wallet address you control on the same chain, to receive the return.
- Your webhook endpoint running, and a way to see what it receives.
1. Check the key and the webhook
Run the key check. Confirm the casino is enabled and the webhook points at your endpoint. Then send a test webhook and confirm delivered: true.
2. Register a new player
Pick a gambler_ref you have never used, for example sample-player-001. Create a deposit with it and your phone number:
curl -X POST https://quinix.byteconnect.us/casino/deposit_address \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"entity_id": 1234,
"currency": "BTC",
"gambler_ref": "sample-player-001",
"phone": "+15551234567",
"amount": 5
}'
A new player gets kyc_required, and an SMS with a verification link goes to the phone:
{
"status": "kyc_required",
"message": "Identity verification required. A verification link has been sent."
}
If the phone already belongs to a verified identity, the message is We found an existing account. A confirmation link has been sent. instead.
No deposit is created yet. Open the link on the phone and complete it. See Player KYC.
3. Create the first deposit
Send the same request again. Until verification completes you get kyc_pending:
{
"status": "kyc_pending",
"message": "Identity verification is pending. Please complete verification to proceed."
}
Once it completes, you get status: "ok" with a deposit. Note deposit_id, address, crypto_amount and expires_at. See Creating deposits for every field.
4. Fund it
Send exactly crypto_amount to address. Players are shown a 15-minute window; a payment is honored until expires_at, 30 minutes after creation. See Expiry and late payments.
If you send a different amount, the deposit can still be accepted, but accept then needs "adjust_to_received": true. See Accept, return, freeze.
5. Watch the webhooks
As the payment is seen, confirmed and screened, your endpoint receives events including deposit.received, ofac_complete, deposit.confirmed and kyt_complete, along with transaction.* status events. See Webhook events for what each one carries.
Do not depend on the order they arrive in. Use the acceptable field instead: it is on every deposit webhook and on GET /casino/deposit/{id}, and it turns true when accept would succeed.
curl https://quinix.byteconnect.us/casino/deposit/$DEPOSIT_ID \
-H "X-API-Key: $API_KEY"
6. Accept
When acceptable is true:
curl -X POST https://quinix.byteconnect.us/casino/deposit/$DEPOSIT_ID/accept \
-H "X-API-Key: $API_KEY"
Check that:
- The response has
"decision": "accepted". - Your endpoint receives
deposit.accepted. - The player's phone (and email, if you sent one) receives a receipt.
7. Create and fund a second deposit
Create another deposit with the same gambler_ref. The player is verified now, so you get status: "ok" straight away. Fund it as in step 4.
8. Return it
Wait until the deposit is confirmed and its KYT result has passed: deposit.confirmed and a passed kyt_complete have arrived, or GET /casino/deposit/{id} shows status: "Confirmed" and kyt_status: "passed". Then return it to your second wallet:
curl -X POST https://quinix.byteconnect.us/casino/deposit/$DEPOSIT_ID/return \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"return_address": "<your second wallet address>",
"reason": "Integration test"
}'
The API does not validate return_address. It accepts any non-empty string. A wrong address, or an address on another chain, loses the funds. Copy it from your wallet and check it before sending.
Check that:
- The response has
"decision": "returned"and areturn_id. - Your endpoint receives
deposit.returned. - The crypto arrives in your second wallet.
Each deposit can be decided once. A second return call gets 400 Decision is already 'returned', cannot return.