Payments & Payouts
Admins can see platform-wide and per-user revenue, review the creator cashout queue, and configure global payout/monetization settings. Four pages: /payments (overview), /payments/cashouts (manual cashout review), /payments/settings (global config), /payments/users/[userId] (per-user drill-down).
This is the admin-side counterpart the user-facing Creator Payouts doc explicitly defers to ("Admin review of manual cashout requests ... and the platform-wide Stripe-vs-manual toggle live in the separate admin GraphQL schema and frontend-admin — not covered by this page"). It was previously undocumented — this is a new doc.
Implementation checklist
Payments overview (/payments)
- Global revenue dashboard (
adminGetGlobalRevenue)
Cashout review queue (/payments/cashouts)
- List cashout requests, filterable by status/user/provider/date range (
adminGetCashouts) - Look up a single cashout by id, no ownership check (
adminGetCashout) - View a user's registered CLABE/RFC/billing address for manual review (
adminGetPayoutProfile) - Cancel a cashout, with a reason (
adminCancelCashout) - Mark a manual cashout as processing (
adminMarkCashoutProcessing) - Complete a manual cashout, with a reference (
adminCompleteManualCashout) - Reject a manual cashout, returning coins to the creator (
adminRejectManualCashout) - Emergency-freeze/unfreeze a user's payout account, independent of their Stripe Connect status (
adminSetPayoutAccountDisabled)
Global payout settings (/payments/settings)
- View current settings (
adminGetPayoutSettings) - Update settings (
adminUpdatePayoutSettings), covering:coinsPerUsd— coin→cash conversion ratepayoutHoldDays— hold period before a cashout is eligibleminCashoutCoins— minimum balance to request a cashoutpayoutsEnabledGlobally— platform-wide kill switchplatformCashoutFeePercent— platform's cut of each cashoutcashoutProvider— the Stripe-vs-manual toggle the payouts doc refers toverificationPriceCoins— price of paid verification (also configured here, not on a dedicated verification-settings screen)referralReferrerBonusCoins/referralReferredBonusCoins— the two referral signup bonuses (see Referral Program)
Per-user revenue (/payments/users/[userId])
- Per-user revenue drill-down (
adminGetUserRevenue)
Where this lives
Backend
apps/backend/graphql/types/admin/payout-admin.type.js— schema for all operations aboveapps/backend/graphql/resolvers/admin/payout-admin.resolver.js— resolversapps/backend/managers/admin-managers/payout-admin.manager.js— cashout review business logicapps/backend/managers/admin-managers/payout-settings.manager.js— reads/writes theSystemSettingsingleton row backing the settings above
Frontend — apps/frontend-admin/src/app/payments/page.tsx, payments/cashouts/page.tsx, payments/settings/page.tsx, payments/users/[userId]/page.tsx.
GraphQL reference
query GlobalRevenue($dateFrom: DateTime, $dateTo: DateTime) {
adminGetGlobalRevenue(dateFrom: $dateFrom, dateTo: $dateTo) {
totalCoinsPurchased totalPurchaseRevenue completedPurchases totalCashedOut
paidCashoutCount pendingCashoutCount canceledCashoutCount failedCashoutCount
netRevenue activePayoutAccounts
}
}
query Cashouts($filters: AdminCashoutFilters, $limit: Int, $offset: Int) {
adminGetCashouts(filters: $filters, limit: $limit, offset: $offset) {
id coinAmount cashAmount currency status provider providerTransferId
createdAt failureReason canceledReason user { id username }
}
}
# AdminCashoutFilters: { status, userId, provider, dateFrom, dateTo }
query Cashout($id: ID!) { adminGetCashout(id: $id) { id status coinAmount cashAmount provider } }
query PayoutProfile($userId: ID!) {
adminGetPayoutProfile(userId: $userId) { clabe rfc billingAddressLine1 billingCity billingState billingZip billingCountry }
}
mutation CancelCashout($id: ID!, $reason: String) { adminCancelCashout(id: $id, reason: $reason) { id status } }
mutation MarkCashoutProcessing($id: ID!) { adminMarkCashoutProcessing(id: $id) { id status } }
mutation CompleteManualCashout($id: ID!, $reference: String) {
adminCompleteManualCashout(id: $id, reference: $reference) { id status }
}
mutation RejectManualCashout($id: ID!, $reason: String) {
adminRejectManualCashout(id: $id, reason: $reason) { id status }
}
mutation SetPayoutAccountDisabled($userId: ID!, $disabled: Boolean!, $reason: String) {
adminSetPayoutAccountDisabled(userId: $userId, disabled: $disabled, reason: $reason) { userId adminDisabled }
}
query PayoutSettings { adminGetPayoutSettings {
coinsPerUsd payoutHoldDays minCashoutCoins payoutsEnabledGlobally
platformCashoutFeePercent cashoutProvider verificationPriceCoins
referralReferrerBonusCoins referralReferredBonusCoins
}}
mutation UpdatePayoutSettings($input: PayoutSettingsInput!) {
adminUpdatePayoutSettings(input: $input) { id coinsPerUsd payoutHoldDays cashoutProvider }
}
query UserRevenue($userId: ID!) {
adminGetUserRevenue(userId: $userId) {
totalCoinsPurchased totalAmountSpent completedPurchases lifetimeEarned
lifetimeCashedOut totalCashedOutAmount currentBalance availableForCashout cashoutCount
}
}