Appearance
Withdrawals
Users with an active funded account can take payouts from their profit. A payout is taken from the gross profit, the balance above the funded starting amount. The user's share is the profit split of the gross amount they take, and exactly that gross amount leaves the balance. Payouts can be partial: what is not taken simply stays on the balance, to be played on or lost. FAST calculates every figure and every condition; your sportsbook handles the actual payment.
Everything before an executed payout is virtual. The balance, the gross profit and the user's share of it are figures on a virtual account, not money owed. Only an executed payout is paid.
Check Withdrawable Amount
GET /v1/users/:userId/withdrawablebash
curl -H "X-API-Key: your-api-key" \
https://api.fundedfast.eu/v1/users/user-001/withdrawablejson
{
"withdrawable": 680.00,
"currentBalance": 5850.00,
"fundedAmount": 5000.00,
"profitSplitPercent": 80,
"payoutCapPercent": null,
"payout": {
"currentBalance": 5850.00,
"virtualBalance": 5850.00,
"fundedAmount": 5000.00,
"profitSplitPercent": 80,
"grossProfit": 850.00,
"profitShare": 680.00,
"available": 680.00,
"availableGross": 850.00,
"withdrawableNow": 680.00,
"withdrawableGross": 850.00,
"minGrossAmount": 62.50,
"minPayout": 50,
"payoutCount": 0,
"maxPayouts": null,
"remainingPayouts": null,
"isFinal": false,
"payoutIntervalDays": null,
"lastPayoutAt": null,
"nextPayoutAt": null,
"mandatoryPayoutThreshold": 7500,
"firstPayoutDeadlineAt": "2026-11-14T10:00:00.000Z",
"totalWithdrawn": 0,
"openStake": 0,
"pending": null,
"reasons": [],
"canRequest": true
},
"correlationId": "uuid"
}withdrawable is the user's share that a request made now may ask for (the same as payout.withdrawableNow); it is 0 while anything blocks a payout. payout carries the full state:
| Field | Meaning |
|---|---|
currentBalance | Ledger balance: the results of settled bets only |
virtualBalance | currentBalance less the stake of open bets: the balance the player sees, and the one gross profit is measured on |
grossProfit | virtualBalance above fundedAmount, before the split |
profitShare | The user's split of the whole gross profit, before caps and conditions |
available / availableGross | Largest share one payout may take once every condition is met (after caps), and the gross amount it takes off the balance |
withdrawableNow / withdrawableGross | The same, but 0 while any reason blocks a request. withdrawableGross is the largest grossAmount a request may send now |
minPayout / minGrossAmount | The tier's minimum payout, measured on the user's share, and the smallest gross amount that reaches it |
isFinal | The next payout is the last one the account allows: it takes the whole gross profit and ends the account |
nextPayoutAt | When the gap after the last executed payout ends, if the tier sets one |
firstPayoutDeadlineAt | Request the first payout by then or the account ends. Null with no deadline, and once a payout has executed |
pending | The request waiting for the operator's decision, if any (amount, grossAmount, isFinal, isMandatory) |
reasons | Every reason a payout is not possible yet, not just the first (see below) |
Show the user the gross amount they can take and the share it pays, side by side. The user picks an amount between minGrossAmount and withdrawableGross.
Reasons a payout is not possible yet
| Code | Meaning |
|---|---|
account_not_active | The funded account is no longer active |
payout_pending | A request is already waiting for a decision |
max_payouts_reached | The account has used every payout it allows |
first_payout_deadline | The deadline for the first payout has passed (until carries it) |
no_profit | The virtual balance is not above the funded amount |
below_min_payout | The share available is below the minimum payout. current, required and missing are on the share; requiredGross is the gross profit the minimum needs (200 at 80% needs 250) |
payout_interval | Too soon after the previous executed payout (until carries when the gap ends) |
open_bets | Last payout only: it ends the account, so it waits until every open bet has settled (current is the open stake) |
Every reason is blocking (blocking: true) except open_bets: the last payout may still be requested with bets open, and only its execution waits for them. There are no activity conditions on a funded payout: minimum active days and minimum bets are challenge rules only.
Process Withdrawal
POST /v1/users/:userId/withdrawbash
curl -X POST https://api.fundedfast.eu/v1/users/user-001/withdraw \
-H "X-API-Key: your-api-key" \
-H "X-Idempotency-Key: payout-user-001-2026-10-15-1" \
-H "Content-Type: application/json" \
-d '{"grossAmount": 500.00}'The X-Idempotency-Key header is required. Use a value unique to this payout and reuse it if you retry the same request, so a retry can never pay twice. Without it the request fails with 400 missing_idempotency_key; if FAST cannot reach its idempotency store it answers 503 service_unavailable rather than risk a duplicate, so retry later with the same key. Keys are remembered for 24 hours and may be up to 128 characters; reusing a key with a different body returns 409 idempotency_conflict. The SDK sets this header for you and keeps it stable across its own retries.
| Body field | Meaning |
|---|---|
grossAmount | The gross profit to take off the balance, in whole cents, from payout.minGrossAmount up to payout.withdrawableGross. The user's share is the profit split of it, rounded down to the cent; the operator keeps the rest. Required, except on the account's last allowed payout (payout.isFinal), which always takes the whole gross profit and may omit it |
deferred | Server key only: store the request as pending for an operator decision instead of executing it |
grossAmount is the only amount the endpoint takes. The user's share is never an input: a body with amount instead is a 400 validation_error.
Pending requests and operator decisions
A request from the widget (a player's own token) is never paid on the spot: it is stored as pending and answered 202 with "status": "pending", a payoutRequestId, the amount (share) and the grossAmount. A server-key call is executed at once unless it sends "deferred": true. While a request is pending the account refuses every new bet, so the figures cannot move under the operator's decision; bets already accepted settle normally.
The operator decides in the backoffice, or through the API:
GET /v1/admin/payout-requests?status=pending
POST /v1/admin/payout-requests/:id/confirm
POST /v1/admin/payout-requests/:id/reject {"reason": "optional text"}Confirm moves the money and fires funded_account.payout; reject changes nothing on the account (the profit stays, betting resumes) and fires funded_account.payout_rejected. Only an executed payout counts toward the number of payouts allowed. Confirm answers 409 in two expected cases, both on the account's last payout:
open_bets: the last payout ends the account, so it waits until every open bet has settled. Confirm once they have.payout_amount_changed: the whole gross profit is worth something else now that those bets settled. The request has been updated to the current figure; review it and confirm again.
A request still pending when the account closes (cancelled, refunded, revoked) is rejected with reason account_closed.
A tier can also set a mandatory payout threshold. When the virtual balance reaches it, FAST creates a pending request for the whole gross profit on its own, past the minimum payout, the gap and the first-payout deadline; executing it takes the balance back to the funded amount. It counts as one of the allowed payouts. New tiers get a threshold of 150% of the funded amount (+50%) unless you set another or null.
json
{
"status": "executed",
"payoutRequestId": "uuid",
"amount": 400.00,
"grossAmount": 500.00,
"isFinal": false,
"newBalance": 5350.00,
"userPayout": 400.00,
"ownStakeReturned": 100.00,
"rewardBonus": 0,
"totalPayout": 500.00,
"operatorShare": 100.00,
"forfeitedProfit": 0,
"accountClosed": false,
"correlationId": "uuid"
}On success, pay totalPayout to the user through your payment system. On the account's first payout this is the profit share plus the user's full own stake (ownStakeReturned); on later payouts ownStakeReturned is 0 and totalPayout equals userPayout (plus any rewardBonus). The own stake is not deducted from the funded balance; you pay it on top. Tax on the payout is a matter between you and the user: FAST's figures are before any tax.
| Field | Meaning |
|---|---|
amount / userPayout | The user's share: the profit split of grossAmount, rounded down to the cent |
grossAmount | Gross virtual profit taken off the balance |
ownStakeReturned | Own stake returned, first payout only, otherwise 0 |
rewardBonus | Paid on top from the user's payout_bonus_percent rewards, consumed by this payout; not deducted from the balance. 0 when there is none |
totalPayout | What you pay the user: userPayout + ownStakeReturned + rewardBonus |
operatorShare | grossAmount minus the user's share |
newBalance | Balance after the payout: the previous balance less grossAmount |
forfeitedProfit | Share a cap kept from the last payout, which can no longer be paid once the account ends |
accountClosed | Whether this payout reached the tier's maximum payout count and closed the account |
Profit Split Math
With an 80/20 split (user keeps 80%), on a 5,000 EUR funded account:
Current balance: 5,850.00 EUR
Funded amount: 5,000.00 EUR
Gross profit: 850.00 EUR
User takes (gross): 500.00 EUR
User share (80%): 400.00 EUR (paid to the user, before any tax)
Operator share (20%): 100.00 EUR
New balance: 5,350.00 EURThe 350 EUR of gross profit not taken stays on the balance, and nothing is split a second time. The user can take more later, under the same conditions.
The share is rounded down to the cent and the operator's share is the rest, so the two always add up to the gross: grossAmount: 333.33 at 80% pays 266.66 and leaves the operator 66.67.
Payout Conditions
All set per challenge tier, all measured on the user's share before any tax:
| Tier field | Effect |
|---|---|
fundedMinPayout | Smallest share a request may ask for. 200 at an 80% split needs 250 gross profit. The last payout is never stopped by it |
fundedPayoutIntervalDays | Days after an executed payout before the next can be requested. Null or 0 = no gap, the default |
fundedMaxPayouts | Number of payouts the account allows. The last one takes the whole gross profit, waits for open bets, and ends the account |
payoutCapPercent | Max user share per payout, as a percentage of the funded amount |
fundedTotalPayoutCap | Lifetime cap on the user's shares across all payouts |
fundedMandatoryPayoutThreshold | Balance at which FAST requests the whole gross profit on its own. Default on new tiers: 150% of the funded amount |
fundedFirstPayoutDays | Days from the account opening within which the first payout must be requested (see below). Default on new tiers: 30 |
First-payout deadline
With fundedFirstPayoutDays set, the user must request the first payout within that many days of the funded account opening. firstPayoutDeadlineAt in the payout state and in progress carries the date. A request filed in time keeps the right however long the operator takes to decide it. If the deadline passes with no payout requested (or with the only request rejected after it), the account ends: it is revoked with reason first_payout_deadline and FAST sends funded_account.revoked. Once a payout has executed the deadline no longer applies. null turns it off; tiers that existed before the deadline was introduced have none.
Payout Cap
If a payoutCapPercent is configured, each payout's user share is capped at that percentage of the funded amount. With a 20% cap on a 5,000 EUR account, one payout pays at most 1,000 EUR to the user; only the gross amount behind that share leaves the balance, and the rest of the profit stays on it for a later payout. fundedTotalPayoutCap limits the shares paid across the life of the account.
Operator overview
GET /v1/admin/funded-accounts?status=active&limit=200Every funded account with its start, ledger and virtual balance, gross profit, the user's share, what could be requested right now, executed and remaining payouts, the deadline for the first payout, the last request's status, and open bets as their potential return. status is active (the default), closed, revoked or all; limit defaults to 200, up to 2,000.
The summary always covers every active account, whatever the list filter:
| Field | Meaning |
|---|---|
activeAccounts | Active funded accounts |
payableNow / payableAccounts | Shares users could request right now with every condition met, and on how many accounts. Real only once requested and executed |
virtualGrossProfit | Virtual: balance above the funded amount on active accounts |
virtualProfitShare | Virtual: the users' split of it |
pending | Requests waiting for a decision: count, amount (shares), grossAmount |
executed | Payouts paid: count, amount (shares), grossAmount, operatorShare, ownStakeReturned, rewardBonus, and totalPaid (shares + returned stakes + bonuses) |
rejected | count of rejected requests |
open | Open bets: bets, stake, potentialReturn (stake x odds, the most they could add to virtual balances; not a liability) |
Each account also carries blockedBy, the reason codes that currently stop a request, and pending, the request waiting for a decision. The figures come from the same calculation as the widget and the request path, so the console never shows an amount a request would refuse. The SDK exposes it as admin.payouts.fundedAccounts().
Error Cases
| Status | Cause |
|---|---|
| 400 | missing_idempotency_key: no X-Idempotency-Key header |
| 400 | validation_error: grossAmount missing (on any payout but the last) or not positive |
| 400 | invalid_amount: grossAmount is not in whole cents, or so small that the share rounds to 0 |
| 400 | insufficient_withdrawable_balance: grossAmount above withdrawableGross |
| 400 | below_min_payout, payout_interval, max_payouts_reached, first_payout_deadline, no_profit: a tier payout rule is not met; reasons lists each one |
| 400 | open_bets: the last payout waits until every open bet has settled |
| 400 | payout_pending: a request is already waiting for a decision |
| 402 | withdrawal_declined: your approval URL declined the payout |
| 403 | approval_required: widget-initiated withdrawal with no approval URL configured |
| 404 | not_found: no active funded account for this user |
| 503 | service_unavailable: idempotency store unavailable, retry with the same key |
Withdrawal Flow
- Call
GET /v1/users/:userId/withdrawable. Ifpayout.canRequestisfalse, show the userpayout.reasonsand do not proceed. - Show the withdrawal form: the gross amount from
payout.minGrossAmountup topayout.withdrawableGross, with the share it pays beside it. On the last payout (payout.isFinal) there is nothing to choose: it is the whole gross profit. - Call
POST /v1/users/:userId/withdrawwithgrossAmountand anX-Idempotency-Key. - On
200(executed), paytotalPayoutto the user through your payment system. On202(pending), wait for the decision: FAST sendsfunded_account.payout_requestednow, andfunded_account.payoutorfunded_account.payout_rejectedonce it is made. - FAST dispatches a
funded_account.payoutwebhook when the money moves.