Skip to content

Wallet ​

Creator wallet balances, transaction history, affiliate earnings view, payout requests, and dashboard KPI summaries used for creator analytics.


Wallet resource ​

Current wallet responses include:

FieldTypeNotes
availableintegerFunds ready for payout.
holdintegerFunds currently on hold.
pendingintegerFunds currently in payout processing.
totalintegerAggregate wallet total.
referral_revenueintegerAffiliate revenue amount.
cashout_availablebooleanWhether a payout can be requested now: available is at least payout_minimum and no payout block applies (since 2026-10-14 the minimum counts).
payout_minimumintegerThe smallest payout the account can request, in cents of the wallet's currency (30.00 today). Also on every entry of balances[].
crypto_estimateobject or nullCrypto payouts (2026-10-08): what available is expected to buy in USDT after fees, at the rate of the day - usdt (string, 2 decimals) and rate, plus the deducted fees in cents. An estimate, not a promise; null unless the account pays out by crypto and a rate is known. Also on every entry of balances[].
hold_period_daysintegerDays a sale stays on hold for this account before it moves to available: 14 by default, set per account by Fangate.
converted_earningsbooleantrue once a share earned in another currency was converted into this account's currency (see below).
conversion_buffer_percentagenumberThe conversion buffer in force, in percent.
transactionsarrayOne page of wallet rows (see Transaction rows).
transactions_metaobjectPaging of transactions: current_page, last_page, per_page, total.

What a price becomes: GET /api/fees/preview ​

GET /api/fees/preview?price=1000 answers, for the account called (name it with X-Fangate-Account), what a sale at this price brings: net is exactly what the seller receives; the buyer pays gross, or with_age_check.gross where the buyer's country requires the age check. fees is every fee in one sum. Minor units of the account's currency; price at least 500. Any API key that reads products may call it. The account's current fees apply - a sale keeps the numbers it was booked with. The values below only show the shape; your account's fees decide the numbers.

json
{ "price": 1000, "currency": "EUR", "net": 825, "gross": 1100, "fees": 275, "with_age_check": { "gross": 1150, "fees": 325 } }

Refund requests ​

Fangate does not refund through the API, but you can ask for it: POST /api/transactions/{transaction_id}/refund-request with transaction_id as payment webhooks send it (txn_123) and an optional reason (up to 1000 characters). It works for a paid sale of the account that is called (name it with X-Fangate-Account), up to 30 days after the sale, once per sale; an API key needs can_create_new_urls (Manage content). The answer is 201 with status: requested - nothing is refunded yet. Fangate reviews the request and passes it to the payment provider. When the refund goes through, the ordinary payment.cancelled follows; when it does not, refund_request.rejected with the reason. An agency account always names the account with X-Fangate-Account; without it the call answers 403, because the agency account itself has no sales. Errors: 404 for a sale that is not in the account, 422 with transaction_not_refundable (not paid or already reversed), refund_request_window_closed (older than 30 days) or refund_request_exists.

Hold period ​

Every earning is held before it can be paid out: a sale, an agency's share of a sale and an affiliate commission alike. The hold starts when the earning is booked - the moment the payment is confirmed - and lasts hold_period_days of the account that receives it: 14 days unless Fangate set another period for that account. It is the same for every payment method. Once the period is over, the amount moves from hold to available within a few minutes.

Shares earned in another currency ​

A sale is always booked in the seller's currency. An agency's share of a creator's sale and an affiliate commission go to an account that may hold another currency: such a share is converted into the recipient's currency when it is booked - at the reference exchange rate, minus a conversion buffer of up to 5 % (the value in force is conversion_buffer_percentage), rounded down to the cent. Exchange rates move between the moment a share is booked and the moment it is paid out, and banks charge for converting currencies. To cover both, Fangate deducts a conversion fee of up to 5 % from the reference rate when the share is booked. The seller's own earnings are never converted. A refund or chargeback takes back exactly the converted amount that was credited. If no reference rate is available at the moment of the sale, the share is booked unconverted in the sale's currency and shows up as its own balance.


GET /api/dashboard/summary ​

Pre-aggregated dashboard KPIs for the authenticated creator (content counts, link clicks, unlocks, product revenue totals, top-performing products, wallet buckets).

  • Auth required: Yes
  • Roles: Authenticated creator with a wallet
  • Content type: none

Response shape notes ​

The payload extends the historical single-account shape with:

