Creating deposits
A deposit starts with one call: POST /casino/deposit_address. You send the player, the
currency and the amount. ByteFederal checks the player's KYC, prices the deposit from the
casino's fee configuration, and returns an address and the exact crypto amount to pay.
POST https://quinix.byteconnect.us/casino/deposit_address
Request
Send a JSON body with the header Content-Type: application/json.
The Content-Type: application/json header is required. Without it the body is not read
at all: the API treats it as empty and skips validation. The request then fails with an
error that does not describe the real problem.
| Field | Type | Required | Description |
|---|---|---|---|
entity_id | integer | Yes | The casino's entity id. It must belong to your affiliate. An entity-scoped key may only use its own entity. |
currency | string | Yes | BTC, LTC or ETH. Upper case. The currency must be enabled for your affiliate. |
gambler_ref | string | Yes | Your stable reference for the player. KYC status is kept per casino and gambler_ref, so reuse the same value for the same player. Keep it to 255 characters or fewer. |
phone | string | Yes | The player's phone number. KYC links are sent to it by SMS. Required on every call, including for players who have already passed KYC. |
email | string or null | No | The player's email address. Must be a valid email address if present. When it is supplied, the player's receipt is also sent by email. |
amount | number | Yes | Must be greater than zero. By default this is the USD amount the player wants credited. See Amounts. |
amount_is_crypto | boolean | No | Default false. When true, amount is the amount of crypto the player will send. |
no_conf | boolean | No | Default false. Asks for pre-confirmation acceptance. See Fast deposits. |
instant | boolean | No | Default false. Asks for instant (pre-KYT, pre-confirmation) acceptance. Implies no_conf. See Fast deposits. |
machine_id | string | No | Your machine or kiosk identifier, at most 64 characters. It is echoed on deposit reads and on webhooks. |
Types are strict. entity_id must be a JSON number, not a string. no_conf, instant and
amount_is_crypto must be JSON booleans.
Obsolete fields
Older integrations sent player_amount, affiliate_fee and total_amount. These fields
are accepted and discarded. They have no effect on the price. Fees always come from the
casino's fee configuration held by ByteFederal. Remove them from new code.
Example
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",
"email": "[email protected]",
"amount": 100,
"machine_id": "kiosk-042"
}'
Responses
Every successful call returns HTTP 200. Branch on the status field. It is one of ok,
kyc_required or kyc_pending.
KYC is checked first. If the player is not verified, no deposit is created and no address is issued.
ok: deposit created
{
"status": "ok",
"deposit_id": 4821,
"transaction_id": 90312,
"gambler_ref": "sample-player-001",
"address": "bc1qexampledepositaddress000000000000000",
"currency": "BTC",
"crypto_amount": 0.0017517,
"usd_amount": 103,
"player_amount": 100,
"entity_net_usd": 99,
"affiliate_net_usd": 99,
"crypto_rate": 58800,
"market_rate": 60000,
"fee": 0,
"fee_usd": 0,
"bf_fee_usd": 0,
"bf_spread_usd": 2.1020399999999997,
"affiliate_fee_usd": 3,
"charges": [
{
"beneficiary": "BF",
"kind": "SPREAD",
"paid_by": "PLAYER",
"percent": 0.02,
"amount_usd": 2.1020399999999997,
"amount_crypto": 0.00003503
},
{
"beneficiary": "AFFILIATE",
"kind": "FEE",
"paid_by": "PLAYER",
"percent": 0.03,
"amount_usd": 3,
"amount_crypto": 0.00005102
},
{
"beneficiary": "BF",
"kind": "FEE",
"paid_by": "ENTITY",
"percent": 0.01,
"amount_usd": 1,
"amount_crypto": 0.00001701
}
],
"expires_at": "2026-09-25T15:30:00.000Z"
}
The example uses an illustrative fee configuration: a 2% ByteFederal spread, a 3% BurraPay fee paid by the player, and a 1% ByteFederal fee paid by the casino. The market rate is $60,000. The numbers were produced by the API's own pricing code.
| Field | Type | Description |
|---|---|---|
status | string | ok. |
deposit_id | integer | The deposit's id. Use it for every later call and to match webhooks. |
transaction_id | integer | The id of the underlying payment. Webhooks carry it too. |
gambler_ref | string | Echo of the request. |
address | string | The address the player pays. Reads call this field wallet. |
currency | string | Echo of the request. |
crypto_amount | number | The exact amount of crypto the player must send, rounded to at most 8 decimal places. |
usd_amount | number | What the player pays in total, in USD: the player amount plus every fee the player pays. |
player_amount | number | The amount to credit the player, in USD. |
entity_net_usd | number | What the casino is settled for this deposit, after any fees the casino pays. |
affiliate_net_usd | number | Deprecated. The same value as entity_net_usd. |
crypto_rate | number | The USD price per coin the player is quoted: market_rate less all spreads. |
market_rate | number | The market price per coin at quote time, before spreads. |
charges | array | Every fee and spread on this deposit. See Charges. |
fee, fee_usd, bf_fee_usd, bf_spread_usd, affiliate_fee_usd | number | Deprecated. Partial views of charges, kept for older integrations. They cannot represent every charge. Read charges instead. |
expires_at | string | ISO 8601 UTC time the quote expires, 30 minutes after creation. ByteFederal honors a payment until then. Show the player a 15-minute window, not this time: read Expiry and late payments. |
Money values in this response are not rounded. Round them only for display. Values read
back later from GET /casino/deposit/{id} are stored values and can differ in the last
digits (for example 2.10204 instead of 2.1020399999999997).
kyc_required and kyc_pending
{
"status": "kyc_required",
"message": "Identity verification required. A verification link has been sent."
}
{
"status": "kyc_pending",
"message": "Identity verification is pending. Please complete verification to proceed."
}
The player has not passed KYC. ByteFederal sends the player a link by SMS. Show the
player the message and ask them to complete verification, then call this endpoint
again. The full flow and every message value are on the KYC page.
Amounts
USD mode (default)
amount is the player amount: the USD value you will credit the player. Fees the player
pays are added on top. Spreads are applied to the rate.
crypto_rate = market_rate × (1 − sum of spread percents)
usd_amount = amount × (1 + sum of player-paid fee percents)
crypto_amount = usd_amount ÷ crypto_rate
player_amount = amount
Crypto mode (amount_is_crypto: true)
amount is the crypto the player will send, fees included. The player amount is derived
from it.
crypto_amount = amount, rounded to at most 8 decimal places
usd_amount = crypto_amount × crypto_rate
player_amount = usd_amount ÷ (1 + sum of player-paid fee percents)
Minimum and maximum
No minimum deposit is enforced today. amount only has to be greater than zero. Instant
deposits have a per-player cap, described below. There is no other maximum in the API.
Charges
Each deposit carries a list of charges. A charge is one fee or spread, earned by one party and paid by one party. You never send fees. They come from the casino's fee configuration, which ByteFederal sets up with BurraPay per casino.
| Field | Type | Description |
|---|---|---|
beneficiary | string | Who earns the charge: BF (ByteFederal), AFFILIATE (BurraPay) or ENTITY (the casino). |
kind | string | SPREAD or FEE. |
paid_by | string | PLAYER or ENTITY. |
percent | number | The configured rate as a fraction. 0.02 is 2%. |
amount_usd | number | The charge in USD. |
amount_crypto | number or null | The charge in the deposit's currency. |
How each kind works:
- Spread (
kind: "SPREAD"). Always paid by the player. It lowers the rate the player gets. Itsamount_usdiscrypto_amount × market_rate × percent, so a 2% spread is 2% of the market value of the crypto sent, which is slightly more than 2% ofusd_amount. - Player-paid fee (
kind: "FEE",paid_by: "PLAYER"). A percent of the player amount, added on top of it. - Casino-paid fee (
kind: "FEE",paid_by: "ENTITY"). A percent of the player amount, deducted from the casino's settlement. It does not change what the player pays.
The casino's settlement is:
entity_net_usd = player_amount
+ the casino's own player-paid fee
+ the casino's own spread
− casino-paid fees
In the example: 100 + 0 + 0 − 1 = 99.
Only charges with a percent above zero appear in the list.
Credit the player player_amount. If the player pays a different amount than quoted, the
deposit is re-priced when you accept it, and the accept response carries the final
player_amount. See Accept, return, freeze.
Fast deposits
By default a deposit can be accepted only after it has one on-chain confirmation and has passed KYT screening. Two flags make it acceptable sooner. Both must be enabled for the casino by ByteFederal.
| Flag | Acceptable when | Requires |
|---|---|---|
no_conf: true | Before confirmation, once ByteFederal's pre-confirmation checks mark it eligible and KYT has passed. | The casino enabled for no-conf deposits. |
instant: true | Before confirmation and before KYT completes, within the player's instant cap. | The casino enabled for both instant and no-conf deposits. |
instant: true always implies no_conf: true.
Instant caps
An instant deposit has two limits, both set per casino by ByteFederal:
- Quote cap. Checked at creation against
usd_amount(what the player pays, including player-paid fees). The default is $500 for a player's first deposit and $1,500 once the player has an earlier deposit with this casino that was accepted and confirmed on chain. Over the cap, creation fails with codeinstant_over_cap. - Received ceiling. Checked at accept against the market value of what actually
arrived. The default is $600 for a first deposit and $1,600 for a returning player. If
the player overpays past it, the deposit stops being instant and waits for KYT to pass.
Reads show this as
instant_downgraded: true.
The tier is decided when the deposit is created and does not change afterwards.
One fast deposit at a time
A player can have only one fast (no_conf or instant) deposit in flight with a casino.
Another fast deposit is refused while an earlier one is either:
- unpaid, not yet timed out, and not yet past its
expires_at, or - paid but not yet confirmed on chain.
The refusal is a 409 with code fast_deposit_unconfirmed. Standard deposits are never
blocked by this rule. You can create the new deposit without the fast flags instead.
Errors
Errors other than schema validation return a JSON body with a detail message. Some also
carry a machine-readable code and extra fields at the top level. Branch on code where
one exists. The full error reference is on the Errors page.
Schema validation failures (a missing field, a wrong type, an unknown currency) return
400 with a different body (abbreviated here):
{
"success": false,
"error": {
"name": "ZodError",
"message": "[\n {\n \"code\": \"invalid_value\", ... \"path\": [\n \"currency\"\n ], ... }\n]"
}
}
error.message is a JSON-encoded string listing each problem and the path of the field.
Errors specific to this endpoint:
| Status | code | detail | Meaning |
|---|---|---|---|
| 400 | BTC is not enabled for this affiliate | The currency is not enabled for your affiliate. The ticker varies. | |
| 400 | BTC is not enabled | The currency is switched off for everyone. The ticker varies. | |
| 400 | instant_over_cap | Instant deposits are capped at $500.00 USD for a player's first deposit; requested $515.00. Create it without "instant" to use pre-confirmation-KYT acceptance instead. | The quote is over the player's instant cap. Extra fields: requested_usd, instant_max_usd, instant_tier (first or returning). For a returning player the text reads for a player's deposits after their first confirmed one. |
| 403 | API key is scoped to a different entity | An entity-scoped key used another entity_id. | |
| 403 | Entity status is 'disabled', must be 'active' or 'enabled' | The casino is switched off. | |
| 403 | Entity is not enabled for instant (pre-KYT) deposits — requires both entity.instant_allowed and entity.no_conf_allowed | instant: true on a casino not enabled for it. | |
| 403 | Entity is not enabled for no-conf deposits (entity.no_conf_allowed) | no_conf: true on a casino not enabled for it. | |
| 404 | Entity not found for this affiliate | The entity_id does not exist under your affiliate. | |
| 409 | fast_deposit_unconfirmed | Cannot create instant deposit: deposit 4820 is an open fast-deposit quote (unpaid, not yet expired). Wait for it to confirm (deposit.confirmed), or create this deposit without the fast flag. | See One fast deposit at a time. Extra fields: blocking_deposit_id, blocking_status. The text says no-conf instead of instant for a no-conf request, and has not reached its first on-chain confirmation yet when the blocking deposit is already paid. |
| 500 | Entity fee schedule is not configured for this entity; contact ByteFederal | The casino has no fee configuration in force. | |
| 500 | Entity fee configuration is invalid; contact ByteFederal | The casino's fee configuration is invalid. | |
| 500 | Failed to create casino deposit | See the warning below. | |
| 502 | Unable to fetch BTC rate | No market rate was available. Retry. The ticker varies. | |
| 503 | Could not serialize fast deposit creation — try again | A concurrent fast-deposit request for the same player held the lock. Retry. | |
| 503 | Identity verification service unavailable | The KYC check could not run. Retry. |
Example instant_over_cap body:
{
"detail": "Instant deposits are capped at $500.00 USD for a player's first deposit; requested $515.00. Create it without \"instant\" to use pre-confirmation-KYT acceptance instead.",
"code": "instant_over_cap",
"requested_usd": 515,
"instant_max_usd": 500,
"instant_tier": "first"
}
A 500 Failed to create casino deposit does not always mean nothing was created. When no
pre-generated address is available, the API waits up to 30 seconds for a new one after the
deposit is recorded. If that wait fails, you get this 500, but the deposit already
exists without an address you can show the player. If the failed request was a fast
deposit, that deposit blocks a new fast deposit for the same player until its expires_at
passes or it is paid. List the player's recent deposits with GET /casino/deposits if you
need to reconcile.
Authentication errors (401, 403 for a key without admin scope) are covered on the
Authentication page.
What happens next
The deposit is created with status: "Pending" and decision: "pending". From here,
webhooks tell you when the payment is seen, confirmed and screened. When a deposit's
acceptable flag is true, you can accept it. See:
- Deposit lifecycle for the full state flow, and Expiry and late payments.
- Webhook event reference for each event.
- Accept, return, freeze for the decision calls.