Deposit lifecycle
A deposit moves along three independent tracks. Your integration watches all three.
| Track | Field | Values | Who changes it |
|---|---|---|---|
| Payment | status | Pending, Succeed, Underpaid, Overpaid, Confirmed, … | ByteFederal's payment engine, as the blockchain moves |
| Decision | decision | pending, accepted, returned, frozen | You (accept, return, freeze), or ByteFederal on a screening failure |
| Screening | kyt_status, ofac_status | KYT: passed, review, failed. OFAC: clear, hit, timed_out | ByteFederal's screening |
You never have to combine these yourself to decide when to accept. The acceptable flag does that for you.
Transaction status
status is the payment state of the deposit's underlying transaction. It appears on deposit reads (GET /casino/deposit/{id}) and in the generic transaction.<status> webhooks. Values are case-sensitive strings, exactly as shown.
| Status | Meaning |
|---|---|
Pending | Waiting for payment. Nothing has arrived at the address yet. |
Succeed | The exact quoted amount has been seen on-chain. Not yet confirmed. |
Underpaid | Less than the quoted amount has been seen on-chain. Not yet confirmed. |
Overpaid | More than the quoted amount has been seen on-chain. Not yet confirmed. |
Timedout | Nothing arrived by the deposit's expires_at, 30 minutes after creation. See Expiry and late payments. |
Cancelled | The deposit was cancelled while still unpaid. |
Confirmed | The payment reached its required confirmations: 1 for BTC and LTC, 12 blocks for Ethereum assets. |
ConfirmedKYTReview | Confirmed, and KYT returned review or failed. ByteFederal compliance handles it. |
ConfirmedApproved | Confirmed. The accept gate treats it the same as Confirmed. |
PendingSettlement | Accepted and being settled to the casino. |
Settled | Settled to the casino. |
Refund | You returned the deposit and the refund has been sent on-chain. |
An underpaid or overpaid deposit still confirms. It becomes Confirmed once the amount that did arrive reaches the required confirmations. The deposit webhooks tell you the difference in amount_matches, delta_crypto and delta_usd_at_market.
Events: what fires when
Every event below is a webhook sent to your webhook URL. Payloads are documented in Webhook events.
| Event | Fires when | Carries acceptable |
|---|---|---|
transaction.pending | The deposit is created. | No |
deposit.received | Funds are first seen on-chain (status becomes Succeed, Underpaid or Overpaid). | Yes |
transaction.succeed, transaction.underpaid, transaction.overpaid | Status becomes that value. | No |
ofac_complete | The OFAC screen of the funding addresses finishes, or misses its deadline (ofac_result: clear, hit or timed_out). Fires again if the result changes. | Yes |
kyt_complete | KYT finishes (kyt_result: passed, review or failed). Fires again if the result changes, for example review to passed after compliance review. | Yes |
deposit.confirmed | The payment reaches its required confirmations (status becomes Confirmed or a later status). | Yes |
transaction.confirmed | Status becomes Confirmed. | No |
double_spend_alert | A no-conf deposit's funding transaction disappeared before it confirmed. | Always false |
deposit.accepted | You called accept and it succeeded. | Always false |
deposit.returned | You called return and it succeeded. | Always false |
deposit.frozen | You called freeze and it succeeded. | Always false |
transaction.refund | Status becomes Refund (the return has been sent on-chain). | No |
transaction.settled | Status becomes Settled. | No |
transaction.timedout | Status becomes Timedout. | No |
transaction.cancelled | Status becomes Cancelled. | No |
Rules that hold for every deposit:
transaction.<status>,deposit.receivedanddeposit.confirmedare each sent at most once per deposit.deposit.receivedalways arrives beforedeposit.confirmed. No other ordering is guaranteed.kyt_completeandofac_completecome from separate workers and can arrive before or afterdeposit.confirmed.- ByteFederal detects status changes by polling. If a deposit passes through a status between two polls, no
transaction.<status>event is sent for that status.deposit.receivedanddeposit.confirmedare still sent, because they are derived from where the deposit ends up. ConfirmedKYTReview,ConfirmedApprovedandPendingSettlementhave notransaction.<status>event. You see them on reads, and you learn about KYT throughkyt_complete.- There is no
deposit.frozenevent when ByteFederal freezes a deposit. A KYT failure arrives askyt_completewithkyt_result: "failed"anddecision: "frozen". An OFAC hit arrives asofac_completewithofac_result: "hit".
Typical order
A standard deposit, paid in full, usually produces:
transaction.pendingdeposit.received,transaction.succeedofac_complete(clear)deposit.confirmed,transaction.confirmedkyt_complete(passed,acceptable: true)- You call accept.
deposit.accepted - Later,
transaction.settled
For a no-conf or instant deposit, kyt_complete and acceptable: true can arrive before step 4. See Deposit levels.
Decision
decision records what happens to the funds. Every deposit starts at pending. It leaves pending exactly once, and there is no API to move it again.
| Decision | Set by | What happens next |
|---|---|---|
pending | Deposit creation | Waiting for you (or for screening). |
accepted | POST /casino/deposit/{id}/accept | The deposit is credited and settled to the casino. |
returned | POST /casino/deposit/{id}/return | ByteFederal sends the received crypto to your return address. Status later becomes Refund. |
frozen | POST /casino/deposit/{id}/freeze, or ByteFederal when KYT fails or OFAC hits | Funds are held. Contact ByteFederal to resolve it. |
ByteFederal freezes only a deposit whose decision is still pending. If you already accepted an instant deposit and a later KYT or OFAC result is bad, the decision stays accepted. You receive kyt_complete (failed) or ofac_complete (hit) with decision: "accepted". That event is your signal to reverse the player's credit. The same applies to double_spend_alert on an accepted no-conf deposit.
Screening: KYT and OFAC
ByteFederal screens every deposit twice. You do not run either screen yourself.
KYT
KYT (Know Your Transaction) scores the risk of the funds' on-chain history. It runs when a standard deposit confirms, or before confirmation for a no-conf or instant deposit.
kyt_status on reads | kyt_result in kyt_complete | Meaning | Effect |
|---|---|---|---|
null or pending | not sent | Not finished. | Accept waits, except for instant deposits within their ceiling. |
passed | passed | Clean. | Accept, return and freeze are allowed (subject to the other gates). |
review | review | Needs manual compliance review. | Accept is blocked. Status becomes ConfirmedKYTReview. You receive kyt_complete again when review finishes. |
failed | failed | Blocking risk found. | A pending deposit is frozen. Status becomes ConfirmedKYTReview. |
OFAC
The OFAC screen checks the addresses that funded the deposit against the sanctions list. It starts as soon as the payment is seen. It has a deadline of 15 seconds after deposit.received is sent. If the screen has not finished by then, the deposit proceeds as timed_out and the screen keeps running.
ofac_status on reads | ofac_result in ofac_complete | Meaning | Effect |
|---|---|---|---|
pending | not sent | Screen running, deadline not reached. | Accept and return are refused with 409 code ofac_screen_pending. |
clear | clear | No sanctioned address. | Accept and return are allowed. |
timed_out | timed_out | Deadline passed before the screen finished. | Accept and return are allowed. A second ofac_complete follows with the final result. |
hit | hit | A funding address is sanctioned. | A pending deposit is frozen. Accept and return are refused forever with 409 code ofac_sanctioned. |
A timed_out screen can later turn into hit. If you accepted in between, you receive ofac_complete with ofac_result: "hit" and decision: "accepted". Reverse the player's credit and contact ByteFederal compliance.
The matched addresses are never sent to partners. The result is the whole signal.
The acceptable flag
acceptable is a snapshot of the deposit's decision, payment and screening readiness for acceptance. It does not promise that an accept request will succeed.
Key your accept logic on it. On any webhook that carries acceptable: true, you may call accept. The same rule works for standard, no-conf and instant deposits. You do not need to track which screen each level waits for.
acceptable uses the decision, payment and screening checks below. It is true only when all of these hold:
-
decisionispending. -
The payment state allows it. Either:
statusisConfirmed,ConfirmedApprovedorConfirmedKYTReview, orstatusisSucceed,OverpaidorUnderpaid, the deposit is no-conf, andno_conf_stateiseligible.
A no-conf deposit whose funding transaction was double-spent (
no_conf_state: "double_spent") is never acceptable, whatever its status. -
ofac_statusisclearortimed_out. -
kyt_statusispassed. Or: the deposit is instant, KYT has not finished (nullorpending), and the received value is within the deposit's instant ceiling.
acceptable appears on:
GET /casino/deposit/{id}andGET /casino/deposits, computed at read time.deposit.received,deposit.confirmed,kyt_completeandofac_complete, computed when the event was built.deposit.accepted,deposit.returned,deposit.frozenanddouble_spend_alert, where it is alwaysfalse.
It is not on the generic transaction.<status> events.
Four things to know:
- It is a snapshot. State can change between the webhook and your accept call. A double-spend or a late KYT failure closes the gate again. Keep handling
409from accept. The next webhook carries the new value. - It can become
truewithout a webhook. No event fires when a no-conf deposit becomeseligible. If the last webhook for a deposit saidfalseand you are still waiting, read the deposit withGET /casino/deposit/{id}. - It does not check amount adjustments or late-payment repricing. If the received amount differs from the quote (
amount_matches: false), accept returns400unless you send"adjust_to_received": true. A restored late deposit requires that flag even when the amounts match, and acceptance can still fail if it cannot be repriced. See Decisions. - A late instant accept revalues the ceiling. Readiness uses the deposit's recorded rate. Acceptance uses the current market rate for a restored late deposit, which can put an instant deposit still waiting for KYT over its ceiling. Accept then returns
409codeinstant_received_over_capeven ifacceptablewastrueand the deposit's state has not changed. Wait for KYT to pass.
Deposit levels: standard, no-conf and instant
You choose the level per deposit with the no_conf and instant flags on create. ByteFederal must enable a level for your casino before you can use it.
| Standard | No-conf | Instant | |
|---|---|---|---|
| Request flags | none | "no_conf": true | "instant": true (implies no-conf) |
| Earliest accept | After confirmation | Before confirmation, once eligible | Before confirmation, once eligible |
| KYT needed before accept | Yes, passed | Yes, passed | No, if within the instant ceiling |
| OFAC needed before accept | clear or timed_out | clear or timed_out | clear or timed_out |
| Size limit | none | none | Per-player quote cap and received ceiling |
| Double-spend risk | none | Yours | Yours |
Standard
The default. Accept opens after the payment confirms, OFAC is clear or timed_out, and KYT is passed. KYT runs at confirmation, so kyt_complete is usually the event that carries acceptable: true.
No-conf
Accept can open before the first confirmation.
After the payment is seen, ByteFederal checks the funding transaction. no_conf_state on reads shows the result:
no_conf_state | Meaning |
|---|---|
null | Not evaluated yet. |
pending_guards | Being evaluated. |
eligible | Can be accepted before confirmation. KYT runs now. |
fell_back | Not eligible. The deposit follows the standard flow and becomes acceptable after confirmation. An eligible BTC or LTC deposit that is still unconfirmed after 24 hours also falls back. |
double_spent | The funding transaction disappeared before confirming. Never acceptable. You receive double_spend_alert. |
Once eligible, the deposit becomes acceptable when KYT passes and OFAC is clear or timed_out. kyt_complete (passed) is usually the event that carries acceptable: true.
You carry the double-spend risk on a no-conf or instant deposit you accept before confirmation. If the funding transaction disappears afterwards, the decision stays accepted. You receive double_spend_alert and must reverse the player's credit yourself.
Instant
Instant goes one step further than no-conf: accept can open before KYT finishes. It still waits for no-conf eligibility and for OFAC clear or timed_out. A completed review or failed KYT result always blocks accept.
Instant deposits have two limits. ByteFederal sets both per casino.
- Quote cap. Checked at create. If the quoted total is over the cap, create fails with
400codeinstant_over_cap. Create the deposit withoutinstantinstead. The cap has two tiers: one for a player's first deposit, and a higher one once the player has an accepted, confirmed deposit with your casino. The error body'sinstant_tierfield (firstorreturning) tells you which tier applied. - Received ceiling. Checked against what actually arrives, valued at the quote's market rate for ordinary deposits. A late accept uses the current market rate instead. The ceiling is fixed when the deposit is created. Reads show it as
instant_received_max_usd.
At deposit.received, the received value is evaluated at the deposit's recorded rate. If it is over the ceiling, for example because the player overpaid, instant_downgraded becomes true. A pending deposit then waits for KYT passed like a no-conf deposit. The event already carries instant_downgraded: true when that excess is visible at that point.
A late accept separately checks the ceiling at the current market rate. An over-ceiling refusal returns 409 code instant_received_over_cap and does not set instant_downgraded; wait for KYT to pass before accepting.
If KYT later fails on an instant deposit you already accepted, the decision stays accepted. You receive kyt_complete with kyt_result: "failed" and must reverse the player's credit.
One fast deposit per player
A player can have only one no-conf or instant deposit in flight at a time. Create returns 409 code fast_deposit_unconfirmed while the player's previous fast deposit:
- is paid but not yet confirmed, or
- is an unpaid quote that has not timed out, which means its
expires_athas not passed.
The error body's blocking_deposit_id field names the deposit that blocks. Standard deposits are never blocked. You can always create the deposit without the fast flags instead.
Expiry and late payments
A deposit's quote is locked when it is created. The response carries expires_at, 30 minutes after creation.
Show the player a 15-minute payment window. ByteFederal keeps watching the address and honors a payment until expires_at, 30 minutes after creation. The extra 15 minutes are a grace period for players who are slow or have trouble paying. A payment that arrives in that grace period is credited like any other.
If nothing has arrived by expires_at, the status becomes Timedout and the quote expires.
A deposit paid after it expired is not restored automatically. ByteFederal is alerted internally. Support can restore an eligible deposit after verifying the payment.
If a player pays after expires_at, contact ByteFederal with the deposit_id and the on-chain transaction id.
Late payments
After support restores a deposit, its new webhook events and its single-deposit and list reads carry late_payment: true. The boolean is present only when true and absent otherwise. Events for a restored deposit can arrive after transaction.timedout; the player may already have been told the deposit expired.
A restored late deposit can be accepted only with adjust_to_received: true, at the current market rate. The original quote is preserved in ByteFederal's records. Return is unchanged and still follows its existing gates.
The expires_at limit applies only to a deposit where nothing has arrived. Once any amount is seen (Succeed, Underpaid or Overpaid), the deposit continues to confirmation, however long that takes.
Each deposit address is used once. Never show a player the address of an earlier deposit. Create a new deposit instead.
For ordinary deposits, the quote's market rate stays locked. If the received amount differs and you accept with "adjust_to_received": true, the amounts are recalculated at the rate locked at creation. Restored late deposits use the current market rate at acceptance instead.