FieldTypeNotes
currency_unifiedbooleanFor one account, always true.
accountsarrayOne object per creator in the summary (single-account: one element) with user_id, email, display_name, currency_id, currency_code, and wallet_balance.
wallet_balanceobject or nullTop-level aggregate wallet buckets when every account shares the same currency_id; otherwise null (use per-account accounts[].wallet_balance).
total_content_itemsintegerCount of qualifying products with complete media.
total_link_clicksintegerSum of short-link views.
total_unlocksintegerSum of product unlocks.
total_product_revenueintegerSum of total_earnings (minor units).
overall_conversion_ratenumberDerived from totals.
top_performingarrayUp to five products ranked by conversion with revenue and thumbnail metadata.

Clients that need full wallet transaction history for charts should still call GET /api/wallet with the relevant bearer token per account.


POST /api/dashboard/summary/aggregate ​

Same KPI aggregation as GET /api/dashboard/summary, but merged across multiple creator accounts.

  • Auth required: Yes (primary account’s api token in Authorization)
  • Roles: Authenticated creator with a wallet on every resolved account
  • Content type: application/json

Request body ​

FieldTypeRequiredNotes
additional_tokensstring[]NoDeprecated when the bearer has linked sub-accounts (master / hybrid). Ignored in that case; aggregation uses persisted links from account_group_members instead. For standalone and pure sub_account (no own links), only the bearer is aggregated. Pure sub_account accounts must not send this field → 403.

The primary user is always included from the bearer token. Accounts with linked_accounts automatically include every sub-account they linked (from login / GET /api/user/linked-accounts).

Important semantics ​

  • Trust model: Combined metrics for multiple creators are allowed only when the backend recognizes a master → sub-account link created by the bearer (or the caller is aggregating only themselves). Holding another user’s token in additional_tokens does not grant access.
  • Currency: If combined accounts use different currency_id values, currency_unified is false and root wallet_balance is null; use each accounts[].wallet_balance and interpret total_product_revenue with care across currencies.

Error examples ​

Sub-account without own links sent additional_tokens:

json
{
  "success": false,
  "errors_message": "Sub-accounts without their own linked accounts cannot aggregate other accounts.",
  "data": null
}

GET /api/wallet ​

Return wallet balances and creator wallet transactions.

  • Auth required: Yes
  • Roles: Authenticated creator with wallet

Query parameters ​

ParameterTypeRequired
pageintegerNo
limitintegerNo
fromstringNo
tostringNo
currencystringNo
bookingsbooleanNo
activitystringNo
sortstringNo

from / to narrow the transaction list to rows created in that window (UTC). Both take a date (2026-09-17) or an ISO 8601 date-time; a plain to date covers that whole day, so from=2026-09-17&to=2026-09-17 is one day. A date-time with an offset is taken as that instant (2026-09-17T16:30:00+02:00 is 14:30 UTC) - URL-encode the plus sign as %2B, a bare + in a query string is a space. Without them the list is complete. An unparsable value or a to before from answers 422 (errors_code: validation_failed).

The other parameters only shape the transaction list; the balances in the response stay those of the account currency:

  • currency - ISO code (usd, EUR, …): list the rows of the account's balance in that currency. An account that holds no balance in it gets an empty list.
  • bookings=1 - one row per booking: the hold and release rows of an earning are left out (its state is on the earning itself, see hold_status), and so are empty rows other than sales.
  • activity - earnings, refunds, payouts or affiliate: only rows of that kind. Refunds and chargebacks of affiliate commissions count as affiliate.
  • sort - newest (default), oldest or largest (by amount).

An unknown value of any of them answers 422 (errors_code: validation_failed).

Success response example ​

json
{
  "success": true,
  "errors_message": null,
  "data": {
    "available": 15000,
    "hold": 3000,
    "pending": 5000,
    "total": 23000,
    "referral_revenue": 2500,
    "cashout_available": true,
    "transactions": [
      {
        "id": 1,
        "amount": 550,
        "type": "product_earning",
        "booking_kind": "earning",
        "hold_status": "on_hold",
        "hold_until": "2026-05-04T10:15:00+00:00",
        "counterparty": null,
        "created_at": "2026-04-20 10:15:00",
        "available_at": null,
        "hold_period_days": null,
        "days_until_available": null,
        "title": "Money for a photo",
        "product_id": 42,
        "product_title": "Beach set",
        "transaction_id": "txn_123"
      }
    ],
    "transactions_meta": { "current_page": 1, "last_page": 1, "per_page": 15, "total": 1 }
  }
}

Transaction rows ​

transactions is one page of the wallet rows, sized by limit and moved with page (newest first unless sort says otherwise); transactions_meta tells how many pages there are. Each row carries:

