Skip to content

Payouts​

Earnings and payout management


Get user earnings​

GET
/payouts/earnings

Returns the authenticated creator's earnings summary in integer CENTS (#1499) — every field is suffixed _cents and must be divided by 100 before display. The target is always derived from the authenticated principal — any ?userId query param is ignored (#1072). total_cents and fees_cents are lifetime aggregates from the canonical ledger. For creators with an active Stripe Connect account, available_cents, pending_cents and withdrawn_cents come from Stripe directly (pending_cents additionally includes platform-held net funds that haven't transferred yet). Creators without a Connect account see available_cents and withdrawn_cents as 0 and pending_cents equal to total_cents (everything sits on FundlyHub's platform balance awaiting onboarding). Rate limited to 100 requests per minute per account.

Authorizations​

BearerAuth

In the browser, authentication rides on the httpOnly session cookies set by /cognito/signin or the Google / Apple sign-in at /cognito/oauth/{provider}. For scripts and for Swagger UI testing, paste an API key (fh_live_…, created with POST /api-keys); a Cognito JWT is accepted too. Sign-in does not return a token in its body.

Type
HTTP (bearer)

Responses​

Earnings summary (all values are integer cents)

application/json
JSON
{
"total_cents": 0,
"pending_cents": 0,
"available_cents": 0,
"withdrawn_cents": 0,
"ready_to_pay_out_cents": 0,
"fees_cents": 0
}

Playground​

Server
Authorization

Samples​


Get pending earnings breakdown​

GET
/payouts/earnings/pending-breakdown

Per-donation attribution of the creator's not-yet-available money, lazy-loaded by the Earnings tab's Pending-tile dialog (#1131). The target is always the authenticated principal. Each donation is classified into one of three states: destination_charge_pending (Stripe holds it for this creator, card settlement pending), platform_held_unsettled (platform balance, awaiting settlement), or platform_held_settled (platform balance, eligible for release now). Rows already transferred to the creator's Stripe balance, settled destination charges, and rows under review are excluded. Rate limited to 100 requests per minute per account.

Authorizations​

BearerAuth

In the browser, authentication rides on the httpOnly session cookies set by /cognito/signin or the Google / Apple sign-in at /cognito/oauth/{provider}. For scripts and for Swagger UI testing, paste an API key (fh_live_…, created with POST /api-keys); a Cognito JWT is accepted too. Sign-in does not return a token in its body.

Type
HTTP (bearer)

Responses​

Pending breakdown (all amounts in cents)

application/json
JSON
{
"pending_breakdown": {
"has_payout_account": true,
"total_cents": 0,
"destination_charge_cents": 0,
"platform_held_unsettled_cents": 0,
"platform_held_settled_cents": 0,
"donations": [
{
"donation_id": "string",
"amount_cents": 0,
"fundraiser_title": "string",
"fundraiser_slug": "string",
"state": "string",
"available_on": "string",
"donated_at": "string"
}
]
}
}

Playground​

Server
Authorization

Samples​


List Stripe connected accounts​

GET
/stripe/accounts

Returns the authenticated user's Stripe Connect accounts. Refreshes each account's enabled/onboarding flags from the Stripe API on read (transient downgrades are suppressed unless Stripe reports a concrete requirement). Returns an empty array if the user has no connected account. Rate limited to 100 requests per minute per account.

Authorizations​

BearerAuth

In the browser, authentication rides on the httpOnly session cookies set by /cognito/signin or the Google / Apple sign-in at /cognito/oauth/{provider}. For scripts and for Swagger UI testing, paste an API key (fh_live_…, created with POST /api-keys); a Cognito JWT is accepted too. Sign-in does not return a token in its body.

Type
HTTP (bearer)

Responses​

Connected accounts (array; empty if none)

application/json
JSON
[
{
"stripe_account_id": "string",
"charges_enabled": true,
"payouts_enabled": true,
"details_submitted": true,
"onboarding_complete": true,
"country": "string",
"default_currency": "string",
"created_at": "string",
"requirements": {
}
}
]

Playground​

Server
Authorization

Samples​


Start or resume Stripe Connect onboarding​

POST
/stripe/connect/accounts

Creates the caller's Stripe Connect account if they do not have one, then returns a fresh onboarding link in either case. Send the creator to onboardingUrl; the link is single-use and short-lived, so call this again rather than caching it.
If the stored account no longer exists at Stripe, a new account is created transparently. Requires a bearer session; rate limited to 100 requests per minute per account.

Authorizations​

BearerAuth

In the browser, authentication rides on the httpOnly session cookies set by /cognito/signin or the Google / Apple sign-in at /cognito/oauth/{provider}. For scripts and for Swagger UI testing, paste an API key (fh_live_…, created with POST /api-keys); a Cognito JWT is accepted too. Sign-in does not return a token in its body.

Type
HTTP (bearer)

Request Body​

application/json
JSON
{
"businessType": "individual"
}

Responses​

Account id plus a fresh onboarding link

application/json
JSON
{
"accountId": "acct_1AbCdEfGhIjKlMnO",
"onboardingUrl": "string",
"status": "string"
}

Playground​

Server
Authorization
Body

Samples​


Get connected-account status​

GET
/stripe/connect/accounts/{accountId}/status

Reads one connected account straight from Stripe and refreshes the cached flags on FundlyHub's side. The account is addressed by its Stripe id, which you get from GET /stripe/accounts.
Ownership: accountId must be a connected account the caller owns: their own account, or an organization's account where the caller holds org.read_payouts in that organization. Any other id, including one that does not exist, returns 404; the response does not distinguish the two.
This is a pure read: it never moves money. Requires a bearer session; rate limited to 100 requests per minute per account.

Authorizations​

BearerAuth

In the browser, authentication rides on the httpOnly session cookies set by /cognito/signin or the Google / Apple sign-in at /cognito/oauth/{provider}. For scripts and for Swagger UI testing, paste an API key (fh_live_…, created with POST /api-keys); a Cognito JWT is accepted too. Sign-in does not return a token in its body.

Type
HTTP (bearer)

Parameters​

Path Parameters

accountId*

Stripe connected-account id.

Type
string
Required
Example"acct_1AbCdEfGhIjKlMnO"

Responses​

Account status

application/json
JSON
{
"status": "string",
"chargesEnabled": true,
"payoutsEnabled": true,
"detailsSubmitted": true,
"requirements": {
}
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Create an embedded-components account session​

POST
/stripe/connect/sessions

Mints a Stripe Account Session client secret for the embedded Connect components (account_onboarding, payouts, payments). Omit accountId to use the caller's most recent connected account.
Ownership: an explicit accountId must be a connected account the caller owns: their own account, or an organization's account where the caller holds org.manage_payouts in that organization. Any other id, including one that does not exist, returns 404 and no session is created.
Requires a bearer session; rate limited to 100 requests per minute per account.

Authorizations​

BearerAuth

In the browser, authentication rides on the httpOnly session cookies set by /cognito/signin or the Google / Apple sign-in at /cognito/oauth/{provider}. For scripts and for Swagger UI testing, paste an API key (fh_live_…, created with POST /api-keys); a Cognito JWT is accepted too. Sign-in does not return a token in its body.

Type
HTTP (bearer)

Request Body​

application/json
JSON
{
"accountId": "string"
}

Responses​

Account session

application/json
JSON
{
"clientSecret": "string"
}

Playground​

Server
Authorization
Body

Samples​


List transfers to the creator's Stripe balance​

GET
/stripe/connect/transfers

Platform → creator transfers recorded for the authenticated caller, newest first. These are movements onto the creator's Stripe balance; payouts to their bank are a separate list (GET /stripe/connect/payouts). Requires a bearer session; rate limited to 100 requests per minute per account.

Authorizations​

BearerAuth

In the browser, authentication rides on the httpOnly session cookies set by /cognito/signin or the Google / Apple sign-in at /cognito/oauth/{provider}. For scripts and for Swagger UI testing, paste an API key (fh_live_…, created with POST /api-keys); a Cognito JWT is accepted too. Sign-in does not return a token in its body.

Type
HTTP (bearer)

Parameters​

Query Parameters

limit
Type
integer
Default
10
Maximum
100
offset
Type
integer
Default
0

Responses​

Transfer rows (bare array)

application/json
JSON
[
{
"id": "string",
"stripe_transfer_id": "string",
"donation_id": "string",
"fundraiser_id": "string",
"amount_cents": 0,
"application_fee_cents": 0,
"currency": "string",
"status": "string",
"failure_reason": "string",
"created_at": "string",
"arrived_at": "string"
}
]

Playground​

Server
Authorization
Variables
Key
Value

Samples​


List payouts to the creator's bank​

GET
/stripe/connect/payouts

Payouts from the creator's Stripe balance to their bank account. Read live from Stripe so the list matches what the creator sees in their bank; if Stripe is unreachable the endpoint falls back to FundlyHub's own records, which only cover payouts this API initiated or that a webhook recorded.
arrival_date and created are Unix timestamps in seconds, not ISO strings. Stripe paginates by cursor, so offset only applies to the database fallback. Requires a bearer session; rate limited to 100 requests per minute per IP.

Authorizations​

BearerAuth

In the browser, authentication rides on the httpOnly session cookies set by /cognito/signin or the Google / Apple sign-in at /cognito/oauth/{provider}. For scripts and for Swagger UI testing, paste an API key (fh_live_…, created with POST /api-keys); a Cognito JWT is accepted too. Sign-in does not return a token in its body.

Type
HTTP (bearer)

Parameters​

Query Parameters

limit
Type
integer
Default
10
Maximum
100
offset

Only honoured by the database fallback path.

Type
integer
Default
0

Responses​

Payout rows (bare array)

application/json
JSON
[
{
"id": "po_1AbCdEfGhIjKlMnO",
"amount": 0,
"currency": "string",
"status": "string",
"arrival_date": 0,
"created": 0,
"destination": "string"
}
]

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Withdraw available balance to the bank​

POST
/stripe/connect/payouts

Initiates a standard payout from the caller's connected Stripe balance to their bank account. Omit amountCents to withdraw the full available balance.
The minimum payout is $1.00 (100 cents) and the amount may not exceed the available balance. The caller must have a payout-enabled connected account. Gated by the features.payouts flag; requires a bearer session; rate limited to 100 requests per minute per account.

Authorizations​

BearerAuth

In the browser, authentication rides on the httpOnly session cookies set by /cognito/signin or the Google / Apple sign-in at /cognito/oauth/{provider}. For scripts and for Swagger UI testing, paste an API key (fh_live_…, created with POST /api-keys); a Cognito JWT is accepted too. Sign-in does not return a token in its body.

Type
HTTP (bearer)

Request Body​

application/json
JSON
{
"amountCents": 0
}

Responses​

Payout initiated

application/json
JSON
{
"payoutId": "po_1AbCdEfGhIjKlMnO",
"amount": 0,
"currency": "string",
"status": "string",
"arrivalDate": "string"
}

Playground​

Server
Authorization
Body

Samples​


Refresh payouts and withdrawals from Stripe​

POST
/stripe/connect/payouts/reconcile

Re-reads every payout of the caller's connected Stripe account and repairs FundlyHub's own records of them: the payout rows, the link between each payout and the donations it carried, and the payout entries in the financial ledger. These are what a campaign's Updates feed (GET /projects/{fundraiserId}/updates) lists as withdrawals, so a payout Stripe made on its automatic schedule shows up there without waiting for a webhook. Moves no money. Never a dry run.
Omit accountId to refresh the caller's own account. An acct_… id of an organization account the caller can manage payouts for is also accepted; any other id answers 404, like an unknown one.
Requires a bearer session; rate limited to 100 requests per minute per account, and to one refresh per account per minute (429 with Retry-After).

Authorizations​

BearerAuth

In the browser, authentication rides on the httpOnly session cookies set by /cognito/signin or the Google / Apple sign-in at /cognito/oauth/{provider}. For scripts and for Swagger UI testing, paste an API key (fh_live_…, created with POST /api-keys); a Cognito JWT is accepted too. Sign-in does not return a token in its body.

Type
HTTP (bearer)

Request Body​

application/json
JSON
{
"accountId": "acct_1AbCdEfGhIjKlMnO"
}

Responses​

Refresh result

application/json
JSON
{
"accountId": "acct_1AbCdEfGhIjKlMnO",
"payoutsFound": 0,
"payoutRowsInserted": 0,
"payoutRowsUpdated": 0,
"donationsStamped": 0,
"donationsCleared": 0,
"balanceTransactionsBackfilled": 0,
"ledgerRowsWritten": 0,
"errors": 0,
"payouts": [
{
"id": "po_1AbCdEfGhIjKlMnO",
"status": "string",
"amount": 0,
"currency": "string",
"row": "string",
"donationsStamped": 0,
"ledgerRowsWritten": 0,
"ok": true
}
]
}

Playground​

Server
Authorization
Body

Samples​


Get payout methods and schedule​

GET
/stripe/connect/payout-settings

The bank accounts and debit cards attached to the caller's connected account, plus the payout schedule Stripe currently applies. Requires a bearer session; rate limited to 100 requests per minute per account.

Authorizations​

BearerAuth

In the browser, authentication rides on the httpOnly session cookies set by /cognito/signin or the Google / Apple sign-in at /cognito/oauth/{provider}. For scripts and for Swagger UI testing, paste an API key (fh_live_…, created with POST /api-keys); a Cognito JWT is accepted too. Sign-in does not return a token in its body.

Type
HTTP (bearer)

Responses​

Payout methods and schedule

application/json
JSON
{
"payoutMethods": [
{
"id": "string",
"type": "string",
"bankName": "string",
"last4": "string",
"currency": "string",
"country": "string",
"routingNumber": "string",
"status": "string",
"defaultForCurrency": true,
"brand": "string"
}
],
"schedule": "string"
}

Playground​

Server
Authorization

Samples​


Update the payout schedule​

PUT
/stripe/connect/payout-schedule

Sets how often Stripe pays the creator out. weekly requires weeklyAnchor (a weekday name), monthly requires monthlyAnchor (1–31); manual and daily take neither. Requires a bearer session; rate limited to 100 requests per minute per account.

Authorizations​

BearerAuth

In the browser, authentication rides on the httpOnly session cookies set by /cognito/signin or the Google / Apple sign-in at /cognito/oauth/{provider}. For scripts and for Swagger UI testing, paste an API key (fh_live_…, created with POST /api-keys); a Cognito JWT is accepted too. Sign-in does not return a token in its body.

Type
HTTP (bearer)

Request Body​

application/json
JSON
{
"interval": "string",
"weeklyAnchor": "monday",
"monthlyAnchor": 0
}

Responses​

The schedule Stripe now applies

application/json
JSON
"string"

Playground​

Server
Authorization
Body

Samples​


Get a Stripe dashboard link​

GET
/stripe/connect/express-login

Returns a URL into Stripe for the caller's connected account — a single-use Express login link deep-linked to payouts for Express accounts, or the Connect dashboard URL for other account types. Do not cache it. Requires a bearer session; rate limited to 100 requests per minute per account.

BearerAuth

In the browser, authentication rides on the httpOnly session cookies set by /cognito/signin or the Google / Apple sign-in at /cognito/oauth/{provider}. For scripts and for Swagger UI testing, paste an API key (fh_live_…, created with POST /api-keys); a Cognito JWT is accepted too. Sign-in does not return a token in its body.

Type
HTTP (bearer)

Dashboard URL

application/json
JSON
{
"url": "string"
}
Server
Authorization

Powered by VitePress OpenAPI

Built with VitePress