FieldTypeNotes
idintegerWallet row id - not the txn_{id} of the payment webhook; that is transaction_id below.
transaction_idstring or nullThe sale's id exactly as payment webhooks send it in data.transaction_id (txn_123); null for rows that are not a sale. One sale can show up in more than one row (the hold and its release).
amountintegerMinor units of the wallet currency (550 = 5.50). Always positive - whether money came in or went out follows from booking_kind.
typestringLedger row kind, e.g. product_earning, agency_share, affiliate_earning, refund, fee, hold, pending, withdrawal.
booking_kindstringWhat the row means: earning and affiliate (money in), refund and fee (money out), payout_requested (moved from available to processing), payout_paid (money out), payout_declined (the requested amount was taken out of processing), hold and release (money moved between on hold and available), other.
usdt_estimatestring or nullpayout_requested rows of a crypto payout (2026-10-08): what the requested amount buys in USDT at today's rate after fees, null otherwise. The payout confirmation names what was actually sent.
hold_statusstring or nullEarnings only (product_earning, agency_share, affiliate_earning): on_hold, available, or reversed once the sale was refunded or charged back. null for every other row.
hold_untilstring or nullEarnings only: while on_hold the moment it becomes available, once available the moment it was released; ISO 8601.
counterpartystring or nullAgency share rows (agency_share): the public name of the creator whose sale it was. null otherwise.
product_idinteger or nullThe product a sale row belongs to; null for rows that are not a sale (payouts, affiliate earnings, holds).
product_titlestring or nullTitle of that product.
saleobject or nullThe sale behind the row in minor units of the sale's currency: gross (what the buyer paid), fees (every fee in one sum, age check included) and net (the seller's earning), plus currency. gross = fees + net. Also status - paid, or reversed once the sale was refunded or charged back, on every row of that sale - with reversed_at and reversal_reason (refund, chargeback or other, as payment.cancelled names it). null for rows that are not a sale and for affiliate commissions - those belong to another creator's sale.
client_referencestring or nullYour own reference of the product sold (set on POST/PATCH /api/products), so a row matches your order without a lookup. null for rows without a sale and for affiliate commissions.
available_at, hold_period_days, days_until_availableHold information; the last two only on hold rows.

Reconciling a lost webhook: list the period (from / to), collect the transaction_id values and compare them with the data.transaction_id of the webhooks you received. For a sale you never heard of, the net amount is amount and the product product_id - or have the webhook sent again with POST /api/webhooks/{id}/redeliveries.


GET /api/wallet/affiliate ​

Return affiliate-only revenue and affiliate wallet transactions.

  • Auth required: Yes
  • Roles: Authenticated creator with wallet

Query parameters ​

ParameterTypeRequired
pageintegerNo
limitintegerNo

Success response example ​

json
{
  "success": true,
  "errors_message": null,
  "data": {
    "referral_revenue": 2500,
    "transactions": {
      "data": [
        {
          "id": 33,
          "amount": 220,
          "type": "affiliate_earning",
          "created_at": "2026-04-20 10:15:00",
          "title": "Referral revenue"
        }
      ]
    }
  }
}

POST /api/wallet/cashout ​

Create a payout request for the creator's full currently available balance.

The available balance must be at least 30.00 in the wallet's currency (since 2026-10-14). Below that the request is refused with payout_below_minimum and nothing moves; the minimum itself goes through. GET /api/wallet says so beforehand: cashout_available is false below payout_minimum. Refusals come in this order: payout_account_required, the agency block (payout_blocked_reason), then payout_below_minimum; an empty wallet answers 400 "No available funds".

  • Auth required: Yes
  • Roles: Authenticated creator with wallet
  • Content type: no body required

Request body ​

No request body is currently required.

Success response example ​

json
{
  "success": true,
  "errors_message": null,
  "data": "Cashout created successfully"
}

Error examples ​

json
{
  "success": false,
  "errors_message": "No available funds",
  "data": null
}

Without a saved payout account (since 2026-09-27; see Users):

json
{
  "success": false,
  "errors_message": "Add your payout account under Settings before requesting a payout.",
  "errors_code": "payout_account_required",
  "data": null
}

Below the minimum payout (since 2026-10-14):

json
{
  "success": false,
  "errors_message": "The minimum payout is 30.00 USD.",
  "errors_code": "payout_below_minimum",
  "data": null
}

Side effects ​

  • backend creates payout state from current wallet
  • current implementation uses the wallet service and does not ask the API client for a payout amount

Transaction behavior ​

Current public wallet responses expose transaction items with:

FieldType
idinteger
amountinteger
typestring
created_atstring
titlestring or null

Do not assume every internal payout/admin transaction type is exposed publicly.


Fangate backend developer documentation