Skip to content

Complete REST API for FundlyHub — the AI-powered fundraising platform.

Authentication

The web app authenticates with httpOnly session cookies (access_token,
id_token, refresh_token) that POST /cognito/signin and the OAuth
callback set. Sign-in does not return tokens in its body.

Scripts and integrations authenticate with an API key: create one
with POST /api-keys from a signed-in session and send it as
Authorization: Bearer fh_live_…. A Cognito JWT is also accepted in the
same header. An API key acts as its owner, with every permission the
owner holds — treat it like a password. A key expires (at most one year
after it is created), cannot create or revoke API keys, and stops working
while its owner's account is not active. Send one credential per
request: either the session cookies or an Authorization header.

A missing credential answers 401, and so does a session token that is
present but invalid or expired (Invalid token, code: TOKEN_INVALID) or
that cannot be verified (code: TOKEN_VERIFICATION_FAILED): refresh the
session and retry. An API key that is unknown, expired or revoked, or whose
owner's account is not active, answers 401 (Invalid API key). 403 is
reserved for an authenticated caller who is not allowed to do something.

Operations that show no security requirement are genuinely public. Where
an operation lists both BearerAuth and {}, authentication is optional
and changes what comes back — an owner sees their own drafts, a signed-in
donor gets the gift attributed to their account.

Some endpoints additionally require a specific permission; where that
is the case the permission is named in the operation's description, and a
session without it gets 403 with required_permission in the body.
Several write endpoints also require a verified email address
(403 with code: EMAIL_NOT_VERIFIED) or sit behind a feature flag
(403 with feature_key). A flag with no stored setting counts as on.

Response envelopes

Most read endpoints wrap their payload: a single object comes back as
{ "data": { … } }, and a collection as { "data": [ … ] }, with
paginated collections adding { "pagination": { "limit", "offset", "total" } }. This is a convention rather than a rule — a handful of
endpoints return a bare object or a bare array, and each operation below
documents the shape it actually returns. Errors are always unwrapped:
{ "error": "…", "message": "…" }, sometimes with a machine-readable
code or a details array of validation failures.

Rate limits

A global limiter of 100 requests/minute per IP covers the API.
Public browsing reads — campaign, organization, category, platform-stats
and search reads, and the profile reads — are exempt from it, and most
of them count against a 300/min per IP bucket instead (an operation
that can answer 429 lists it). Other routes add a tighter bucket on
top of the global one:

  • Authentication (sign-up, sign-in, password reset and change, unsubscribe writes, platform tips): 10/min per IP
  • Verification resends and private-contact changes: 5/min per user (per IP for a signed-out resend)
  • Public writes that send mail or store free text (receipt emails, donor notes, DMCA notices, ambassador applications): 5/min per IP
  • Financial and endorsement endpoints (earnings, Stripe Connect, endorsements, receipt resends): 100/min per account
  • Organization creation: 5/hour per (IP, user)
  • Organization member lookups and adds (GET /org-admin/{slug}/users/search, POST /org-admin/{slug}/members): 30/min per user, one bucket for both
  • Campaign media and outcome-report writes: 30 per 15 minutes per (IP, user)
  • Referral clicks: 120/min per caller; card share images: 120/min per IP; campaign presence heartbeats: 4/min per IP and campaign
  • AI endpoints: 10/min per user, applied inside the handler
  • AI image generation: 10/hour and 30/day per user

Exceeding a limit returns 429 with RateLimit-Policy,
RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset and
Retry-After headers. The AI endpoints' in-handler limit answers a bare
429 without them.

Contact​

Servers​

https://api.staging.fundlyhub.org/api/v1Staging
https://api.fundlyhub.org/api/v1Production

Register a new user​

POST
/cognito/signup

Create a new account via AWS Cognito. The account is confirmed immediately and a verification link is mailed to the address; the email stays unverified until that link is followed (see GET /cognito/verify-email), and several write endpoints refuse an unverified account. Gated by the features.user_registration flag — when the flag is off the endpoint answers 403. Rate limited to 10 requests per minute per IP. When the risk engine flags the caller (repeated sign-ups from one IP), a reCAPTCHA token must be sent as captchaToken.

Request Body​

application/json
JSON
{
"email": "user@example.com",
"password": "SecureP@ssw0rd!",
"name": "John Doe",
"captchaToken": "string",
"ambassadorInviteToken": "string"
}

Responses​

Account created; verification email sent.

application/json
JSON
{
"message": "string",
"userSub": "string",
"userConfirmed": true
}

Playground​

Server
Body

Samples​


Confirm registration​

POST
/cognito/confirm

Confirm a Cognito account with a verification code. Sign-up already confirms the account itself, so this is needed only when POST /cognito/signup answered userConfirmed: false. It does not mark the email verified — that is the link sent by sign-up.

Request Body​

application/json
JSON
{
"email": "string",
"code": "123456"
}

Responses​

Account confirmed

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

Playground​

Server
Body

Samples​


Sign in​

POST
/cognito/signin

Authenticate with email and password. Tokens are not returned in the body: the session is set as httpOnly cookies (access_token, id_token, refresh_token) that the browser sends on every later request. Scripts and server-to-server integrations should use an API key instead (see Authentication). When the risk engine flags repeated failures, a reCAPTCHA token must be sent as captchaToken. If Cognito asks for a further challenge, the body carries challengeRequired: true, challengeName and session and no cookies are set.

Request Body​

application/json
JSON
{
"email": "user@example.com",
"password": "string",
"captchaToken": "string"
}

Responses​

Authentication successful; session cookies set.

application/json
JSON
{
"message": "Signin successful",
"user": {
"id": "string",
"email": "string",
"name": "string",
"avatar": "string",
"role": "string",
"email_verified": true,
"created_at": "string",
"profile_slug": "string",
"deletion_scheduled_for": "string"
},
"expiresIn": 0
}

Playground​

Server
Body

Samples​


Refresh tokens​

POST
/cognito/refresh

Exchange the refresh_token cookie for new access and ID token cookies. There is no request body — a refresh token sent in JSON is ignored.

Responses​

Tokens refreshed; new access_token and id_token cookies set.

application/json
JSON
{
"message": "string",
"expiresIn": 0
}

Playground​

Samples​


Sign out​

POST
/cognito/logout

Revoke the session's Cognito tokens (global sign-out) and clear the session cookies. Always answers 200, even without a session.

Responses​

Logged out

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

Playground​

Samples​


Get current user​

GET
/cognito/me

The signed-in user's profile. Cookie session only — this endpoint does not accept an Authorization header or an API key. When the short-lived session has expired but the refresh cookie is still valid, it renews the session transparently and sets new cookies. While FundlyHub support is viewing the account on the user's behalf it returns that user with is_impersonating: true and impersonated_by.

Responses​

Current user info

application/json
JSON
{
"user": {
"id": "string",
"email": "string",
"name": "string",
"avatar": "string",
"role": "string",
"email_verified": true,
"created_at": "string",
"profile_slug": "string",
"auth_provider": "string",
"needs_name_update": true,
"deletion_scheduled_for": "string",
"is_impersonating": true,
"impersonated_by": "string"
}
}

Playground​

Samples​


Request password reset​

POST
/cognito/forgot-password

Send a password reset code to the user's email. Answers 200 whether or not the address has an account, so it cannot be used to discover accounts.

Request Body​

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

Responses​

Reset code sent, if the account exists

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

Playground​

Server
Body

Samples​


Reset password​

POST
/cognito/reset-password

Set a new password using the reset code.

Request Body​

application/json
JSON
{
"email": "string",
"code": "string",
"newPassword": "string"
}

Responses​

Password reset

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

Playground​

Server
Body

Samples​


Initiate OAuth login​

GET
/cognito/oauth/{provider}

Redirect to the Cognito Hosted UI for a third-party provider. After the provider signs the user in, GET /cognito/oauth/callback sets the session cookies and redirects to redirect on the FundlyHub site.

Open this URL in the browser that will be signed in, by navigating to it rather than fetching it. The response sets a short-lived httpOnly cookie that the callback requires. A sign-in completed in a different browser, after about ten minutes, or after a newer sign-in was started in the same browser is refused, and the browser is sent to /auth?error=state_mismatch with no session set; starting again fixes it.

Parameters​

Path Parameters

provider*
Type
string
Required
Valid values
"google""apple"

Query Parameters

redirect

The path on the FundlyHub site to send the browser to after sign-in, such as /campaigns/help-food-bank?tab=updates. It must start with a single /; a full URL on the FundlyHub site is reduced to its path. Any other value, such as a URL on another host or a protocol-relative //host, is replaced by /. Defaults to /.

Type
string
Example"/campaigns/help-food-bank"
Max Length
2048

Responses​

Redirect to the OAuth provider. Sets the short-lived sign-in cookie that the callback checks.

Playground​

Server
Variables
Key
Value

Samples​


Change password​

POST
/cognito/change-password

Changes the password of an email/password account, given the current one.

Cookie session only. A request authenticated with an Authorization: Bearer header or an API key answers 401 Not authenticated. Google and Apple accounts have no password to change.

Rate limited at 10 requests/minute per IP (authentication bucket).

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
{
"currentPassword": "string",
"newPassword": "string"
}

Responses​

Password changed

application/json
JSON
{
"success": true,
"message": "string"
}

Playground​

Server
Authorization
Body

Samples​


Resend the email-verification link​

POST
/cognito/resend-verification

Sends a fresh verification link to the account registered under email (matched case-insensitively against the login address, not the private contact address — for that use POST /users/me/private-contact/resend).

Always answers 200 with the same message, whether or not the address has an account and even when sending fails, so it cannot be used to discover accounts.

No authentication. Rate limited at 5 requests/minute, keyed by user when a session is present and by IP otherwise.

Request Body​

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

Responses​

Accepted (sent if the address is known)

application/json
JSON
{
"message": "If this email exists, a verification link has been sent."
}

Playground​

Server
Body

Samples​


Verify an email address (link target)​

GET
/cognito/verify-email

The URL in verification emails. Consumes the token and always redirects to the frontend with the outcome in a query parameter; it never returns JSON.

?verification= is one of: success; invalid (no token); failed (unknown, used or expired token); contact_taken (the link proved a private contact address another account already holds); error (unexpected failure).

When the link proved the account's login address, the Cognito email_verified attribute is updated too, and any pending ambassador invitation for that address is settled.

No authentication. Rate limited at 300 requests/minute per IP.

Query Parameters

token*
Type
string
Required

Redirect to {FRONTEND_URL}/?verification=<outcome>

Server
Variables
Key
Value

OAuth callback (Google / Apple)​

GET
/cognito/oauth/callback

The Cognito Hosted UI's redirect_uri after a Google or Apple sign-in, started at GET /cognito/oauth/{provider}. Not called by API clients directly.

Exchanges code for tokens, provisions or links the profile, sets the access_token, id_token and refresh_token httpOnly cookies, and redirects to the URL carried in state — which is the redirect query parameter given when the flow was started, or the frontend root.

Every failure is also a redirect, to {FRONTEND_URL}/auth?error=…: unverified_account_exists (a provider identity linked to a native account whose address was never verified), missing_code, token_exchange_failed, invalid_token, oauth_error, or the provider's own error with a message.

Parameters​

Query Parameters

code

Authorization code from Cognito.

Type
string
state

Where to send the browser after a successful sign-in.

Type
string
error
Type
string
error_description
Type
string

Responses​

Redirect — to state on success (with session cookies set), or to /auth?error=… on the frontend.

Playground​

Server
Variables
Key
Value

Samples​


List fundraisers​

GET
/fundraisers

A paginated list of public campaigns, newest first. No authentication; the result is the same whoever asks. Only published campaigns (active or ended) with visibility: public are listed — drafts, campaigns awaiting review, paused, rejected, unlisted and private campaigns never appear here, whatever is asked for — and deleted campaigns are excluded. Each item is a campaign card (FundraiserCard); fetch the detail read for the full campaign. Card text is translated into the reader's language (lang, then the language cookie, then Accept-Language) where a translation exists.

Near a point. With near=<lat>,<lng> the list holds only the campaigns whose city is within radius_mi miles (default 20) of that point, nearest first and then most raised, and each item carries distance_mi. Every other filter still applies, and so do the public-only rules above. A campaign's point is its CITY's centroid, geocoded on the server from the free-text location; a campaign whose location has no city-level point yet is not in a near list. For the cities to offer a picker, read GET /fundraisers/cities.

Only the parameters below are accepted. Any other query parameter is ignored.

Parameters​

Query Parameters

status

active — live campaigns whose end date has not passed; closed — ended campaigns plus live ones past their end date; ended — the same as closed; all — both (the default). Any other value answers 400 with { "error": "Invalid status", "allowed": [...] }.

Type
string
Valid values
"active""closed""ended""all"
Default
"all"
category

Filter by category — its id, slug or name all match.

Type
string
q

Free-text search over title, summary, story, category and location — the same match GET /search?scope=campaigns uses. Matches are ranked first.

Type
string
is_project

true for projects only, false for fundraisers only; omit for both.

Type
boolean
sort

raised sorts by most raised first. Omit for newest first.

Type
string
Valid values
"raised"
lang

Language to translate card text into.

Type
string
Valid values
"en""ru""uk""es"
limit

Page size, 1–100. A larger value is treated as 100; a missing, zero, negative or non-numeric value as 20.

Type
integer
Minimum
1
Maximum
100
Default
20
offset

Number of campaigns to skip, 0 or more. A negative or non-numeric value is treated as 0.

Type
integer
Minimum
0
Default
0
near

<lat>,<lng> in decimal degrees, e.g. 38.5816,-121.4944: latitude −90..90, longitude −180..180. Lists only the campaigns within radius_mi of the point, nearest first, then most raised (this order replaces sort and the search rank), each with distance_mi. Anything that is not two numbers in range — including an empty value or the parameter sent twice — answers 400 { "error": "invalid_near" }.

Type
string
Example"38.5816,-121.4944"
Pattern
"^\\s*[+-]?(\\d+(\\.\\d*)?|\\.\\d+)\\s*,\\s*[+-]?(\\d+(\\.\\d*)?|\\.\\d+)\\s*$"
radius_mi

Radius in miles around near, 1–100, default 20. A larger value is treated as 100, a smaller one as 1, and a non-numeric one as 20. Ignored without near.

Type
number
Minimum
1
Maximum
100
Default
20

Responses​

Paginated list of campaign cards

application/json
JSON
{
"data": [
],
"pagination": {
"limit": 0,
"offset": 0,
"total": 0
}
}

Playground​

Server
Variables
Key
Value

Samples​


Create fundraiser​

POST
/fundraisers

Create a new fundraising campaign.
Send status: "draft" to save a draft, which skips the publish gate. Any other status, including an omitted one, runs the publish gate (profile readiness, an image, reasonability and AI review), and a flagged campaign lands pending for review. Note that an omitted status that passes the gate is stored as draft, not active. Send status: "active" to publish.
Requires a bearer session and is gated by the features.fundraiser_creation flag. Publishing requires a verified email address. A caller whose email is not yet verified may still create a draft (status: "draft" sent explicitly) and may hold at most 5 drafts. Past that the answer is 403 with code UNVERIFIED_DRAFT_LIMIT. Any other status from an unverified caller answers 403 with code EMAIL_NOT_VERIFIED. A failing gate answers 403, not 401.

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
"string"

Responses​

Fundraiser created

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

Playground​

Server
Authorization
Body

Samples​


List cities with active fundraisers​

GET
/fundraisers/cities

Every city that has at least one active public campaign, for a "near" city picker: one row per city, with how many active public campaigns it has and a representative point to pass to GET /fundraisers?near=<lat>,<lng>. No authentication.

Active means what GET /fundraisers?status=active lists: status active, end date not passed, visibility: public, not deleted. Cities come from a server-side, city-level geocode of each campaign's free-text location; campaigns whose location has no city (not yet geocoded, not a place, or a whole state or country) are not counted. lat/lng is the average of that city's campaigns' points, which are all the city's centroid, to 2 decimals. Sorted by count, most first, then by label. label is "City, REGION" in the US and "City, Country" elsewhere. Cached for up to 5 minutes.

Responses​

Cities with active public campaigns

application/json
JSON
{
"data": [
{
"label": "Sacramento, CA",
"city": "Sacramento",
"region": "CA",
"country": "US",
"lat": 38.58,
"lng": -121.49,
"count": 12
}
]
}

Playground​

Samples​


Get fundraiser​

GET
/fundraisers/{id}

Retrieve a single fundraiser by UUID — the stored row, without the joined owner and raised figures the slug read adds. Authentication is optional and widens what you can see: a campaign that is not active, paused or ended, is private, or has been deleted, is returned to its owner and answers 404 to everyone else. An unlisted campaign is readable with its link. The owner also gets trustStatus and the private fields they entered, such as beneficiary_contact; every other caller, signed in or not, gets the campaign without them.

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)
or

Parameters​

Path Parameters

id*
Type
string
Required
Format
"uuid"

Query Parameters

lang

Overlay the stored translation for this language, when one exists.

Type
string
Valid values
"en""ru""uk""es"

Responses​

Fundraiser details

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

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Delete fundraiser​

DELETE
/fundraisers/{id}

Soft-deletes a fundraiser (sets deleted_at). Only the owner may delete. A campaign that has collected funds cannot be deleted and answers 400. Once deleted, GET /fundraisers/{id} and GET /fundraisers/slug/{slug} answer 404 to everyone but its owner.

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

id*
Type
string
Required
Format
"uuid"

Responses​

Fundraiser soft-deleted

application/json
JSON
{
"success": true,
"campaignId": "string",
"slug": "string",
"deletedAt": "string"
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Update fundraiser​

PATCH
/fundraisers/{id}

Update fundraiser details. Only the owner can update. Setting status is how a draft is published (active) or sent for review (pending). Publishing runs the same gate as creation — profile readiness, at least one image, reasonability and AI review — and a flagged campaign lands pending. A campaign that has collected money cannot go back to draft.
The caller's email must be verified, with one exception: an unverified caller may edit a campaign that is currently draft, as long as the body sends no status or sends status: "draft". Moving a draft to any other status, or editing a campaign that is not a draft, answers 403 with code EMAIL_NOT_VERIFIED.

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

id*
Type
string
Required
Format
"uuid"

Request Body​

application/json
JSON
"string"

Responses​

Fundraiser updated

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

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Get fundraiser by slug​

GET
/fundraisers/slug/{slug}

Retrieve a fundraiser using its URL-friendly slug, with the owner, category name, raised figures and share count joined in. Authentication is optional and widens what you can see, exactly as on GET /fundraisers/{id}: unpublished, private and deleted campaigns, the private fields such as beneficiary_contact, and trustStatus are for the owner only.

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)
or

Parameters​

Path Parameters

slug*
Type
string
Required

Query Parameters

lang

Overlay the stored translation for this language, when one exists.

Type
string
Valid values
"en""ru""uk""es"

Responses​

Fundraiser details

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

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Check slug availability​

GET
/fundraisers/check-slug/{slug}

Check if a fundraiser slug is available. Every campaign counts, including drafts and soft-deleted ones.

Parameters​

Path Parameters

slug*
Type
string
Required

Query Parameters

exclude

A campaign id to ignore — pass the campaign being edited so its own slug reads as available.

Type
string
Format
"uuid"

Responses​

Availability status

application/json
JSON
{
"available": true,
"suggestion": "string"
}

Playground​

Server
Variables
Key
Value

Samples​


Get fundraiser statistics​

GET
/fundraisers/{id}/stats

Aggregate totals for one campaign. Readable exactly when GET /fundraisers/{id} is: a campaign that is not active, paused or ended, is private, or has been deleted answers 404 to everyone but its owner. Authentication is optional.

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)
or

Parameters​

Path Parameters

id*
Type
string
Required
Format
"uuid"

Responses​

Campaign statistics

application/json
JSON
{
"data": {
"fundraiser_id": "string",
"title": "string",
"goal_amount_cents": 0,
"total_raised_cents": 0,
"total_tips_cents": 0,
"donation_count": 0,
"donor_count": 0,
"percentage_funded": 0
}
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Deprecated

Get campaign stats (broken)​

GET
/campaigns/{id}/stats

Not available: currently answers 500 for every campaign. Use GET /fundraisers/{id}/stats instead.
Intended as a public stat-tile read: raised and goal (cents), donor, update and view counts, dates and days left.

Parameters​

Path Parameters

id*
Type
string
Required
Format
"uuid"

Responses​

Campaign stats (bare object; not currently reachable)

application/json
JSON
{
"id": "string",
"title": "string",
"raised": "string",
"goal": "string",
"donor_count": "string",
"update_count": "string",
"view_count": "string",
"created_at": "string",
"end_date": "string",
"days_left": 0
}

Playground​

Server
Variables
Key
Value

Samples​


Run a pre-publish trust assessment​

POST
/fundraisers/{id}/assess

Runs the full trust assessment the platform applies at publish time, without publishing: profile and campaign blockers, suggestions, a trust score, an AI analysis of the story, and the moderation decision it would lead to. No request body. Campaign owner only.

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

id*
Type
string
Required
Format
"uuid"

Responses​

Assessment (bare object)

application/json
JSON
"string"

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get a campaign's lifecycle timeline​

GET
/fundraisers/{id}/activity

Lifecycle events (created, submitted for review, approved, rejected, updated, update posted, goal reached, deleted), newest first, with who acted. Campaign owner only; works for soft-deleted campaigns too.
Actions taken by FundlyHub staff appear with role: "admin" and null id, name and email.

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

id*
Type
string
Required
Format
"uuid"

Responses​

Timeline (unwrapped)

application/json
JSON
{
"activity": [
]
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Report a campaign​

POST
/fundraisers/{id}/report

Flags an active campaign for moderator review. One report per user per campaign: reporting again replaces the earlier reason and details. Requires a verified email address.

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

id*
Type
string
Required
Format
"uuid"

Request Body​

application/json
JSON
{
"reason": "string",
"details": "string"
}

Responses​

Report recorded

application/json
JSON
{
"success": true,
"message": "string"
}

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Contact the organizer​

POST
/fundraisers/{id}/contact

Sends a message to the campaign's organizer by email. The organizer receives it with the sender's email as the reply address and answers by replying, so the organizer's own address is never revealed unless they reply. Authentication is optional: anyone who can read the campaign may write, with the same visibility rule as GET /fundraisers/{id} (a campaign hidden from the caller answers 404). Limited to five messages an hour per client address and, when signed in, per account. A message with more than three links is refused, and the name may contain none.

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)
or

Parameters​

Path Parameters

id*
Type
string
Required
Format
"uuid"

Request Body​

application/json
JSON
{
"email": "string",
"message": "string",
"name": "string"
}

Responses​

The message was accepted for delivery.

application/json
JSON
{
"sent": true
}

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Get the featured donor for a campaign​

GET
/fundraisers/{id}/donor-highlight

Feeds the campaign page's "{name} and N others have donated" row: one featured donor and up to three faces, chosen from the latest 100 paid, non-anonymous gifts. Authentication is optional and only changes WHO is featured: a signed-in viewer sees people they follow, or who follow them, first. Only public campaigns that are active, paused or ended return donors; anything else returns empty.

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)
or

Parameters​

Path Parameters

id*

The campaign's UUID; anything else answers 400.

Type
string
Required
Format
"uuid"

Responses​

Featured donor (bare object)

application/json
JSON
{
"featured": {
"name": "string",
"avatar": "string"
},
"avatars": [
]
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get related campaigns​

GET
/fundraisers/{id}/related

Four lists of other people's live, public campaigns for the discovery rail at the bottom of a campaign page: same category (similar), same US state (nearby), 70–99% funded (almost) and newest (recent). An empty list means that tab is not shown. Public.
Titles and summaries are in the reader's language (?lang=, then the locale cookie, then Accept-Language) when a translation exists; when a language is resolved, each card also carries translation_source and, where the text was replaced, original_title / original_summary.

Parameters​

Path Parameters

id*

The campaign's UUID; anything else answers 400.

Type
string
Required
Format
"uuid"

Query Parameters

limit

Cards per list, clamped to 1–12.

Type
integer
Minimum
1
Maximum
12
Default
12
lang
Type
string
Valid values
"en""ru""uk""es"

Responses​

The four lists (bare object)

application/json
JSON
{
"similar": [
],
"nearby": [
],
"almost": [
],
"recent": [
]
}

Playground​

Server
Variables
Key
Value

Samples​


Get a campaign's outcome report​

GET
/fundraisers/{id}/outcome-report

The creator's published account of what the money did. Returns { "report": null } (not 404) when there is no report, when it is still a draft, and when FundlyHub has hidden it; the three cases are deliberately indistinguishable. Authentication is accepted and does not change the report; owners read their draft from /mine. The campaign itself is readable exactly when GET /fundraisers/{id} is: a campaign that is not active, paused or ended, is private, or has been deleted answers 404 to everyone but its owner.

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)
or

Parameters​

Path Parameters

id*
Type
string
Required
Format
"uuid"

Responses​

The published report, or null

application/json
JSON
{
"report": {
"id": "string",
"fundraiserId": "string",
"authorId": "string",
"title": "string",
"body": "string",
"attachments": [
],
"invoiceCount": 0,
"publishedAt": "string",
"hiddenAt": "string",
"createdAt": "string",
"updatedAt": "string"
}
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Save or publish the outcome report​

PUT
/fundraisers/{id}/outcome-report

Creates or replaces the campaign's single outcome report, and with publish: true publishes it in the same call. Publishing is one-way: a published report stays published on later saves, and publishedAt keeps its first value. Only the campaign's owner may write it. The body is sanitised as rich text; the title is plain text. Shares the media-upload rate limit (30 per 15 minutes). Audit-logged.

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

id*
Type
string
Required
Format
"uuid"

Request Body​

application/json
JSON
{
"title": "string",
"body": "string",
"attachments": [
],
"invoice_count": 0,
"publish": false
}

Responses​

The saved report

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

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Get my campaign's outcome report, draft included​

GET
/fundraisers/{id}/outcome-report/mine

The owner's view of the outcome report: a draft is returned, and a hidden report is returned with hiddenAt set. { "report": null } when none has been written. Campaign owner only.

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

id*
Type
string
Required
Format
"uuid"

Responses​

The report, or null

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

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get aggregate campaign stats​

GET
/analytics/campaigns/aggregate

Counters for the /causes stat tiles, over public, non-deleted campaigns in active or ended status, filtered the same way as the listing. "Closed" means ended, or active with a past end_date. Every figure, total_donors and topCategories included, covers the same filtered set.

Counts and sums are returned as numeric strings.

No authentication.

Parameters​

Query Parameters

is_project
Type
string
Valid values
"true""false""1""0"
category

Category slug, id or name.

Type
string

Responses​

The aggregates (bare object)

application/json
JSON
{
"total_campaigns": "128",
"active_campaigns": "string",
"closed_campaigns": "string",
"total_raised_cents": "string",
"total_goal": "string",
"avg_completion_percent": "string",
"total_donors": "string",
"topCategories": [
{
"id": 0,
"name": "string",
"campaign_count": "string",
"total_raised_cents": "string"
}
]
}

Playground​

Server
Variables
Key
Value

Samples​


Create donation​

POST
/donations

Record a pending donation row against a fundraiser. The Stripe fee is computed server-side and the donor is the session's account.
Requires a bearer session and a verified email address, is gated by the features.donations flag, and is protected by reCAPTCHA v3 (action donation) — send the token as recaptcha_token in the body or in the x-recaptcha-token header. Because this route already requires a verified email, a Cognito session may omit the token; an API key or impersonation session without one answers 400. A token that is sent is always verified: below the score threshold answers 403.
This is the bookkeeping half of a gift. Money is moved by POST /payments/create-intent + POST /payments/confirm.

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​

Header Parameters

x-recaptcha-token

reCAPTCHA v3 token, action donation. Alternative to recaptcha_token in the body.

Type
string
x-app-attest-key-id

iOS only. The App Attest key id (standard base64, as DCAppAttestService.generateKey returns it) of a key registered with POST /app-attest/attest. Send with x-app-attest-assertion.

Type
string
x-app-attest-assertion

iOS only. base64 of the assertion from generateAssertion(keyId, clientDataHash: SHA256(raw request body)). The body must carry a fresh app_attest_challenge. A valid assertion replaces the reCAPTCHA token; the headers alone never do. An invalid one answers 403 with code APP_ATTEST_INVALID, APP_ATTEST_KEY_UNKNOWN (attest a new key) or APP_ATTEST_CHALLENGE_INVALID (fetch a new challenge), unless the request passes reCAPTCHA some other way.

Type
string

Request Body​

application/json
JSON
"string"

Responses​

Donation created

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

Playground​

Server
Authorization
Headers
Body

Samples​


List donations for fundraiser​

GET
/fundraisers/{fundraiserId}/donations

Public donor wall for one fundraiser: paid donations only, newest first, with a true total count. Donor email and payment identifiers are never returned, and anonymous gifts have their donor name and avatar stripped. Amounts are net (donation minus the Stripe fee) so the list agrees with the creator's balance.
Only a campaign anyone may open by link (live, ended or paused; not private; not deleted) has a public donor wall. For any other campaign the answer is an empty data array with total: 0, the same as for an unknown id, unless the caller is signed in as the campaign's owner or an admin.

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)
or

Parameters​

Path Parameters

fundraiserId*
Type
string
Required
Format
"uuid"

Query Parameters

limit

Page size, clamped to 1–200. A missing, zero, negative or non-numeric value means 20.

Type
integer
Minimum
1
Maximum
200
Default
20
offset

A missing, negative or non-numeric value means 0.

Type
integer
Minimum
0
Default
0

Responses​

Paginated list of donations

application/json
JSON
{
"data": [
],
"pagination": {
"limit": 0,
"offset": 0,
"total": 0
}
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get donation by receipt ID​

GET
/donations/receipt/{receiptId}

The donor's receipt. Public — the receipt id is the Stripe PaymentIntent (pi_…) or invoice (in_…) id, a capability token only the donor holds, so treat it as a secret: the response includes the donor's email and card details. Answers for a donation in any payment state, including pending.

Parameters​

Path Parameters

receiptId*

The receipt id, or the donation's PaymentIntent id.

Type
string
Required

Responses​

Receipt details

application/json
JSON
{
"data": {
"id": "string",
"fundraiser_id": "string",
"amount_cents": 0,
"net_amount_cents": 0,
"fee_amount_cents": 0,
"tip_amount_cents": 0,
"currency": "string",
"donor_name": "string",
"donor_email": "string",
"is_anonymous": true,
"payment_status": "string",
"payment_method_type": "string",
"card_brand": "string",
"card_last4": "string",
"receipt_id": "string",
"created_at": "string",
"campaign_title": "string",
"campaign_slug": "string",
"beneficiary_name": "string",
"fundraiser": {
"title": "string",
"slug": "string"
}
}
}

Playground​

Server
Variables
Key
Value

Samples​


Send donation receipt​

POST
/donations/receipt/email

Email the receipt for one donation.

The donation is named by receipt_id and nothing else — every figure
in the email is read from that row, so the caller cannot dictate the
contents. receipt_id is the Stripe PaymentIntent id, which is not
guessable.

recipient_email is deliberately free-form, because "send it to my
accountant" is the feature. What bounds it instead is a cap of 5
sends per donation
, after which this returns 429 for that donation
permanently.

Authentication is optional; the endpoint is rate limited.

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)
or

Request Body​

application/json
JSON
{
"receipt_id": "pi_3abc123def456",
"recipient_email": "string"
}

Responses​

Receipt sent.

application/json
JSON
{
"success": true,
"message": "string"
}

Playground​

Server
Authorization
Body

Samples​


Get a campaign's top donors​

GET
/fundraisers/{fundraiserId}/top-donors

The campaign's biggest donors, one row per person across all their paid gifts. Anonymous donors keep their total but not their name; they are identified by an opaque anonymous_key. When any donor gave in more than one currency, meta.mixed_currency is true and the totals should not be shown. Public.
Only a campaign anyone may open by link (live, ended or paused; not private; not deleted) has a public ranking. For any other campaign the answer is an empty data array, the same as for an unknown id, unless the caller is signed in as the campaign's owner or an admin.

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)
or

Parameters​

Path Parameters

fundraiserId*
Type
string
Required
Format
"uuid"

Query Parameters

limit

Rows to return, clamped to 1–25.

Type
integer
Minimum
1
Maximum
25
Default
5

Responses​

Top donors

application/json
JSON
{
"data": [
{
"id": "string",
"anonymous_key": "string",
"is_anonymous": true,
"donor_name": "string",
"donor_avatar": "string",
"total_cents": 0,
"donation_count": 0,
"last_donation_at": "string",
"currency": "string"
}
],
"meta": {
"mixed_currency": true
}
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


List recent gifts (public feed)​

GET
/donations/recent

Paid gifts for the homepage hero, newest first, in one of two modes:

  • Unscoped (no slugs): the newest limit gifts platform-wide.
  • Per campaign (slugs): the newest perCampaign gifts for
    each named campaign, ranked within that campaign.

Only gifts to public campaigns in active or ended status appear, and gifts a moderator pulled from the feed never do. An anonymous gift has its name, avatar, city and ordinal nulled. amount_cents is the net amount (after the Stripe fee) — the same figure the campaign page shows. Campaign titles are localised as for GET /users/{id}/campaigns.

Publicly cached for 15 seconds. No authentication. Rate limited at 300 requests/minute per IP.

Parameters​

Query Parameters

limit

Unscoped mode only.

Type
integer
Minimum
1
Maximum
24
Default
12
slugs

Comma-separated campaign slugs (or a repeated parameter). At most 6 are used; extras are ignored.

Type
string
perCampaign

Per-campaign mode only.

Type
integer
Minimum
1
Maximum
40
Default
3
lang
Type
string
Valid values
"en""ru""uk""es"

Responses​

The gifts

application/json
JSON
{
"data": [
]
}

Playground​

Server
Variables
Key
Value

Samples​


Get the donor's note​

GET
/donations/receipt/{receiptId}/note

The note already on a paid donation, so the composer can show it and its remaining writes (3 − note_edit_count). data is null when there is no note.

No authentication: the receipt id is the capability. Rate limited at 300 requests/minute per IP.

Parameters​

Path Parameters

receiptId*

The receipt id, or the donation's Stripe PaymentIntent id.

Type
string
Required

Responses​

The note, or null

application/json
JSON
{
"data": {
"id": "string",
"content": "string",
"gif": {
"id": "xT4uQulxzV39haRFjG",
"title": "string",
"width": 480,
"height": 270,
"mp4_url": "https://media2.giphy.com/media/xT4uQulxzV39haRFjG/giphy.mp4",
"webp_url": "https://media2.giphy.com/media/xT4uQulxzV39haRFjG/giphy.webp",
"gif_url": "https://media2.giphy.com/media/xT4uQulxzV39haRFjG/giphy.gif",
"still_url": "https://media2.giphy.com/media/xT4uQulxzV39haRFjG/giphy_s.gif",
"preview_mp4_url": "https://media2.giphy.com/media/xT4uQulxzV39haRFjG/200w.mp4",
"preview_webp_url": "https://media2.giphy.com/media/xT4uQulxzV39haRFjG/200w.webp",
"preview_width": 200,
"preview_height": 113
},
"created_at": "string",
"updated_at": "string",
"note_edit_count": 0,
"retracted": true,
"hidden": true,
"campaign_slug": "string"
}
}

Playground​

Server
Variables
Key
Value

Samples​


Post, edit or retract the donor's note​

POST
/donations/receipt/{receiptId}/note

Writes the note a donor leaves on their receipt, which appears in the campaign's comments. The receipt id is the authorisation — guest donors have no session — and the donation must be paid and to a campaign. A missing, unpaid or person-targeted donation gets the same 404.

Each donation allows 3 writes in total (post, edits and retract combined); after that every write is 429. Read the current note with the GET first so a reload does not spend one. The note is attributed to an account only when the caller is signed in as the donor.

Authentication is optional. Behind features.comments. Rate limited at 5 requests/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)
or

Parameters​

Path Parameters

receiptId*

The receipt id, or the donation's Stripe PaymentIntent id.

Type
string
Required

Request Body​

application/json
JSON
{
"content": "string",
"retract": true
}

Responses​

Note retracted

application/json
JSON
{
"data": {
"id": "string",
"retracted": true
}
}

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Categories​


List categories​

GET
/categories

Get all active fundraiser categories, ordered by display_order.

Responses​

List of categories

application/json
JSON
{
"data": [
]
}

Playground​

Samples​


Get all category statistics​

GET
/categories/stats

Organization count, active-campaign count and funds raised for every active category, in display_order. Only public campaigns and approved or verified organizations are counted.

Responses​

Statistics for all categories

application/json
JSON
{
"data": [
{
"category_name": "string",
"category_slug": "string",
"organization_count": 0,
"campaign_count": 0,
"total_raised_cents": 0
}
]
}

Playground​

Samples​


Get category​

GET
/categories/{id}

A single active category, addressed by its numeric id or its slug.

Parameters​

Path Parameters

id*

Category id (an integer) or slug.

Type
string
Required

Responses​

Category details

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

Playground​

Server
Variables
Key
Value

Samples​


Get category statistics​

GET
/categories/{id}/stats

Organization count, active-campaign count and funds raised for one category. Only public campaigns with status active and approved or verified organizations are counted.

Parameters​

Path Parameters

id*

Category id (an integer) or slug.

Type
string
Required

Responses​

Category statistics with fundraiser counts

application/json
JSON
{
"data": {
"category_name": "string",
"organization_count": 0,
"fundraiser_count": 0,
"total_raised_cents": 0
}
}

Playground​

Server
Variables
Key
Value

Samples​


List organizations​

GET
/organizations

Public list of approved/verified, non-deleted organizations. Returns their public fields plus a true total count. Rate-limited.

Parameters​

Query Parameters

verification_status

Only approved or verified take effect; other values fall back to the default public filter.

Type
string
Valid values
"approved""verified"
country
Type
string
limit

Clamped to 1..100. Defaults to 20.

Type
integer
Minimum
1
Maximum
100
Default
20
offset
Type
integer
Minimum
0
Default
0

Responses​

Paginated list of organizations

application/json
JSON
{
"data": [
{
"id": "string",
"legal_name": "string",
"dba_name": "string",
"slug": "string",
"country": "string",
"address": "string",
"website": "string",
"logo": "string",
"banner_image": "string",
"description": "string",
"mission": "string",
"categories": [
"string"
],
"social_links": {
"additionalProperties": "string"
},
"founded_year": 0,
"verification_status": "string",
"verification_completed_at": "string",
"kind": "string",
"parent_organization_id": "string",
"created_at": "string",
"updated_at": "string"
}
],
"pagination": {
"limit": 0,
"offset": 0,
"total": 0
}
}

Playground​

Server
Variables
Key
Value

Samples​


Create organization​

POST
/organizations

Multi-tier onboarding payload.
Requires a bearer session and a verified email address — an unverified session answers 403. Self-service creation is capped at 5 organizations per hour per (IP, user).

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
{
"legal_name": "string",
"ein": "12-3456789",
"country": "string",
"website": "string",
"description": "string",
"categories": [
"string"
],
"kind": "company",
"parent_organization_id": "string",
"dbas": [
{
"dba_name": "string"
}
],
"locations": [
{
"label": "string",
"address": {
"additionalProperties": "string"
}
}
]
}

Responses​

Organization created, pending verification. The caller becomes its org_owner.

application/json
JSON
{
"data": {
"id": "string",
"slug": "string",
"legal_name": "string",
"kind": "string",
"parent_organization_id": "string",
"verification_status": "string",
"dbas": [
{
"id": "string",
"dba_name": "string",
"is_default": true
}
],
"locations": [
{
"id": "string",
"label": "string",
"address": {
"additionalProperties": "string"
},
"is_primary": true
}
],
"created_at": "string"
}
}

Playground​

Server
Authorization
Body

Samples​


Get the caller's organizations​

GET
/organizations/me

Organizations the authenticated caller holds an active org-scoped role on. Flat array, no pagination.

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​

Caller's organizations

application/json
JSON
{
"data": [
{
"id": "string",
"legal_name": "string",
"dba_name": "string",
"slug": "string",
"country": "string",
"website": "string",
"logo": "string",
"description": "string",
"verification_status": "string",
"kind": "string",
"parent_organization_id": "string",
"created_at": "string",
"updated_at": "string",
"role_name": "string",
"role_display_name": "string",
"role_hierarchy_level": 0,
"org_role_title_id": "string",
"org_role_title_label": "string",
"org_role_title_category": "string",
"start_date": "string",
"end_date": "string",
"is_current": true,
"affiliation_description": "string"
}
]
}

Playground​

Server
Authorization

Samples​


Get organization by ID or slug​

GET
/organizations/{id}

Public read of a single org by UUID or slug. Anonymous callers only see approved/verified non-deleted orgs; an active member of the organization can also read it in its other states and additionally receives suspension/rejection metadata (suspension_reason, rejected_reason, suspended_until) and the unredacted contact_email. Authentication is therefore optional but not inert.

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)
or

Parameters​

Path Parameters

id*

Organization UUID or slug.

Type
string
Required

Responses​

Organization detail

application/json
JSON
{
"data": {
"id": "string",
"legal_name": "string",
"dba_name": "string",
"slug": "string",
"country": "string",
"website": "string",
"logo": "string",
"banner_image": "string",
"description": "string",
"mission": "string",
"verification_status": "string",
"kind": "string",
"parent_organization_id": "string",
"address": "string",
"categories": [
"string"
],
"social_links": {
"additionalProperties": "string"
},
"founded_year": 0,
"verification_completed_at": "string",
"contact_email": "string",
"contact_email_public": true,
"suspension_reason": "string",
"rejected_reason": "string",
"suspended_until": "string",
"created_at": "string",
"updated_at": "string",
"primary_location": {
"id": "string",
"label": "string",
"address": {
"additionalProperties": "string"
},
"is_publicly_visible": true
},
"dbas": [
{
"id": "string",
"dba_name": "string",
"is_default": true
}
],
"children": [
{
"id": "string",
"slug": "string",
"legal_name": "string",
"logo": "string",
"verification_status": "string"
}
]
}
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get organization stats​

GET
/organizations/{id}/stats

Campaign counts, funds raised, unique donors and followers for an org (UUID or slug). A bare object — not wrapped in data.

Parameters​

Path Parameters

id*
Type
string
Required

Responses​

Organization stats

application/json
JSON
{
"campaignCount": 0,
"totalCampaignCount": 0,
"totalFundsRaisedCents": 45600000,
"uniqueDonorCount": 0,
"followerCount": 0
}

Playground​

Server
Variables
Key
Value

Samples​


Get organization public team​

GET
/organizations/{id}/members

Public "Our team" list for an org (UUID or slug). Filtered to active, publicly-visible, non-expired memberships whose user profile is not private.

Parameters​

Path Parameters

id*
Type
string
Required

Responses​

Organization team members

application/json
JSON
{
"data": [
{
"user_id": "string",
"name": "string",
"profile_slug": "string",
"avatar": "string",
"kyc_verified_at": "string",
"org_role_title_id": "string",
"role_title_label": "string",
"role_title_category": "string",
"role_title_sort_order": 0,
"start_date": "string",
"end_date": "string",
"is_current": true,
"affiliation_description": "string",
"rbac_role_name": "string",
"rbac_hierarchy_level": 0
}
]
}

Playground​

Server
Variables
Key
Value

Samples​


Get organization updates feed​

GET
/organizations/{id}/updates

Public, latest-first updates feed for an org (UUID or slug). Offset pagination, limit clamped 1..50.

Parameters​

Path Parameters

id*
Type
string
Required

Query Parameters

limit
Type
integer
Minimum
1
Maximum
50
Default
20
offset
Type
integer
Minimum
0
Default
0

Responses​

Organization updates

application/json
JSON
{
"data": [
{
"id": "string",
"org_id": "string",
"author_user_id": "string",
"title": "string",
"body": "string",
"cover_image": "string",
"published_at": "string",
"created_at": "string",
"updated_at": "string",
"author_name": "string",
"author_profile_slug": "string",
"author_avatar": "string"
}
],
"pagination": {
"limit": 0,
"offset": 0,
"total": 0
}
}

Playground​

Server
Variables
Key
Value

Samples​


List public organization documents​

GET
/organizations/{id}/documents/public

Approved trust documents an organization admin has marked public, for an approved or verified org (UUID or slug). Metadata only — there is no public download.

Parameters​

Path Parameters

id*
Type
string
Required

Responses​

Public documents

application/json
JSON
{
"data": [
{
"id": "string",
"doc_type": "string",
"original_filename": "string",
"content_type": "string",
"size_bytes": 0,
"reviewed_at": "string",
"created_at": "string"
}
]
}

Playground​

Server
Variables
Key
Value

Samples​


List organization role titles​

GET
/org-role-titles

Public reference list of non-deprecated position titles (the LinkedIn-style "position" picker on the org-admin Members page), ordered by sort_order then label. These titles are display-only and carry no permissions — they are distinct from the RBAC roles org_owner / org_admin / org_viewer. Pass an id from this list as org_role_title_id when adding a member.

Responses​

Role titles

application/json
JSON
{
"data": [
]
}

Playground​

Samples​


List campaign locations by US state​

GET
/locations

US states that currently have active campaigns, with a campaign count per state, sorted by state name. The state is parsed out of each campaign's free-text location (a two-letter code or full state name); campaigns whose location cannot be matched to a state are left out. Cached for 5 minutes. Drives the location filter on campaign browse.

Responses​

States with active campaigns

application/json
JSON
{
"data": [
{
"code": "CA",
"name": "California",
"count": 0
}
]
}

Playground​

Samples​


Report an organization​

POST
/organizations/{id}/report

Flags an organization for review by FundlyHub's trust team. A signed-in caller with a verified email address can report; no relationship to the organization is needed. Each user holds at most one report per organization — reporting again overwrites the earlier category and details and puts the report back to pending.

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

id*

Organization UUID (a slug is not accepted and answers 404).

Type
string
Required
Format
"uuid"

Request Body​

application/json
JSON
{
"category": "string",
"details": "string"
}

Responses​

Report recorded

application/json
JSON
{
"success": true
}

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Get user profile​

GET
/users/{id}

Public profile by UUID or profile_slug. Authentication is optional: the caller's own profile may include their email, and a profile marked private is redacted for every other viewer.
WHAT SURVIVES THE REDACTION (#1696): id, name, avatar, profile_slug, created_at and the four counters — campaign_count, total_funds_raised, follower_count and following_count — with their REAL values. The leaderboard has always published a private person's rank and impact, so a profile reporting zeroes beside a board reporting real figures would be two surfaces disagreeing about one person rather than privacy.
Dropped: bio, location, website, social_links, email, phone, private_contact_email, display_name, account_status, kyc_verified_at and account_kind. The last three are more than a name — a Team chip and a verification tick say something about the person, which is exactly what a private profile withholds.

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)
or

Parameters​

Path Parameters

id*

User UUID or profile_slug.

Type
string
Required

Responses​

User profile — a bare object, not wrapped in data. The fields marked own profile only are present only when the caller is the profile's owner.

application/json
JSON
{
"id": "string",
"name": "string",
"display_name": "string",
"email": "string",
"avatar": "string",
"bio": "string",
"location": "string",
"website": "string",
"social_links": {
"additionalProperties": "string"
},
"profile_visibility": "string",
"profile_slug": "string",
"account_status": "string",
"role": "string",
"campaign_count": 0,
"total_funds_raised": 0,
"follower_count": 0,
"following_count": 0,
"phone": "string",
"private_contact_email": "string",
"private_contact_verified": true,
"kyc_verified_at": "string",
"account_kind": "string",
"created_at": "string"
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Update user profile​

PATCH
/users/{id}

Update your own profile. The fields below are the whole writable set;
anything else in the body is ignored rather than rejected.

location has been accepted since #1654 and was missing from this
schema; profile_visibility is new in #1696.

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

id*
Type
string
Required

Request Body​

application/json
JSON
{
"name": "string",
"profile_slug": "string",
"social_links": {
"additionalProperties": "string"
},
"location": "Sacramento, CA",
"profile_visibility": "private"
}

Responses​

Profile updated

application/json
JSON
{
"success": true,
"message": "string"
}

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Get a user's organization memberships​

GET
/users/{id}/organizations

Public org memberships for a user (UUID or profile_slug). Memberships marked not publicly visible, memberships of deleted organizations, and every membership of a private profile — even to its owner — are left out. 404 only when the user does not exist.

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)
or

Parameters​

Path Parameters

id*
Type
string
Required

Responses​

User organizations

application/json
JSON
{
"data": [
{
"id": "string",
"legal_name": "string",
"dba_name": "string",
"slug": "string",
"logo": "string",
"verification_status": "string",
"kind": "string",
"role_name": "string",
"role_display_name": "string",
"org_role_title_label": "string",
"start_date": "string",
"end_date": "string",
"is_current": true,
"affiliation_description": "string"
}
]
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get a user's public activity feed​

GET
/users/{id}/activity

The public activity feed on a profile (#1693): six kinds of public act, ordered newest first. Accepts a UUID or a profile_slug; auth-optional.

campaign_launched (the campaign passed approval), achievement_earned (a badge, read through the same public projection the profile badge strip uses), commented, donated, update_posted and endorsed (declared, or their referral link for that campaign recorded a visit — the definition the Endorsed-by dialog and the profile chip already use).

Each row inherits the visibility of the thing it reports: a refunded or charged-back gift, a hidden or retracted comment, a withdrawn update, a soft-deleted campaign and a revoked award are all simply absent. Anonymous gifts never appear, for anyone, including the profile's owner. A campaign that is unlisted, private, paused, draft or deleted is never named. A profile with show_donations_on_profile off keeps every row type except donated.

All money is INTEGER CENTS, never dollars. amount_cents on a donated row is what the giver paid — the donation plus the platform tip — which is the same figure the profile's Impact stat sums, so the two cannot disagree.

Paging is a KEYSET cursor, not an offset: pass the nextCursor from the previous page back as cursor. A cursor this endpoint did not issue is a 400. nextCursor is null on the last page.

Parameters​

Path Parameters

id*

A user UUID or a profile_slug.

Type
string
Required

Query Parameters

group

Filter chip. giving is donated; fundraising is campaign_launched and update_posted; community is commented, achievement_earned and endorsed. An unrecognised value falls back to all. The summary block is NOT filtered — it is the strip above the chips and always counts every type.

Type
string
Valid values
"all""giving""fundraising""community"
Default
"all"
limit
Type
integer
Minimum
1
Maximum
50
Default
20
cursor

The opaque nextCursor from the previous page. Omit for page 1.

Type
string

Responses​

A page of the feed. A private profile answers 200 with an empty items array to everybody but its owner, rather than 404 — the page renders and the section is simply empty.

application/json
JSON
{
"items": [
{
"id": "donated:6f1c2a2e-2b0a-4c6f-9a7e-2f0b9c1d4e55",
"type": "string",
"at": "string",
"campaign": {
"id": "string",
"slug": "string",
"title": "string",
"cover_image": "string"
},
"amount_cents": 0,
"currency": "string",
"excerpt": "string",
"gif": {
"id": "xT4uQulxzV39haRFjG",
"title": "string",
"width": 480,
"height": 270,
"mp4_url": "https://media2.giphy.com/media/xT4uQulxzV39haRFjG/giphy.mp4",
"webp_url": "https://media2.giphy.com/media/xT4uQulxzV39haRFjG/giphy.webp",
"gif_url": "https://media2.giphy.com/media/xT4uQulxzV39haRFjG/giphy.gif",
"still_url": "https://media2.giphy.com/media/xT4uQulxzV39haRFjG/giphy_s.gif",
"preview_mp4_url": "https://media2.giphy.com/media/xT4uQulxzV39haRFjG/200w.mp4",
"preview_webp_url": "https://media2.giphy.com/media/xT4uQulxzV39haRFjG/200w.webp",
"preview_width": 200,
"preview_height": 113
},
"achievement": {
"id": "string",
"title": "string",
"tagline": "string",
"tier": "string",
"badge_art_url": "string",
"background_color": "string"
}
}
],
"nextCursor": "string",
"joinedAt": "string",
"summary": {
"windowDays": 0,
"total": 0,
"byType": {
"additionalProperties": 0
}
}
}

Playground​

Server
Variables
Key
Value

Samples​


Get a user's public donation activity​

GET
/users/{id}/donation-activity

"Causes I support" on a public profile — the aggregate plus one entry per supported campaign. Accepts a UUID or a profile_slug; 404 only when the user does not exist.

Anonymous gifts are excluded, always. A profile that is private, or that has show_donations_on_profile off, answers zeroes. Only settled (paid) gifts count, and only to a campaign a reader could actually open — a deleted, draft, private, paused or unlisted campaign is neither listed nor counted (#1694).

Each entry in recent_supported_causes is a full campaign card, the same read model /fundraisers serves the /causes grid from, so the section renders the card the rest of the product uses. total_cents figures are INTEGER CENTS.

total_donated_cents is the PUBLIC figure and excludes anonymous gifts. It is the GIVER-FACING value of those gifts — the donation plus the platform tip, which is what the card was charged — so it agrees with the profile activity feed's per-gift figures and with the leaderboard's given figure. /donor/me/summary counts every gift the owner made and is a different number by design; do not compare them.

currency is the ISO 4217 code total_donated_cents is denominated in, taken from the donor's most recent gift that named one. Read it: minor units are not always hundredths, so formatting the total without it is a 100x error for a zero-decimal currency, not just the wrong symbol.

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)
or

Parameters​

Path Parameters

id*
Type
string
Required

Query Parameters

limit

Causes per page. The profile rail asks for 6; the dedicated page asks for more.

Type
integer
Minimum
1
Maximum
48
Default
6
offset
Type
integer
Minimum
0
Default
0

Responses​

User donation activity

application/json
JSON
{
"data": {
"total_donated_cents": 0,
"currency": "USD",
"causes_supported_count": 0,
"recent_supported_causes": [
{
}
],
"pagination": {
"limit": 0,
"offset": 0,
"total": 0
}
}
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get a user's Impact and leaderboard rank​

GET
/users/{id}/impact

The figures behind the Impact stat on a public profile, read from the same all-time field /leaderboard is served from, so the two surfaces always agree. Accepts a UUID or a profile_slug. All money is integer cents. A user who has not moved money answers zeroes and a null rank rather than 404 — their referral impressions are still reported. A private profile answers its headline impact figure only, with the rest of the breakdown zeroed and rank null, to everybody but its owner. If the leaderboard field cannot be read the endpoint answers 200 with zeroes rather than failing the profile.

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)
or

Parameters​

Path Parameters

id*
Type
string
Required

Responses​

The user's Impact breakdown

application/json
JSON
{
"impact": {
"rank": 0,
"impact": 0,
"raised": 0,
"given": 0,
"driven": 0,
"impressions": 0,
"gifts": 0
}
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get a user's permissions​

GET
/users/{id}/permissions

Role assignments and effective permissions for the user named in the path. Requires a bearer session. Callers may read their own; reading another user's requires the view_all_users permission, and any other caller gets 403. Answers can be several minutes old; for the caller's own, current permissions use GET /me/capabilities.

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

id*
Type
string
Required
Format
"uuid"

Responses​

User permissions — a bare object.

application/json
JSON
{
"roles": [
{
"role_name": "string",
"context_type": "string",
"context_id": "string",
"hierarchy_level": 0
}
],
"permissions": [
"string"
],
"roleDefinitions": [
{
"name": "string",
"hierarchy_level": 0,
"context_type": "string"
}
]
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get user preferences​

GET
/users/{id}/preferences

Returns the caller's own preferences. Callers may only access their own — any other path id answers 403.
Accounts with no stored row get a default object rather than a 404, so the returned key set differs slightly between the two cases. suppressed_scopes is always present: it lists the notification scopes this account's email address has been unsubscribed from via an emailed link. Those suppressions are keyed by address, not by account, so they stop mail even while the matching toggle reads true — which is exactly why they are reported separately rather than folded into the toggles.

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

id*
Type
string
Required

Responses​

User preferences

application/json
JSON
{
"user_id": "string",
"email_notifications": true,
"push_notifications": true,
"suppressed_scopes": [
"string"
],
"additionalProperties": "string"
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Update user preferences​

PUT
/users/{id}/preferences

Upserts the caller's own preferences and returns the stored row. Callers may only update their own — any other path id answers 403. suppressed_scopes is read-only and is not accepted here; an address unsubscribed by an emailed link can only be resubscribed through /unsubscribe/resubscribe.

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

id*
Type
string
Required

Request Body​

application/json
JSON
{
"view_mode": "string",
"theme": "string",
"admin_theme": "string",
"recent_searches": [
"string"
],
"search_suggestions": true,
"email_notifications": true,
"push_notifications": true,
"reduced_motion": true,
"high_contrast": true,
"font_size": "string",
"has_completed_onboarding": true,
"has_skipped_onboarding": true,
"last_visited": "string",
"auto_save": true,
"default_category": "string",
"notify_donations": true,
"notify_comments": true,
"notify_updates": true,
"notify_milestones": true,
"notify_campaign_status": true,
"notify_followers": true,
"notify_org_status": true,
"notify_payouts": true,
"notify_digest": true,
"notify_donation_reminders": true,
"notify_endorsement_requests": true
}

Responses​

Updated preferences — the stored row.

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

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Upload user avatar​

POST
/users/{id}/avatar

Upload the caller's own avatar from a base64-encoded image — JPEG, PNG or WebP, at most 5 MB decoded. Callers may only update their own.

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

id*
Type
string
Required

Request Body​

application/json
JSON
{
"fileBase64": "string",
"contentType": "string"
}

Responses​

Avatar uploaded

application/json
JSON
{
"success": true,
"avatar_url": "string"
}

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Delete user avatar​

DELETE
/users/{id}/avatar

Delete the caller's own avatar. Callers may only delete their own.

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

id*
Type
string
Required

Responses​

Avatar deleted

application/json
JSON
{
"success": true
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Self-deactivate account​

POST
/users/{id}/deactivate

Deactivates the caller's own account and clears auth cookies. Callers may only deactivate their own.

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

id*
Type
string
Required

Responses​

Account deactivated

application/json
JSON
{
"success": true,
"message": "string"
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get the pending account deletion​

GET
/users/me/deletion-request

The caller's pending account deletion. awaiting_payout is true once the 30 days have passed and deletion is waiting for money owed to the caller to be paid out.

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​

A deletion is pending.

application/json
JSON
{
"status": "string",
"requested_at": "string",
"scheduled_for": "string",
"awaiting_payout": true
}

Playground​

Server
Authorization

Samples​


Request account deletion​

POST
/users/me/deletion-request

Schedules deletion of the caller's account 30 days from now. In the same step every personal campaign of theirs that is active, paused or pending is closed (status ended), so it stops taking donations, and every session is signed out: the cookies of this one are cleared, every refresh token is revoked and every API key is revoked. An access token already issued keeps working until it expires (at most an hour).

The person can sign in again during the 30 days, which is how they reach Cancel; GET /cognito/me and the sign-in response then carry deletion_scheduled_for. They cannot publish or reopen a campaign meanwhile (publish blocker account_deletion_pending).

After the 30 days the account is deleted once nothing is owed to the person: money not yet paid out is paid out to their verified payout account first, and deletion waits for it. Donation and payout records are kept, anonymised; everything else is deleted, including the sign-in. Campaigns they created for an organization are the organization's: they keep running, and when the deletion completes they are handed to an owner of that organization, unchanged.

Idempotent: while a request is pending, calling again returns 200 with the same schedule and changes nothing. Requires a signed-in session; refused for an API key and while FundlyHub support is viewing the 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​

A deletion was already pending; its schedule, unchanged.

application/json
JSON
"string"

Playground​

Server
Authorization

Samples​


Cancel account deletion​

DELETE
/users/me/deletion-request

Cancels the caller's pending account deletion. Allowed until the deletion has completed. Campaigns the request closed go back to the status they had, if they are still closed and not deleted; any other campaign is left as it is. Requires a signed-in session; refused for an API key and while FundlyHub support is viewing the 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​

Cancelled.

application/json
JSON
{
"status": "string",
"cancelled_at": "string",
"restored_campaign_ids": [
"string"
]
}

Playground​

Server
Authorization

Samples​


Set private contact email​

PUT
/users/me/private-contact

Sets the caller's private contact email (visible only to the FundlyHub team). Validates format, blocks disposable domains, and triggers a verification email when the address changes — unless it is the caller's own verified sign-in address, which counts as verified at once. Shares the verification-resend limit: 5 requests per minute per user.

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
{
"email": "string"
}

Responses​

Private contact email saved

application/json
JSON
{
"success": true,
"email": "string",
"verified": true,
"message": "string"
}

Playground​

Server
Authorization
Body

Samples​


Set phone number​

PUT
/users/me/phone

Sets the caller's phone number (stored only; no SMS verification).

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
{
"phone": "string"
}

Responses​

Phone number saved

application/json
JSON
{
"success": true,
"phone": "string",
"message": "string"
}

Playground​

Server
Authorization
Body

Samples​


Get publish-readiness checklist​

GET
/users/me/publish-readiness

Returns the publish-gate checklist for the caller (hard blockers + soft suggestions). When the checklist is unavailable the answer is ready: true, checklist: null and migration_pending: true.

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​

Publish-readiness status

application/json
JSON
{
"ready": true,
"checklist": {
"additionalProperties": true
},
"blockers": [
"string"
],
"suggestions": [
"string"
],
"migration_pending": true
}

Playground​

Server
Authorization

Samples​


Check profile slug availability​

GET
/users/check-slug/{slug}

Parameters​

Path Parameters

slug*
Type
string
Required

Query Parameters

exclude

User id to exclude from the uniqueness check.

Type
string

Responses​

Slug availability

application/json
JSON
{
"available": true
}

Playground​

Server
Variables
Key
Value

Samples​


Get a profile's trust badges​

GET
/users/{id}/badges

The trust badges (e.g. identity verified, brand ambassador) on a profile, newest first. id is a UUID or a profile slug.

A private profile answers { "badges": [] } to everyone but its owner — the same answer as a profile with no badges, so the response does not confirm that the profile is private.

Authentication is optional; it only matters for the owner.

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)
or

Parameters​

Path Parameters

id*

Profile UUID or profile slug.

Type
string
Required

Responses​

The badges (bare object, not the data envelope)

application/json
JSON
{
"badges": [
{
"id": "string",
"badgeType": "string",
"metadata": {
"additionalProperties": "string"
},
"awardedAt": "string"
}
]
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


List a profile's campaigns​

GET
/users/{id}/campaigns

The campaigns shown on a profile: those the person runs, and those they have endorsed (is_endorsed: true), newest activity first. id is a UUID or a profile slug.

A visitor sees public campaigns in active or ended status. The profile's owner, identified by the session (there is no query flag for it), additionally sees their own draft, pending and paused campaigns and their unlisted and private ones. A private profile returns { "data": [] } to everyone but its owner.

Titles and summaries are returned in the reader's language when a translation exists (?lang=, then the language cookie, then Accept-Language).

Rate limited at 300 requests/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)
or

Parameters​

Path Parameters

id*

Profile UUID or profile slug.

Type
string
Required

Query Parameters

limit
Type
integer
Minimum
1
Maximum
100
Default
60
lang
Type
string
Valid values
"en""ru""uk""es"

Responses​

The profile's campaign cards

application/json
JSON
{
"data": [
]
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get a profile's share image​

GET
/users/{id}/og-image

The 1200×630 PNG a shared profile link unfurls into: name, avatar, account kind, location, join date and campaign count. Intended for social crawlers. id is a UUID or a profile slug. The name is the profile's display_name: the name, else @handle, else FundlyHub member, never an email address.

A private profile, like a missing one, is a 404. Cached for five minutes, server-side and via Cache-Control.

No authentication. Rate limited at 300 requests/minute per IP.

Parameters​

Path Parameters

id*

Profile UUID or profile slug.

Type
string
Required

Responses​

The image

image/png

Playground​

Server
Variables
Key
Value

Samples​


Resend the private-contact verification email​

POST
/users/me/private-contact/resend

Sends a new verification link to the caller's private contact email (set with PUT /users/me/private-contact). Links last 24 hours; a verified private contact email is required before publishing a campaign. If the address is already verified, nothing is sent and the response says so.

Rate limited at 5 requests/minute per user, a bucket shared with PUT /users/me/private-contact.

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​

Sent, or already verified

application/json
JSON
{
"success": true,
"alreadyVerified": true,
"email": "string"
}

Playground​

Server
Authorization

Samples​


List top creators​

GET
/marketplace/creators

Public profiles ranked by money raised, then followers. Cached server- side; cached says whether this answer came from the cache.

fundsRaised is in DOLLARS (a decimal), unlike the rest of the API, which uses integer cents.

No authentication.

Parameters​

Query Parameters

limit
Type
integer
Minimum
1
Maximum
100
Default
20

Responses​

The creators (bare object with data, not paginated)

application/json
JSON
{
"data": [
{
"id": "string",
"name": "string",
"avatar": "string",
"location": "string",
"bio": "string",
"profileType": "string",
"fundsRaised": 0,
"campaignsCompleted": 0,
"followersCount": 0,
"sharesCount": 0,
"badges": [
"string"
]
}
],
"total": 0,
"executionTimeMs": 0,
"cached": true
}

Playground​

Server
Variables
Key
Value

Samples​


Public leaderboard​

GET
/leaderboard

One ranked list on impact = raised + given + driven, in integer cents, over the chosen period.
Raised is the sum of the person's counted campaign cards — settled gifts to public fundraisers they organize, net of processor fees, their own gifts included;
Given is every settled gift they made under their name; Driven is other people's settled gifts through
their share or ambassador link to fundraisers they do not organize. Every dollar counts once.
Anonymous donors appear as alias rows keyed on an opaque anonymousKey; guest and anonymous rows link to their donor page under /d/{kind}/{key}.
When the request carries a session, standing describes where the caller ranks on the full view.
q searches the ranked board by name without renumbering it: a match keeps the rank it has on the full view.

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)
or

Parameters​

Query Parameters

period
Type
string
Valid values
"all""30d""7d"
Default
"all"
role

Everyone; people organizing a public fundraiser; ambassador role holders; or donors — everyone with a settled gift under their name, whatever their role, anonymous identities included. Everyone, creators and ambassadors rank on impact; donors rank on given (see metric). A filtered view is ranked within itself.

Type
string
Valid values
"all""creators""ambassadors""donors"
Default
"all"
offset
Type
integer
Minimum
0
Default
0
limit
Type
integer
Minimum
1
Maximum
100
Default
25
q

Name search over this view. Trimmed and cut to 100 characters.

Type
string
Max Length
100
lang

Language for badge titles and anonymous aliases (en, ru, uk, es). Defaults from Accept-Language.

Type
string

Responses​

One page of the ranked view

application/json
JSON
{
"entries": [
{
"rank": 0,
"tied": true,
"id": "string",
"kind": "string",
"name": "string",
"avatar": "string",
"href": "string",
"anonymousKey": "string",
"isCreator": true,
"isAmbassador": true,
"raised": 0,
"given": 0,
"driven": 0,
"impact": 0,
"score": 0,
"impressions": 0,
"gifts": 0,
"badges": [
{
"slug": "string",
"artKey": "string",
"artUrl": "string",
"tier": "string",
"title": "string"
}
],
"badgeCount": 0
}
],
"qualified": 0,
"hasMore": true,
"standing": {
"rank": 0,
"tied": true,
"score": 0,
"impact": 0,
"raised": 0,
"given": 0,
"driven": 0,
"gap": 0,
"above": "string"
},
"period": "string",
"role": "string",
"metric": "string",
"offset": 0,
"limit": 0,
"query": "string",
"executionTimeMs": 0,
"cached": true
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Public donor page​

GET
/donors/{kind}/{key}

The public page behind a guest or anonymous donor row on the leaderboard.

A donor identity is addressed ONLY by an opaque public key of 20 hex characters. The key is
one-way: no email, no identity id and no account reference ever leaves the server, and the
guest key and the anonymous key of one person cannot be related to each other.

given and gifts cover every settled gift of the identity — the same figures the
leaderboard row shows — including gifts to campaigns that are not public. The campaigns
list is public campaigns only, and campaignsHidden counts the gifts the list cannot show.

An anonymous identity is never named: name is null and anonymousKey carries the key, from
which the client derives the same localized alias the donor wall shows.

No authentication: the page is viewer-independent. Money is in integer cents.

Parameters​

Path Parameters

kind*
Type
string
Required
Valid values
"guest""anon"
key*

The opaque public key from a leaderboard row or a search result.

Type
string
Required
Pattern
"^[0-9a-f]{20}$"

Responses​

The donor page

application/json
JSON
{
"kind": "string",
"key": "string",
"name": "string",
"anonymousKey": "string",
"given": 0,
"gifts": 0,
"currency": "string",
"firstGiftAt": "string",
"lastGiftAt": "string",
"rank": 0,
"score": 0,
"href": "string",
"campaigns": [
{
"id": "string",
"slug": "string",
"title": "string",
"coverImage": "string",
"isProject": true,
"givenCents": 0,
"gifts": 0,
"lastGiftAt": "string"
}
],
"campaignsHidden": 0,
"hasMoreCampaigns": true
}

Playground​

Server
Variables
Key
Value

Samples​


Get platform statistics​

GET
/stats

Public endpoint returning aggregate platform stats. A bare object, not wrapped in data.

Responses​

Platform statistics

application/json
JSON
{
"totalRaisedCents": 1234560000,
"activeCampaigns": 0,
"totalSupporters": 0,
"totalCreators": 0,
"totalGoalCents": 5000000000
}

Playground​

Samples​


Get trust center status​

GET
/trust/status

Live security and compliance status for the Trust Center. Public; cached for up to 15 minutes.

Responses​

Trust status

application/json
JSON
{
"success": true,
"data": {
"overallStatus": "string",
"lastChecked": "string",
"controls": [
{
"id": "string",
"label": "string",
"icon": "string",
"status": "string",
"lastChecked": "string",
"details": "string"
}
]
}
}

Playground​

Samples​


ZIP code lookup​

GET
/location/zip/{zipCode}

Look up city and state from a 5-digit US ZIP code. Public; answers are cached.

Parameters​

Path Parameters

zipCode*
Type
string
Required
Example"95630"

Responses​

Location data

application/json
JSON
{
"zipCode": "string",
"city": "string",
"state": "string",
"stateAbbreviation": "string"
}

Playground​

Server
Variables
Key
Value

Samples​


Get feature flags​

GET
/system-settings/features

The features.* flags, read-only, for the signed-in caller — so the client can hide what the server will refuse. Flags that only concern FundlyHub's own operations are omitted. Each value is reduced to the three gating fields.

The server treats a flag that has no row as enabled, so a flag absent from this list is not necessarily off.

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​

The flags

application/json
JSON
{
"data": [
{
"setting_key": "features.comments",
"setting_value": {
"enabled": true,
"allowed_roles": [
"string"
],
"disabled_message": "string"
},
"category": "string"
}
]
}

Playground​

Server
Authorization

Samples​


Get the platform's published numbers​

GET
/platform/numbers

The figures FundlyHub publishes about itself on /@fundlyhub. The same answer for every reader, cached for five minutes; computed_at says how old it is. GET /stats is unchanged and still served.

No authentication. Rate limited at 300 requests/minute per IP.

Responses​

The numbers (bare object)

application/json
JSON
"string"

Playground​

Samples​


List the FundlyHub team​

GET
/platform/team

The FundlyHub team members shown on /@fundlyhub: staff with a public, slugged profile and an account in good standing — at most 48, ordered by role then name. An empty list is a normal 200.

No authentication. Rate limited at 300 requests/minute per IP.

Parameters​

Query Parameters

lang

Cache key for future localised fields. Anything else is treated as en.

Type
string
Valid values
"en""ru""uk""es"
Default
"en"

Responses​

The roster

application/json
JSON
{
"members": [
]
}

Playground​

Server
Variables
Key
Value

Samples​


List platform ambassadors with impact​

GET
/platform/ambassadors

Every holder of the ambassador role who is not banned (at most 100), ranked by impact. total counts all of them; members lists only those with a public, slugged profile, so total can exceed members.length.

No authentication. Rate limited at 300 requests/minute per IP.

Parameters​

Query Parameters

lang
Type
string
Valid values
"en""ru""uk""es"
Default
"en"

Responses​

The ambassador rail

application/json
JSON
{
"members": [
],
"total": 0
}

Playground​

Server
Variables
Key
Value

Samples​


Tip FundlyHub​

POST
/platform/tips

Starts a tip to FundlyHub itself — not a donation to a cause, and not tax-deductible. Creates a pending tip row and a Stripe Checkout Session (payment mode for one_time, monthly subscription mode for recurring) and returns its url; send the browser there. Stripe returns the payer to /tip/{tip_id} on the site. The tip is settled by the Stripe webhook, not by this call.

Authentication is optional. With a session the tip is attributed to the account, and the account's name and email are used when the body does not give them. Currency is always USD.

Rate limited at 10 requests/minute per IP (authentication bucket).

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)
or

Request Body​

application/json
JSON
{
"amount_cents": 0,
"kind": "string",
"donor_email": "string",
"donor_name": "string",
"is_anonymous": false
}

Responses​

Checkout started

application/json
JSON
{
"tip_id": "string",
"kind": "string",
"amount_cents": 0,
"currency": "usd",
"url": "string"
}

Playground​

Server
Authorization
Body

Samples​


Get a tip receipt​

GET
/platform/tips/{id}

The public receipt for one tip: amount, cadence, status and dates, and the signed-in tipper's profile name unless they tipped anonymously. Never an email or a Stripe identifier.

A tip that has not settled yet is a 200 with status: pending — the payer often arrives from Stripe before the webhook does. A monthly tip also carries subscription; its next charge date is read from Stripe once the tip is paid.

No authentication: the tip id is the capability. Rate limited at 300 requests/minute per IP.

Parameters​

Path Parameters

id*
Type
string
Required
Format
"uuid"

Responses​

The receipt (bare object)

application/json
JSON
"string"

Playground​

Server
Variables
Key
Value

Samples​


Email a tip receipt​

POST
/platform/tips/{id}/receipt/email

Emails the receipt for one paid tip to any address — every figure comes from the tip row, so the caller controls only the recipient. Capped at 5 sends per tip, after which this answers 429 for that tip permanently. A missing and an unpaid tip get the same 404.

The mail queue is processed immediately; message says whether the email was sent or only queued.

Authentication is optional. Rate limited at 5 requests/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)
or

Parameters​

Path Parameters

id*
Type
string
Required
Format
"uuid"

Request Body​

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

Responses​

Sent or queued

application/json
JSON
{
"success": true,
"message": "string"
}

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Get the homepage live-activity feed​

GET
/home/activity

The homepage hero's live chips, newest first: gifts, referral-link views and clicks, people viewing a campaign right now, campaigns submitted for review (never named), and achievements earned. Every event passes the same public gates as the surface it comes from — only public, active or ended campaigns are named, and anonymous donors are not.

events is a discriminated union on kind. The same answer for every reader of a language; publicly cached for 15 seconds.

No authentication. Rate limited at 300 requests/minute per IP.

Parameters​

Query Parameters

limit
Type
integer
Minimum
1
Maximum
40
Default
24
lang

Campaign titles in this language when translated.

Type
string
Valid values
"en""ru""uk""es"

Responses​

The feed

application/json
JSON
{
"data": {
"events": [
],
"generated_at": "string"
}
}

Playground​

Server
Variables
Key
Value

Samples​


Send a campaign-page presence heartbeat​

POST
/presence/fundraisers/{id}

Records that a visitor has a campaign page open; feeds the "N people viewing" chip in GET /home/activity. Designed for navigator.sendBeacon — no body. The visitor is the visitor_id cookie, or the per-tab v query parameter when there is no cookie; only a one-way hash of it is stored, and it expires on its own.

No authentication. Rate limited at 4 requests/minute per IP and campaign, then the 300/minute public bucket.

Parameters​

Path Parameters

id*

Fundraiser UUID.

Type
string
Required
Format
"uuid"

Query Parameters

v

Per-tab visitor id, used only when there is no visitor_id cookie.

Type
string
Pattern
"^[A-Za-z0-9_-]{8,64}$"

Responses​

Recorded (no body)

Playground​

Server
Variables
Key
Value

Samples​


Donors​

A donor's own giving history, summary, and annual statements


Get donor summary​

GET
/donor/me/summary

Aggregate giving stats for the authenticated donor, anonymous gifts included. lifetimeAmountCents counts paid gifts only (no refunds or failures); the counts include every gift that left pending. A bare object.

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​

Donor summary

application/json
JSON
{
"lifetimeAmountCents": 0,
"donationCount": 0,
"supportedFundraisers": 0,
"lastDonationAt": "string"
}

Playground​

Server
Authorization

Samples​


Get donor donation history​

GET
/donor/me/donations

Paginated giving history for the authenticated donor with optional filters.

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

page
Type
integer
Minimum
1
Default
1
limit
Type
integer
Minimum
1
Maximum
100
Default
20
year
Type
integer
status
Type
string
Valid values
"paid""refunded""failed""pending"
fundraiserId
Type
string
Format
"uuid"

Responses​

Donor donations, newest first

application/json
JSON
{
"data": [
{
"id": "string",
"fundraiser_id": "string",
"fundraiser_title": "string",
"fundraiser_slug": "string",
"amount_cents": 0,
"tip_amount_cents": 0,
"fee_amount_cents": 0,
"currency": "string",
"payment_status": "string",
"payment_intent_id": "string",
"is_anonymous": true,
"comment": "string",
"created_at": "string"
}
],
"pagination": {
"page": 0,
"limit": 0,
"total": 0,
"totalPages": 0
}
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Download annual giving statement​

GET
/donor/me/annual-statement

Generates a year-end giving summary for the authenticated donor as PDF or CSV (binary download). Includes only paid donations in the requested calendar year. Not a tax receipt.

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

year*

Calendar year. Between 2026 and the current year.

Type
integer
Required
Minimum
2026
format*
Type
string
Required
Valid values
"pdf""csv"

Responses​

Generated statement file

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Search​

Full-text search and autocomplete


Full-text search​

GET
/search

Search across campaigns, organizations, users and donors. Queries shorter than two characters return an empty result set rather than an error. Authentication is optional and does not change the result set. Donor rows cover guest donors (matched on the name given at checkout — never on an email) and anonymous identities (matched on the localized alias the donor wall shows for that identity), and they link to /d/{kind}/{key}.
Two limits apply to donor rows specifically. They are returned on the FIRST PAGE ONLY (offset=0); the donor ranking is a single highest-given-first list with no stable second page, so a later offset would repeat the same rows rather than continue them. And a guest-donor name match needs three consecutive alphanumeric characters somewhere in the query — An, a_n and ___ match no guest donor. Anonymous alias matching is unaffected and keeps the two-character minimum. Campaigns, organizations and users page normally and have no such floor.

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)
or

Parameters​

Query Parameters

q*

Search query. Fewer than 2 characters returns an empty result set.

Type
string
Required
scope

Limit to a specific resource type.

Type
string
Valid values
"all""campaigns""users""orgs""donors"
Default
"all"
limit
Type
integer
Default
20
Maximum
100
offset

Pages campaigns. Donor rows are returned only at offset=0 — see the description above.

Type
integer
Default
0
lang

Language an anonymous donor's alias is matched and cached in. Defaults from Accept-Language.

Type
string
Valid values
"en""ru""uk""es"

Responses​

Search results

application/json
JSON
"string"

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Autocomplete suggestions​

GET
/suggest

Typeahead suggestions drawn from the titles of active, public campaigns: a prefix of the original title or of any translated title matches, and the suggestion is the title in the reader's language (lang, the language cookie, then Accept-Language). Queries shorter than two characters return an empty list.

Parameters​

Query Parameters

q*
Type
string
Required
limit
Type
integer
Default
10
Maximum
20

Responses​

Suggestions

application/json
JSON
{
"suggestions": [
"string"
],
"executionTimeMs": 0,
"cached": true
}

Playground​

Server
Variables
Key
Value

Samples​


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

List milestones​

GET
/fundraisers/{fundraiserId}/milestones

Get all milestones for a fundraiser, earliest due date first. Readable exactly when GET /fundraisers/{id} is: a campaign that is not active, paused or ended, is private, or has been deleted answers 404 to everyone but its owner. Authentication is optional.

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)
or

Parameters​

Path Parameters

fundraiserId*
Type
string
Required
Format
"uuid"

Query Parameters

lang

Overlay the stored translation of title and description for this language, when one exists.

Type
string
Valid values
"en""ru""uk""es"

Responses​

List of milestones

application/json
JSON
{
"milestones": [
]
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Create milestone​

POST
/fundraisers/{fundraiserId}/milestones

Add a milestone to a campaign. Only the campaign owner may post one, the caller's email must be verified, and the endpoint is gated by the features.milestones flag.
The request body is camelCase (targetAmountCents, dueDate) while the response row is snake_case (target_amount_cents, due_date). Both are in CENTS; target_amount_cents is also accepted in the body. The dollars-era targetAmount is not, and is ignored.

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

fundraiserId*
Type
string
Required
Format
"uuid"

Request Body​

application/json
JSON
{
"title": "string",
"description": "string",
"targetAmountCents": 0,
"dueDate": "string"
}

Responses​

Milestone created

application/json
JSON
"string"

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Get milestone​

GET
/milestones/{id}

A single milestone by id. Public when its campaign is: a milestone of a campaign that is not active, paused or ended, is private, or has been deleted answers 404 to everyone but the campaign's owner. Authentication is optional.

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)
or

Parameters​

Path Parameters

id*
Type
string
Required
Format
"uuid"

Query Parameters

lang

Overlay the stored translation of title and description for this language, when one exists.

Type
string
Valid values
"en""ru""uk""es"

Responses​

Milestone details

application/json
JSON
"string"

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Update milestone​

PUT
/milestones/{id}

Partial update of a milestone. Only the owner of the parent campaign may update it, and the caller's email must be verified. Send only the fields you are changing; an empty body answers 400.
The request body is camelCase (targetAmountCents, dueDate, completedAt) while the response row is snake_case. Setting completedAt is what marks a milestone complete.

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

id*
Type
string
Required
Format
"uuid"

Request Body​

application/json
JSON
{
"title": "string",
"description": "string",
"targetAmountCents": 0,
"dueDate": "string",
"completedAt": "string"
}

Responses​

Milestone updated

application/json
JSON
"string"

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Delete milestone​

DELETE
/milestones/{id}

Deletes a milestone. Only the owner of the parent campaign may delete it.

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

id*
Type
string
Required
Format
"uuid"

Responses​

Deleted

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Save a hand-edited milestone translation​

PUT
/fundraisers/{id}/milestones/{milestoneId}/translations/{lang}

Creates or overwrites one milestone's translation in lang as source: "human". The milestone must belong to the campaign in the path. Campaign owner only. Audit-logged. lang may not be the campaign's source language.

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

id*

The campaign's UUID.

Type
string
Required
Format
"uuid"
milestoneId*
Type
string
Required
Format
"uuid"
lang*
Type
string
Required
Valid values
"en""ru""uk""es"

Request Body​

application/json
JSON
{
"title": "string",
"description": "string"
}

Responses​

The saved row

application/json
JSON
{
"data": {
"milestone_id": "string",
"language": "string",
"title": "string",
"description": "string",
"source": "string",
"translated_at": "string"
}
}

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Payments​

Stripe payment processing


Create payment intent​

POST
/payments/create-intent

Create a Stripe PaymentIntent for a donation. This is the first half of
the donation flow; confirm it with POST /payments/confirm once Stripe
reports the payment succeeded.

Every field is snake_case, and every amount is in integer cents.
amount_cents is the donation itself; tip_amount_cents is the
optional tip to FundlyHub. The charge Stripe sees is
amount_cents + tip_amount_cents, and it must clear Stripe's $0.50
(50 cent) minimum.

amount_cents was called amount. The value was always cents — only
the name has changed, so that it says so.

fundraiser_id decides where the money goes. Omit it and the
PaymentIntent is created against the platform account with no campaign
attribution — the donation is not credited to any campaign and no
transfer to a creator is scheduled. It is optional in the sense that
the request succeeds without it, not in the sense that it is safe to
leave out.

The campaign must be active and not deleted; anything else is
rejected (404 if the id is unknown, 409 if the campaign exists but
cannot accept money).

Authentication is optional — a signed-in donor gets the donation linked
to their account, an anonymous one does not. reCAPTCHA is enforced
(see below), except that a signed-in session whose email is verified
may omit the token. While donations are switched off platform-wide the
request is refused with 403 and no PaymentIntent is created.

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)
or

Parameters​

Header Parameters

x-recaptcha-token

reCAPTCHA v3 token, action payment. Required unless supplied as recaptcha_token in the body, or the caller is a signed-in session with a verified email. Missing (guest or unverified) → 400; failing the score threshold → 403, whoever sent it.

Type
string
x-app-attest-key-id

iOS only. The App Attest key id (standard base64, as DCAppAttestService.generateKey returns it) of a key registered with POST /app-attest/attest. Send with x-app-attest-assertion.

Type
string
x-app-attest-assertion

iOS only. base64 of the assertion from generateAssertion(keyId, clientDataHash: SHA256(raw request body)). The body must carry a fresh app_attest_challenge. A valid assertion replaces the reCAPTCHA token; the headers alone never do. An invalid one answers 403 with code APP_ATTEST_INVALID, APP_ATTEST_KEY_UNKNOWN (attest a new key) or APP_ATTEST_CHALLENGE_INVALID (fetch a new challenge), unless the request passes reCAPTCHA some other way.

Type
string

Request Body​

application/json
JSON
{
"amount_cents": 5000,
"currency": "usd",
"fundraiser_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"tip_amount_cents": 500,
"tip_percent": 10,
"donor_email": "donor@example.com",
"donor_name": "Alex Rivera",
"is_anonymous": false
}

Responses​

PaymentIntent created

application/json
JSON
{
"client_secret": "string",
"payment_intent_id": "pi_3abc123def456",
"amount_cents": 5500,
"stripe_fee_cents": 190,
"net_amount_cents": 5310
}

Playground​

Server
Authorization
Headers
Body

Samples​


Confirm payment​

POST
/payments/confirm

Confirm a PaymentIntent that Stripe has reported as succeeded, and
settle the donation record.

The field is payment_intent_id (snake_case) — the value returned as
payment_intent_id by POST /payments/create-intent.

Safe to retry: a PaymentIntent whose donation is already paid is
returned as-is rather than double-counted. Stripe webhooks reconcile the
same donation independently, so a client that never reaches this call
still ends up with a settled donation — calling it just makes the
receipt available immediately.

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)
or

Request Body​

application/json
JSON
{
"payment_intent_id": "pi_3abc123def456"
}

Responses​

Payment confirmed; the settled donation is returned.

application/json
JSON
{
"data": {
"id": "string",
"fundraiser_id": "string",
"donor_user_id": "string",
"donor_name": "string",
"donor_avatar": "string",
"amount_cents": 5000,
"currency": "USD",
"tip_amount_cents": 500,
"fee_amount_cents": 175,
"net_amount_cents": 4825,
"payment_status": "string",
"payment_provider": "string",
"payment_intent_id": "string",
"receipt_id": "string",
"comment": "string",
"is_anonymous": true,
"anonymous_key": "string",
"created_at": "string",
"campaign_title": "string",
"campaign_slug": "string",
"card_brand": "string",
"card_last4": "string",
"payment_method_type": "string"
}
}

Playground​

Server
Authorization
Body

Samples​


App Attest​

Apple App Attest for the FundlyHub iOS app. A request carrying a valid assertion may skip reCAPTCHA on POST /payments/create-intent and POST /donations, guest or signed in. See the Native Clients guide for the byte-level protocol.


Issue an App Attest challenge​

POST
/app-attest/challenge

A random, single-use challenge for the iOS app, valid for
expires_in_seconds (300). Fetch one before attesting a key and one
before every donation request that carries an App Attest assertion.

Public (guests call it). Rate limited to 30 a minute per address.
Answers 503 with code: APP_ATTEST_DISABLED while App Attest is not
configured on the server.

Responses​

A fresh challenge (Cache-Control: no-store).

application/json
JSON
{
"challenge": "q7uE3fP9yK2sV1xW4zA6bC8dE0fG2hJ4kL6mN8pR0tU",
"expires_in_seconds": 300
}

Playground​

Samples​


Register an App Attest key​

POST
/app-attest/attest

Register a device key with its attestation. The server verifies the
certificate chain to Apple's App Attestation Root CA, that the
attestation was made for challenge
(clientDataHash = SHA256(UTF-8 bytes of challenge)), the App ID, the
environment, a zero counter and that key_id is the key's hash, then
stores the public key. Attest once per key; attesting a key that is
already registered changes nothing.

Public (guests call it). Rate limited to 10 a minute per address.

Request Body​

application/json
JSON
{
"key_id": "string",
"attestation": "string",
"challenge": "string"
}

Responses​

Key verified and registered.

Playground​

Server
Body

Samples​


Enhance text​

POST
/ai/enhance-text

Rewrite or generate one campaign field with an LLM. Requires a bearer session and is gated by the features.ai_text_enhancement flag. Throughput is capped per user (10 requests per minute by default).
context.field selects the system prompt and must be one of summary, story or milestone; any other value falls back to the summary prompt. text is capped at the server's maximum length.

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
{
"action": "string",
"text": "string",
"context": {
"field": "string",
"title": "string",
"category": "string",
"goalAmount": 0,
"beneficiaryName": "string",
"milestoneTitle": "string",
"milestoneAmount": 0
}
}

Responses​

Enhanced text

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

Playground​

Server
Authorization
Body

Samples​


Campaign AI chat​

POST
/ai/campaign-chat

Conversational assistant for the campaign-creation wizard. Requires a
bearer session; throughput is capped per user (10 requests per minute
by default).

The response is a Server-Sent Events stream (text/event-stream),
not a JSON document. Each event carries one JSON object:

  • {"type":"token","content":"…"} — one streamed text token
  • {"type":"campaign_data","data":{…}} — campaign fields the model extracted
  • {"type":"done"} — stream complete
  • {"type":"error","message":"…"} — the stream failed mid-flight

Only the most recent 30 messages of messages are sent to the model.

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
{
"messages": [
{
"role": "string",
"content": "string"
}
],
"extractedData": {
"additionalProperties": "string"
}
}

Responses​

Server-Sent Events stream of tokens and extracted campaign data.

text/event-stream
JSON
"string"

Playground​

Server
Authorization
Body

Samples​


Detect category​

POST
/ai/detect-category

Classifies a campaign into one of the platform's categories. Requires a bearer session; throughput is capped per user (10 requests per minute by default).
Send any combination of title, summary and description — they are joined, truncated to 500 characters and classified. At least one must be present and the joined text must be 3 characters or longer.

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
{
"title": "string",
"summary": "string",
"description": "string"
}

Responses​

Detected category

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

Playground​

Server
Authorization
Body

Samples​


Generate a project update​

POST
/ai/generate-update

Writes or rewrites a campaign update's text with an LLM. Requires a bearer session and is gated by the features.ai_update_generation flag. Throughput is capped per user inside the handler (10 requests per minute by default).
context.fundraiserTitle is required. Up to three context.previousUpdates are folded into the prompt for generate and improve.

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
{
"action": "string",
"text": "string",
"context": {
"fundraiserTitle": "string",
"fundraiserId": "string",
"milestoneTitle": "string",
"previousUpdates": [
"string"
]
}
}

Responses​

Generated text

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

Playground​

Server
Authorization
Body

Samples​


Import a campaign from a URL​

POST
/ai/scrape-campaign-url

Reads a campaign page on another platform and extracts its fields with an LLM, for the "import from link" step of the campaign builder. Requires a bearer session; throughput is capped per user inside the handler (10 requests per minute by default).
The response carries a one-time scrape_token, valid for 30 minutes; pass it on POST /fundraisers when creating the imported campaign. When the LLM is not configured, only the page title is returned, with a note and no token.

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
{
"url": "string"
}

Responses​

Extracted campaign fields

application/json
JSON
{
"success": true,
"data": {
"title": "string",
"summary": "string",
"story": "string",
"goalAmount": 0,
"categoryName": "string",
"beneficiaryName": "string",
"location": "string",
"type": "string",
"isProject": true,
"coverImage": "string",
"galleryImages": [
"string"
],
"additionalProperties": "string"
},
"platform": "string",
"scrape_token": "string",
"note": "string"
}

Playground​

Server
Authorization
Body

Samples​


RBAC​

The signed-in caller's own roles and permissions


Get current user capabilities​

GET
/me/capabilities

Scope-aware permissions and roles for the authenticated user. Requires a bearer session and nothing else — this is the endpoint a client should use to decide what to show. The answer always includes the caller's global roles; with an organization or fundraiser scope it adds the roles held in that scope. A bare object, not wrapped in data.

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

scopeType

Defaults to global. scopeId is required for the other two.

Type
string
Valid values
"global""organization""fundraiser"
Default
"global"
scopeId

The organization or fundraiser id. Required unless scopeType is global.

Type
string
Format
"uuid"

Responses​

User capabilities

application/json
JSON
{
"permissions": [
"string"
],
"roles": [
"string"
],
"scope": {
"type": "string",
"id": "string"
},
"fetchedAt": "string",
"expiresAt": "string"
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Notifications​

In-app notifications for the authenticated user. Which events also generate email is governed by the toggles on /users/{id}/preferences, not by anything under /notifications.


List notifications​

GET
/notifications

Returns the authenticated user's notifications, newest first, together with the unread count. The count always excludes archived rows, even when archived=true is requested.
There is no offset pagination here — raise limit (max 100) to see further back.

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
20
Maximum
100
archived

Pass "true" to return archived notifications instead of the active ones. Any other value returns the active ones.

Type
string
Valid values
"true""false"

Responses​

Notifications payload

application/json
JSON
{
"notifications": [
],
"unreadCount": 0,
"updatesUnreadCount": 0
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Delete notifications​

DELETE
/notifications

Permanently deletes the given notifications for the authenticated user.

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
{
"ids": [
"string"
]
}

Responses​

Deletion result

application/json
JSON
{
"success": true,
"deleted": 0
}

Playground​

Server
Authorization
Body

Samples​


Mark notifications as read​

PATCH
/notifications/mark-read

Marks the given notification ids as read for the authenticated user.

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
{
"ids": [
"string"
]
}

Responses​

Update result

application/json
JSON
{
"success": true,
"updated": 0
}

Playground​

Server
Authorization
Body

Samples​


Mark all notifications as read​

PUT
/notifications/read-all

Marks all of the authenticated user's notifications as read.

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​

Update result

application/json
JSON
{
"success": true,
"updated": 0
}

Playground​

Server
Authorization

Samples​


Mark one notification as read​

PUT
/notifications/{id}/read

Marks a single notification as read for the authenticated user.

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

id*
Type
string
Required

Responses​

Update result

application/json
JSON
{
"success": true,
"updated": 0
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Archive notifications​

PATCH
/notifications/archive

Archives the given notification ids for the authenticated user.

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
{
"ids": [
"string"
]
}

Responses​

Archive result

application/json
JSON
{
"success": true,
"archived": 0
}

Playground​

Server
Authorization
Body

Samples​


List my campaign updates​

GET
/me/campaign-updates

Updates posted on campaigns the authenticated user is connected to, newest first, each with its read state, plus the unread count. Read state is kept on the server, so it is the same on every device.
A campaign is included when the user follows its holder — the person running a personal campaign, or the organization an org campaign belongs to — and the campaign is public and active or ended; or when the user has a paid gift to it and it is active, ended or paused and not private (an unlisted campaign a donor holds the link to is included). The user's own campaigns and own updates are never included, nor deleted campaigns or withdrawn updates.
An update posted before the user started following or first gave is returned with is_read: true and never counts as unread.
Paged by an opaque keyset cursor: pass next_cursor back as cursor until it is null.

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
20
Minimum
1
Maximum
50
cursor

The next_cursor of the previous page. A cursor this API did not mint is a 400.

Type
string
lang

Overlay translations into this locale, as GET /projects/{fundraiserId}/updates does.

Type
string
Valid values
"en""ru""uk""es"

Responses​

One page of the feed

application/json
JSON
{
"data": [
],
"next_cursor": "string",
"unread_count": 0
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Mark all my campaign updates as read​

PUT
/me/campaign-updates/read-all

Marks every unread update in the user's feed read. With until, only updates posted at or before that instant (inclusive to the millisecond), so clearing the list a client is showing does not also clear an update that arrived after it was fetched.

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
{
"until": "string"
}

Responses​

Update result and the new unread count

application/json
JSON
{
"success": true,
"updated": 0,
"unread_count": 0
}

Playground​

Server
Authorization
Body

Samples​


Mark one campaign update as read​

PUT
/me/campaign-updates/{updateId}/read

Marks one update read for the authenticated user. Idempotent: an update already read answers updated: 0 and keeps its first read_at. Any existing, non-withdrawn update may be marked, whether or not it is in the user's feed, so a client can mark an update read wherever it was opened. There is no "mark unread", as for notifications.

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

updateId*
Type
string
Required
Format
"uuid"

Responses​

Update result and the new unread count

application/json
JSON
{
"success": true,
"updated": 0,
"unread_count": 0
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Check follow status​

GET
/subscriptions/status

Returns whether followerId currently follows followingId. A signed-in caller may ask about any pair — follow edges are public.

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

followerId*
Type
string
Required
followingId*
Type
string
Required
followingType

Defaults to "user".

Type
string
Valid values
"user""organization"
Default
"user"

Responses​

Follow status

application/json
JSON
{
"isFollowing": true
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Follow a user or organization​

POST
/subscriptions

Creates a follow edge from the authenticated caller to following_id. The follower is always the authenticated user and cannot be supplied by the client. Gated by the features.user_follow_user flag.

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
{
"following_id": "string",
"following_type": "user"
}

Responses​

Follow created

application/json
JSON
{
"success": true
}

Playground​

Server
Authorization
Body

Samples​


Unfollow a user or organization​

DELETE
/subscriptions/{followerId}/{followingId}/{followingType}

Removes a follow edge. The path followerId must match the authenticated caller.

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

followerId*
Type
string
Required
followingId*
Type
string
Required
followingType*
Type
string
Required
Valid values
"user""organization"

Responses​

Follow removed

application/json
JSON
{
"success": true
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


List a user's followers​

GET
/users/{id}/followers

Returns the users that follow the given user. Emails are never exposed.
A PRIVATE PROFILE ANSWERS AN EMPTY ARRAY to anyone but its owner (#1696). This list publishes other people's names, avatars, handles and counts, one row per follow, so a private profile's social graph is not enumerable through it. The COUNTS remain public — they ride on the profile payload, which carries real figures for a private profile. 200 with [], not 404: the person exists, their graph is closed.

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)
or

Parameters​

Path Parameters

id*
Type
string
Required

Query Parameters

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

Responses​

Follower list

application/json
JSON
[
{
"id": "string",
"name": "string",
"avatar": "string",
"email": "string",
"role": "string",
"profile_slug": "string",
"follower_count": 0,
"campaign_count": 0,
"type": "string"
}
]

Playground​

Server
Authorization
Variables
Key
Value

Samples​


List who a user is following​

GET
/users/{id}/following

Returns the entities the given user follows. Emails are never exposed.
A PRIVATE PROFILE ANSWERS AN EMPTY ARRAY to anyone but its owner (#1696). This list publishes other people's names, avatars, handles and counts, one row per follow, so a private profile's social graph is not enumerable through it. The COUNTS remain public — they ride on the profile payload, which carries real figures for a private profile. 200 with [], not 404: the person exists, their graph is closed.

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)
or

Parameters​

Path Parameters

id*
Type
string
Required

Query Parameters

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

Responses​

Following list

application/json
JSON
[
{
"id": "string",
"name": "string",
"avatar": "string",
"email": "string",
"role": "string",
"profile_slug": "string",
"follower_count": 0,
"campaign_count": 0,
"type": "string"
}
]

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Recalculate follower counts​

POST
/users/{id}/recalculate-counts

Recounts the caller's followers and followings, stores follower_count / following_count on the profile, and returns them. id must be the caller's own profile UUID; any other profile answers 403. The counts are also refreshed whenever a follow is created or removed, so this is only a manual resync. Requires a bearer session.

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

id*
Type
string
Required
Format
"uuid"

Responses​

The recounted figures

application/json
JSON
{
"success": true,
"data": {
"follower_count": 0,
"following_count": 0
}
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


List comments for a fundraiser​

GET
/fundraisers/{fundraiserId}/comments

Returns paginated comments for a fundraiser, newest first. Hidden and retracted comments are left out. A comment written as a donor's note from their receipt carries its gift (donation_amount_cents, donation_currency); on an anonymous gift the author fields are null and is_anonymous is true. Every row carries gif, a GIF object or null; a GIF comment's content may be empty.
Authentication is optional. Every row carries like_count; for a signed-in caller liked_by_me says whether they like it, and for a guest it is always false.

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)
or

Parameters​

Path Parameters

fundraiserId*
Type
string
Required
Format
"uuid"

Query Parameters

limit
Type
integer
Default
50
Minimum
1
Maximum
100
offset
Type
integer
Default
0
Minimum
0

Responses​

Comment list

application/json
JSON
{
"data": [
{
"id": "string",
"fundraiser_id": "string",
"content": "string",
"gif": {
"id": "xT4uQulxzV39haRFjG",
"title": "string",
"width": 480,
"height": 270,
"mp4_url": "https://media2.giphy.com/media/xT4uQulxzV39haRFjG/giphy.mp4",
"webp_url": "https://media2.giphy.com/media/xT4uQulxzV39haRFjG/giphy.webp",
"gif_url": "https://media2.giphy.com/media/xT4uQulxzV39haRFjG/giphy.gif",
"still_url": "https://media2.giphy.com/media/xT4uQulxzV39haRFjG/giphy_s.gif",
"preview_mp4_url": "https://media2.giphy.com/media/xT4uQulxzV39haRFjG/200w.mp4",
"preview_webp_url": "https://media2.giphy.com/media/xT4uQulxzV39haRFjG/200w.webp",
"preview_width": 200,
"preview_height": 113
},
"parent_comment_id": "string",
"created_at": "string",
"updated_at": "string",
"author_id": "string",
"author_name": "string",
"author_avatar": "string",
"is_anonymous": true,
"donation_amount_cents": 0,
"donation_currency": "string",
"like_count": 0,
"liked_by_me": true
}
],
"pagination": {
"limit": 0,
"offset": 0,
"total": 0
}
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Create a comment​

POST
/fundraisers/{fundraiserId}/comments

Creates a comment (or reply) on a fundraiser. The author is derived from the authenticated user. Content must be 2000 characters or less, and is required unless gif_id is set.
gif_id attaches a GIF (#1963): a GIPHY id from GET /gifs/trending or GET /gifs/search. The server looks it up on GIPHY and stores the GIF object it builds itself; clients never send URLs. Only g and pg GIFs are accepted. A request with gif_id also counts against the GIF rate limit (60 a minute per account).
Requires a verified email address, and is gated by the features.comments flag — either gate failing answers 403.

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

fundraiserId*
Type
string
Required
Format
"uuid"

Request Body​

application/json
JSON
{
"content": "string",
"parent_comment_id": "string",
"gif_id": "string"
}

Responses​

Comment created — the stored row (including gif, a GIF object or null) plus author_name and author_avatar.

application/json
JSON
{
"data": {
"additionalProperties": "string"
}
}

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Trending GIFs for the comment GIF picker​

GET
/gifs/trending

GIPHY's trending GIFs, rated pg or lower, as GIF objects. Cached on the server for a few minutes. Page with offset = the previous answer's next_offset.
Authentication is optional. Rate limited at 60 requests a minute per account (per IP for a guest), on top of the public limit.
Answers 503 { "error": "gifs_unavailable" } while GIF comments are off (features.comment_gifs) or GIPHY is not configured. Clients should hide their GIF button when they get it.

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)
or

Parameters​

Query Parameters

limit
Type
integer
Default
24
Minimum
1
Maximum
50
offset
Type
integer
Default
0
Minimum
0
Maximum
4999

Responses​

A page of GIFs

application/json
JSON
"string"

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Search GIFs for the comment GIF picker​

GET
/gifs/search

GIPHY search, rated pg or lower, as GIF objects. Cached on the server by q, offset, limit and lang. Same limits and 503 behaviour as GET /gifs/trending.

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)
or

Parameters​

Query Parameters

q*

The search term. Whitespace is collapsed and it is cut to 50 characters.

Type
string
Required
Min Length
1
limit
Type
integer
Default
24
Minimum
1
Maximum
50
offset
Type
integer
Default
0
Minimum
0
Maximum
4999
lang

The search language. Anything else is treated as en.

Type
string
Valid values
"en""ru""uk""es"
Default
"en"

Responses​

A page of GIFs

application/json
JSON
"string"

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Delete a comment​

DELETE
/comments/{id}

Deletes a comment. Only the comment's author may delete it. A donor's note tied to a gift is retracted (hidden, kept for the record) rather than deleted.

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

id*
Type
string
Required
Format
"uuid"

Responses​

Comment deleted

application/json
JSON
{
"success": true
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Like a comment​

PUT
/comments/{commentId}/like

Likes a comment or a reply as the authenticated user. Idempotent: liking a comment you already like changes nothing and answers the same state. No verified email is required. Gated by the features.comments flag and the per-account rate limit.

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

commentId*
Type
string
Required
Format
"uuid"

Responses​

Liked; the comment's count after the write

application/json
JSON
"string"

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Unlike a comment​

DELETE
/comments/{commentId}/like

Removes the authenticated user's like from a comment or a reply. Idempotent: unliking a comment you do not like changes nothing.

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

commentId*
Type
string
Required
Format
"uuid"

Responses​

Not liked; the comment's count after the write

application/json
JSON
"string"

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get the project updates feed​

GET
/projects/{fundraiserId}/updates

Returns a unified feed of the fundraiser's updates and its withdrawals, newest first — a bare array. A withdrawal row is this campaign's share of a payout that carried its donations (never the payout's whole amount); paid, in-transit and pending payouts are listed. Withdrawn updates are left out. An unreadable feed answers 200 with an empty array rather than an error.
Readable exactly when GET /fundraisers/{id} is: a campaign that is not active, paused or ended, is private, or has been deleted answers 404 to everyone but its owner.
Authentication is optional. Every update item carries like_count; for a signed-in caller liked_by_me says whether they like it, and for a guest it is always false. Withdrawal items carry neither.

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)
or

Parameters​

Path Parameters

fundraiserId*
Type
string
Required

Query Parameters

lang

Overlay update translations into this language, when they exist.

Type
string
Valid values
"en""ru""uk""es"

Responses​

Update feed (items are type "update" or "withdrawal")

application/json
JSON
[
{
"type": "string",
"id": "string",
"created_at": "string",
"title": "string",
"body": "string",
"author": {
"id": "string",
"name": "string",
"avatar": "string"
},
"amount_cents": 0,
"currency": "string",
"status": "string",
"arrival_date": "string",
"like_count": 0,
"liked_by_me": true
}
]

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Post a project update​

POST
/projects/{fundraiserId}/updates

Creates a project update on a fundraiser. Only the fundraiser owner may post, the caller's email must be verified, and the endpoint is gated by the features.project_updates flag. The body field is required (at most 20,000 characters; title at most 200). The update's language is detected and machine translations are queued.

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

fundraiserId*
Type
string
Required

Request Body​

application/json
JSON
{
"title": "string",
"body": "string"
}

Responses​

Update created — a bare object, not wrapped in data.

application/json
JSON
{
"id": "string",
"fundraiser_id": "string",
"author_id": "string",
"title": "string",
"body": "string",
"source_language": "string",
"created_at": "string",
"updated_at": "string",
"type": "string",
"author": {
"id": "string",
"name": "string",
"avatar": "string"
}
}

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Delete a project update​

DELETE
/projects/{fundraiserId}/updates/{updateId}

Soft-deletes a project update. Only the fundraiser owner may delete it.

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

fundraiserId*
Type
string
Required
updateId*
Type
string
Required

Responses​

Update deleted

application/json
JSON
{
"success": true,
"deletedId": "string"
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Edit a project update​

PATCH
/projects/{fundraiserId}/updates/{updateId}

Changes an update's title and/or body. Campaign owner only; the caller's email must be verified, and the endpoint is gated by the features.project_updates flag. Send at least one of title and body; title: null (or blank) removes the title.
When the words change, the update's language is detected again, its machine translations are dropped and re-queued, and hand-made translations are flagged as outdated. A withdrawn update answers 404. Audit-logged.

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

fundraiserId*
Type
string
Required
Format
"uuid"
updateId*
Type
string
Required
Format
"uuid"

Request Body​

application/json
JSON
{
"title": "string",
"body": "string"
}

Responses​

The edited update (bare object)

application/json
JSON
{
"id": "string",
"fundraiser_id": "string",
"author_id": "string",
"title": "string",
"body": "string",
"source_language": "string",
"created_at": "string",
"updated_at": "string",
"type": "string"
}

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Like a project update​

PUT
/projects/{fundraiserId}/updates/{updateId}/like

Likes a campaign update as the authenticated user. Idempotent: liking an update you already like changes nothing and answers the same state. No verified email is required; the per-account rate limit applies.

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

fundraiserId*
Type
string
Required
Format
"uuid"
updateId*
Type
string
Required
Format
"uuid"

Responses​

Liked; the update's count after the write

application/json
JSON
"string"

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Unlike a project update​

DELETE
/projects/{fundraiserId}/updates/{updateId}/like

Removes the authenticated user's like from a campaign update. Idempotent: unliking an update you do not like changes nothing.

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

fundraiserId*
Type
string
Required
Format
"uuid"
updateId*
Type
string
Required
Format
"uuid"

Responses​

Not liked; the update's count after the write

application/json
JSON
"string"

Playground​

Server
Authorization
Variables
Key
Value

Samples​


List project milestones​

GET
/projects/{fundraiserId}/milestones

Returns all milestones for a fundraiser, ordered by due date then creation date — a bare array, unlike GET /fundraisers/{fundraiserId}/milestones, which wraps the same rows in milestones. Readable exactly when GET /fundraisers/{id} is: a campaign that is not active, paused or ended, is private, or has been deleted answers 404 to everyone but its owner. Authentication is optional.

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)
or

Parameters​

Path Parameters

fundraiserId*
Type
string
Required

Query Parameters

lang

Overlay the stored translation of title and description for this language, when one exists.

Type
string
Valid values
"en""ru""uk""es"

Responses​

Milestone list

application/json
JSON
[
]

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get project funding stats​

GET
/projects/{fundraiserId}/stats

Returns allocation, disbursement, and milestone-count stats for a project-type fundraiser. Non-project fundraisers return zeroed stats. Not available yet for project fundraisers: the endpoint currently answers 500 for them. Readable exactly when GET /fundraisers/{id} is: a campaign that is not active, paused or ended, is private, or has been deleted answers 404 to everyone but its owner. Authentication is optional.

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)
or

Parameters​

Path Parameters

fundraiserId*
Type
string
Required

Responses​

Project stats

application/json
JSON
{
"totalAllocated": 0,
"totalDisbursed": 0,
"unallocated": 0,
"milestones": {
"total": 0,
"additionalProperties": 0
}
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


List translations of a campaign's updates​

GET
/fundraisers/{id}/updates/translations

Every live (not withdrawn) update of the campaign, newest first, with its original text and language and one row per other supported locale. Campaign owner only.

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

id*

The campaign's UUID.

Type
string
Required
Format
"uuid"

Responses​

Updates with their translations

application/json
JSON
{
"data": {
"fundraiser_id": "string",
"updates": [
]
}
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get one update's translations​

GET
/fundraisers/{id}/updates/{updateId}/translations

One update of the campaign: its original and its rows in the other three locales. Campaign owner only. A withdrawn update, or one belonging to another campaign, answers 404.

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

id*

The campaign's UUID.

Type
string
Required
Format
"uuid"
updateId*
Type
string
Required
Format
"uuid"

Responses​

The update and its translations

application/json
JSON
{
"data": {
"fundraiser_id": "string",
"update_id": "string",
"id": "string",
"created_at": "string",
"source": {
"language": "string",
"title": "string",
"content": "string",
"edited_at": "string"
},
"translations": [
]
}
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Save a hand-edited update translation​

PUT
/fundraisers/{id}/updates/{updateId}/translations/{lang}

Creates or overwrites an update's translation in lang as source: "human", so no automatic pass overwrites it. Campaign owner only. Audit-logged. Refused in the update's own language. When the update has a title, the translation must carry one too.

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

id*

The campaign's UUID.

Type
string
Required
Format
"uuid"
updateId*
Type
string
Required
Format
"uuid"
lang*
Type
string
Required
Valid values
"en""ru""uk""es"

Request Body​

application/json
JSON
{
"title": "string",
"content": "string"
}

Responses​

The saved row

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

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Regenerate an update translation​

POST
/fundraisers/{id}/updates/{updateId}/translations/{lang}/regenerate

Re-runs machine translation of one update into lang and stores it as source: "machine". A hand-edited row is only replaced with force=1. Campaign owner only. Audit-logged.

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

id*

The campaign's UUID.

Type
string
Required
Format
"uuid"
updateId*
Type
string
Required
Format
"uuid"
lang*
Type
string
Required
Valid values
"en""ru""uk""es"

Query Parameters

force

1 or true overwrites a hand-edited row.

Type
string
Valid values
"1""true"

Responses​

The regenerated row

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

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Track a share event​

POST
/shares

Records a social-share event for a fundraiser or profile. Authentication is optional — the sharing user is recorded when a session is present, otherwise the row is anonymous.

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)
or

Request Body​

application/json
JSON
{
"entity_type": "string",
"entity_id": "string",
"platform": "string"
}

Responses​

Share tracked

application/json
JSON
{
"success": true,
"message": "string"
}

Playground​

Server
Authorization
Body

Samples​


Campaign link-preview image​

GET
/fundraisers/slug/{slug}/og-image

A 1200×630 PNG Open Graph card for the campaign: title, cover, organizer, raised and goal amounts and donor count. Public; served to social crawlers.
Only a campaign anyone may open by link (live, ended or paused; not private; not deleted) has an image. Any other campaign is a 404, the same as an unknown slug, for every caller.
The language comes from ?lang=, else the locale cookie, else Accept-Language, else the original text. Without ?lang= the response varies on Accept-Language, Cookie. Cached for 30 seconds.

Parameters​

Path Parameters

slug*
Type
string
Required

Query Parameters

lang

Language to render in. Without it the locale cookie, then Accept-Language, decide.

Type
string
Valid values
"en""ru""uk""es"

Responses​

PNG image

image/png

Playground​

Server
Variables
Key
Value

Samples​


Campaign square share poster​

GET
/fundraisers/slug/{slug}/share-poster

A 1080×1080 PNG for feed posts (Instagram and similar). Same data, language rules, caching and 404 for a campaign that is not readable by link as the link-preview image.

Parameters​

Path Parameters

slug*
Type
string
Required

Query Parameters

lang

Language to render in. Without it the locale cookie, then Accept-Language, decide.

Type
string
Valid values
"en""ru""uk""es"

Responses​

PNG image

image/png

Playground​

Server
Variables
Key
Value

Samples​


Campaign story card​

GET
/fundraisers/slug/{slug}/share-story

A 1080×1920 PNG for Instagram and Facebook Stories. Same data, language rules, caching and 404 for a campaign that is not readable by link as the link-preview image.

Parameters​

Path Parameters

slug*
Type
string
Required

Query Parameters

lang

Language to render in. Without it the locale cookie, then Accept-Language, decide.

Type
string
Valid values
"en""ru""uk""es"

Responses​

PNG image

image/png

Playground​

Server
Variables
Key
Value

Samples​


Campaign share kit​

GET
/fundraisers/slug/{slug}/share-kit.zip

The link-preview image, the square poster and the story card in one zip download (<slug>-link.png, <slug>-post.png, <slug>-story.png), as linked from the ambassador endorsement-request email. Same language rules, 30-second caching and 404 for a campaign that is not readable by link as the single images. All three must render, or the call answers 404.

Parameters​

Path Parameters

slug*
Type
string
Required

Query Parameters

lang

Language to render in. Without it the locale cookie, then Accept-Language, decide.

Type
string
Valid values
"en""ru""uk""es"

Responses​

Zip archive, sent as an attachment named <slug>-share-kit.zip

application/zip

Playground​

Server
Variables
Key
Value

Samples​


Get a campaign's share impact​

GET
/fundraisers/{id}/share-impact

What sharing has done for this campaign, all-time: human visits that arrived through a shared link, how many came through endorsers' links, and the paid, non-self-referred gifts traced back to a share. Public. A campaign nobody has shared returns zeros. Readable exactly when GET /fundraisers/{id} is: a campaign that is not active, paused or ended, is private, or has been deleted answers 404 to everyone but its owner. Authentication is optional.

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)
or

Parameters​

Path Parameters

id*

The campaign's UUID; anything else answers 400.

Type
string
Required
Format
"uuid"

Responses​

Share impact (bare object)

application/json
JSON
{
"impressions": 0,
"viaEndorsers": 0,
"gifts": 0,
"donors": 0,
"value": 0,
"currencies": [
"string"
]
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get a campaign's shares per channel​

GET
/fundraisers/{id}/share-channels

Human clicks through shared links, and the gifts they led to, per share channel, all-time. Every channel is present, with zeros when none. Public. Readable exactly when GET /fundraisers/{id} is: a campaign that is not active, paused or ended, is private, or has been deleted answers 404 to everyone but its owner. Authentication is optional.

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)
or

Parameters​

Path Parameters

id*

The campaign's UUID; anything else answers 400.

Type
string
Required
Format
"uuid"

Responses​

Per-channel stats (bare object)

application/json
JSON
{
"total": "string",
"channels": {
"additionalProperties": "string"
},
"unattributed": "string"
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Organization Admin​

The org-scoped admin panel at /org-admin/{slug}/*. Every operation needs a bearer session, resolves {slug} to an organization (an unknown or malformed slug answers 404 Organization not found, never 403), and then checks an org-scoped permission held through the caller's org_owner, org_admin or org_viewer role on that organization. A caller without the permission gets 403 with message: "Requires permission: <name>".

Role → permission map: org_viewer holds org.read, org.read_donations, org.read_payouts and org.read_donors. org_admin adds org.update_settings, org.manage_members, org.manage_dbas, org.manage_locations and org.upload_documents. org_owner adds org.manage_children and org.manage_payouts.


Get organization dashboard totals​

GET
/org-admin/{slug}/overview

Headline numbers for the org-admin dashboard. For a conglomerate the figures roll up the organization and all of its child organizations; for a company they cover the organization alone. totalRaisedCents sums every paid donation on those organizations' fundraisers, in integer cents. uniqueDonors counts distinct signed-in donors only — guest donations do not add to it.

Requires permission: org.read

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"

Responses​

Dashboard totals

application/json
JSON
{
"data": {
"activeFundraisers": 0,
"totalFundraisers": 0,
"totalRaisedCents": 4560000,
"uniqueDonors": 0,
"kind": "string",
"childrenCount": 0
}
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


List the organization's fundraisers​

GET
/org-admin/{slug}/fundraisers

Non-deleted fundraisers owned by this organization (not its children), newest first, with offset pagination. Every status is included — drafts, pending review, ended — unless status narrows it. Private contact fields are never returned.

Requires permission: org.read

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"

Query Parameters

status

Only fundraisers with this status. Send one of the listed values.

Type
string
Valid values
"draft""pending""rejected""active""paused""ended"
limit

Clamped to 1..100. Defaults to 20.

Type
integer
Minimum
1
Maximum
100
Default
20
offset
Type
integer
Minimum
0
Default
0

Responses​

Paginated fundraisers

application/json
JSON
{
"data": [
],
"pagination": "string"
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


List donations to the organization's fundraisers​

GET
/org-admin/{slug}/donations

Donations to this organization's non-deleted fundraisers, newest first, with offset pagination. Every payment status is returned unless status narrows it.

Donor privacy: donor_display_name is Anonymous donor when the gift was marked anonymous, the donor's profile name for a signed-in donor, and the checkout name for a guest. Donor email addresses are never returned.

Requires permission: org.read_donations

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"

Query Parameters

status

Only donations with this payment status. Send one of the listed values.

Type
string
Valid values
"paid""pending""failed""refunded"
fundraiser_id

Only donations to this fundraiser. Must be a UUID.

Type
string
Format
"uuid"
limit

Clamped to 1..100. Defaults to 20.

Type
integer
Minimum
1
Maximum
100
Default
20
offset
Type
integer
Minimum
0
Default
0

Responses​

Paginated donations

application/json
JSON
{
"data": [
],
"pagination": "string"
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


List the organization's donors​

GET
/org-admin/{slug}/donors

Distinct donors who made a paid donation to any of this organization's non-deleted fundraisers, with their lifetime totals here, largest first, with offset pagination. All anonymous gifts are collapsed into a single Anonymous donor row (donor_key: anonymous) so they cannot be told apart by amount. Signed-in donors are keyed user:<profile id>; guest donors are keyed guest:<24 hex characters>. Treat donor_key as an opaque identifier: it is stable across pages and requests, but carries no contact details and cannot be turned back into one.

Requires permission: org.read_donors

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"

Query Parameters

limit

Clamped to 1..100. Defaults to 20.

Type
integer
Minimum
1
Maximum
100
Default
20
offset
Type
integer
Minimum
0
Default
0

Responses​

Paginated donor roll-up

application/json
JSON
{
"data": [
],
"pagination": "string"
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Look up an account by email before adding it as a member​

GET
/org-admin/{slug}/users/search

Confirms which FundlyHub account uses an email address, for the Members page's "Add member" form. q must be a complete email address; it is matched case-insensitively against account login emails only, and at most one result comes back, with the address masked. Anything that is not a complete email address (a name, a fragment, a phone number) answers 200 with an empty list. This is not a directory search.

Available only to organizations that are approved or verified; any other organization gets 403 with code: ORG_NOT_APPROVED.

Rate limited to 30 requests per minute per user, in one bucket shared with POST /org-admin/{slug}/members.

Note the bare { "results": [ … ] } envelope rather than data.

Requires permission: org.manage_members

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"

Query Parameters

q*

A complete email address (surrounding whitespace is trimmed). Matched case-insensitively against account login emails.

Type
string
Required
Example"sam@example.org"
Format
"email"
Max Length
254

Responses​

The matching account, or an empty list when no account uses that email or q is not a complete email address.

application/json
JSON
{
"results": [
]
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


List organization members​

GET
/org-admin/{slug}/members

Everyone holding an active, unexpired org-scoped role on this organization, highest role first, then by name. Includes each member's email address, which is why this sits behind the management permission rather than org.read.

Requires permission: org.manage_members

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"

Responses​

Members

application/json
JSON
{
"data": [
]
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Add a member​

POST
/org-admin/{slug}/members

Adds an existing FundlyHub user, found by email (case-insensitive), to the organization with the given role. The membership is active immediately; no invitation is sent and the user does not have to accept. org_owner cannot be granted here — add the user first, then promote them with PATCH /org-admin/{slug}/members/{userId}.

An optional display title can be set with either org_role_title_id (an id from GET /org-role-titles) or custom_role_title, not both.

Available only to organizations that are approved or verified; any other organization gets 403 with code: ORG_NOT_APPROVED.

Rate limited to 30 requests per minute per user, in one bucket shared with GET /org-admin/{slug}/users/search.

Requires permission: org.manage_members

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"

Request Body​

application/json
JSON
{
"email": "string",
"role": "string",
"org_role_title_id": "executive_director",
"custom_role_title": "string"
}

Responses​

Member added

application/json
JSON
{
"data": {
"user_id": "string",
"user_name": "string",
"role_name": "string"
}
}

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Remove a member​

DELETE
/org-admin/{slug}/members/{userId}

Deactivates every org-scoped role the user holds on this organization. Only an org_owner may remove an owner, and nobody may remove a member whose role is equal to or above their own (403). Removing yourself (leaving) is always allowed. The organization's last remaining owner cannot be removed (400) — promote another member to owner first.

Requires permission: org.manage_members

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"
userId*

The member's profile id. A non-UUID answers 404 Member not found.

Type
string
Required
Format
"uuid"

Responses​

Member removed

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Change a member's role​

PATCH
/org-admin/{slug}/members/{userId}

Moves a member to a different org role. Setting the role they already hold is an idempotent no-op that still answers 200.

Roles rank org_owner > org_admin > org_viewer. Rules enforced, each a 403 when broken:

  • only an org_owner may promote anyone to org_owner, or change the role of another owner;
  • nobody may change the role of a member whose role is equal to or above their own (an
    org_admin manages org_viewers, not other admins);
  • nobody may grant a role above their own.

Lowering your own role (stepping down) is always allowed. The organization's last remaining owner cannot be demoted (400) — promote another member to owner first.

Requires permission: org.manage_members

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"
userId*

The member's profile id. A non-UUID answers 404 Member not found.

Type
string
Required
Format
"uuid"

Request Body​

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

Responses​

Role updated (or already held)

application/json
JSON
{
"data": {
"user_id": "string",
"role_name": "string"
}
}

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Update organization settings​

PATCH
/org-admin/{slug}/settings

Partial update of the organization's profile. Only the fields below are writable; others are ignored. String fields accept a string or null and are trimmed. At least one writable field must be present.

logo and banner_image take a URL as-is; to upload an image use POST /org-admin/{slug}/avatar or /banner instead.

Requires permission: org.update_settings

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"

Request Body​

application/json
JSON
{
"legal_name": "string",
"website": "string",
"description": "string",
"country": "string",
"logo": "string",
"banner_image": "string",
"mission": "string",
"contact_email": "string",
"contact_email_public": true,
"founded_year": 0,
"social_links": {
"twitter": "string",
"linkedin": "string",
"facebook": "string",
"instagram": "string",
"youtube": "string",
"tiktok": "string"
}
}

Responses​

Updated settings

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

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Upload organization logo​

POST
/org-admin/{slug}/avatar

Uploads a new logo as base64 JSON. The image is centre-cropped to 256×256, re-encoded as WebP, stored, and written to the organization's logo straight away — no separate settings save is needed. Any previous logo file is deleted. Maximum 5 MB decoded.

Note the bare response body (no data envelope).

Requires permission: org.update_settings

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"

Request Body​

application/json
JSON
"string"

Responses​

Logo uploaded

application/json
JSON
{
"success": true,
"avatar_url": "string"
}

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Remove organization logo​

DELETE
/org-admin/{slug}/avatar

Deletes the stored logo files and clears the organization's logo.

Requires permission: org.update_settings

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"

Responses​

Logo removed

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Post an organization update​

POST
/org-admin/{slug}/updates

Publishes a post to the organization's public updates feed (GET /organizations/{id}/updates). The caller is recorded as the author.

Requires permission: org.update_settings

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"

Request Body​

application/json
JSON
{
"title": "string",
"body": "string",
"cover_image": "string"
}

Responses​

Update posted

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

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Delete an organization update​

DELETE
/org-admin/{slug}/updates/{updateId}

Permanently deletes one of this organization's updates. A malformed updateId answers 500 rather than 404.

Requires permission: org.update_settings

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"
updateId*
Type
string
Required
Format
"uuid"

Responses​

Update deleted

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Edit an organization update​

PATCH
/org-admin/{slug}/updates/{updateId}

Partial edit of one of this organization's updates. Send at least one of title, body, cover_image.

Requires permission: org.update_settings

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"
updateId*
Type
string
Required
Format
"uuid"

Request Body​

application/json
JSON
{
"title": "string",
"body": "string",
"cover_image": "string"
}

Responses​

Update edited

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

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Upload organization banner​

POST
/org-admin/{slug}/banner

Uploads the public-profile banner as base64 JSON. The image is centre-cropped to 1500×500 (3:1), re-encoded as WebP, stored, and written to the organization's banner_image straight away. Any previous banner file is deleted. Maximum 8 MB decoded.

Note the bare response body (no data envelope).

Requires permission: org.update_settings

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"

Request Body​

application/json
JSON
"string"

Responses​

Banner uploaded

application/json
JSON
{
"success": true,
"banner_url": "string"
}

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Remove organization banner​

DELETE
/org-admin/{slug}/banner

Deletes the stored banner files and clears the organization's banner_image.

Requires permission: org.update_settings

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"

Responses​

Banner removed

Playground​

Server
Authorization
Variables
Key
Value

Samples​


List DBAs​

GET
/org-admin/{slug}/dbas

The organization's "doing business as" names, default first, then alphabetical.

Requires permission: org.read

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"

Responses​

DBAs

application/json
JSON
{
"data": [
]
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Add a DBA​

POST
/org-admin/{slug}/dbas

Adds a DBA name. With is_default: true it becomes the default and the previous default is cleared in the same transaction.

Requires permission: org.manage_dbas

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"

Request Body​

application/json
JSON
{
"dba_name": "string",
"is_default": false
}

Responses​

DBA added

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

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Delete a DBA​

DELETE
/org-admin/{slug}/dbas/{dbaId}

Permanently deletes a DBA. Deleting the default leaves the organization with no default DBA.

Requires permission: org.manage_dbas

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"
dbaId*

A non-UUID answers 404 DBA not found.

Type
string
Required
Format
"uuid"

Responses​

DBA deleted

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Update a DBA​

PATCH
/org-admin/{slug}/dbas/{dbaId}

Renames a DBA and/or changes whether it is the default. Setting is_default: true clears the previous default in the same transaction.

Requires permission: org.manage_dbas

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"
dbaId*

A non-UUID answers 404 DBA not found.

Type
string
Required
Format
"uuid"

Request Body​

application/json
JSON
{
"dba_name": "string",
"is_default": true
}

Responses​

DBA updated

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

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


List office locations​

GET
/org-admin/{slug}/locations

The organization's physical locations, primary first, then oldest first. Includes locations not shown publicly.

Requires permission: org.read

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"

Responses​

Locations

application/json
JSON
{
"data": [
]
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Add an office location​

POST
/org-admin/{slug}/locations

Adds a location. With is_primary: true it becomes the primary location and the previous primary is cleared in the same transaction. Locations are hidden from the public profile unless is_publicly_visible is true.

Requires permission: org.manage_locations

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"

Request Body​

application/json
JSON
{
"label": "Headquarters",
"address": "string",
"is_primary": false,
"is_publicly_visible": false
}

Responses​

Location added

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

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Delete an office location​

DELETE
/org-admin/{slug}/locations/{locationId}

Permanently deletes a location. Deleting the primary leaves the organization with no primary location.

Requires permission: org.manage_locations

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"
locationId*

A non-UUID answers 404 Location not found.

Type
string
Required
Format
"uuid"

Responses​

Location deleted

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Update an office location​

PATCH
/org-admin/{slug}/locations/{locationId}

Partial update of a location. address, when sent, replaces the whole address object. Setting is_primary: true clears the previous primary in the same transaction.

Requires permission: org.manage_locations

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"
locationId*

A non-UUID answers 404 Location not found.

Type
string
Required
Format
"uuid"

Request Body​

application/json
JSON
{
"label": "string",
"address": "string",
"is_primary": true,
"is_publicly_visible": true
}

Responses​

Location updated

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

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Start or resume Stripe Connect onboarding​

POST
/org-admin/{slug}/payouts/connect

Creates the organization's Stripe Express account (business type company) if it has none, or reuses the existing one, and returns a fresh single-use onboarding link. Safe to call repeatedly — each call returns a new link. If the stored account no longer exists on Stripe a new one is created in its place.

The organization must have verification_status: verified, and the features.org_level_stripe_connect flag must be on (503 otherwise).

Requires permission: org.manage_payouts (organization owners only)

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"

Responses​

Onboarding link created

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

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get Stripe Connect status​

GET
/org-admin/{slug}/payouts/status

Whether the organization can take charges and receive payouts. Reads the account live from Stripe and refreshes the stored flags. If Stripe cannot be reached, the last stored flags are returned instead and the Stripe-only fields (defaultCurrency, country, businessType, requirementsCurrentlyDue) are absent. With no account yet the body is { "data": { "connected": false } }.

Requires permission: org.read_payouts

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"

Responses​

Connect status

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

Playground​

Server
Authorization
Variables
Key
Value

Samples​


List child organizations​

GET
/org-admin/{slug}/children

Organizations whose parent is this one, newest first. Always empty for a company; only a conglomerate has children.

Requires permission: org.read

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"

Responses​

Child organizations

application/json
JSON
{
"data": [
]
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Create a child organization​

POST
/org-admin/{slug}/children

Creates a new company under this conglomerate. Validation is the same as POST /organizations, except that the new organization is always a company (kind is ignored once it passes validation) and sending parent_organization_id in the body is rejected — the parent is always the {slug} organization. The caller becomes org_owner of the child. The child starts with verification_status: pending; the first DBA becomes its default and the first location its primary.

Requires a verified email address.

Requires permission: org.manage_children (organization owners only)

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"

Request Body​

application/json
JSON
{
"legal_name": "string",
"ein": "12-3456789",
"country": "string",
"website": "string",
"description": "string",
"categories": [
"string"
],
"dbas": [
{
"dba_name": "string"
}
],
"locations": [
{
"label": "string",
"address": "string"
}
]
}

Responses​

Child organization created

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

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


List verification documents​

GET
/org-admin/{slug}/documents

The organization's verification documents in every state except superseded, newest first, including review outcome and whether each is shown on the public profile.

Financial documents — w9, voided_check and other — are listed only when the caller also holds org.upload_documents; otherwise they are left out of the list. ein_letter and 501c3_determination are listed with org.read alone.

Requires permission: org.read

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"

Responses​

Documents

application/json
JSON
{
"data": [
]
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Upload a verification document​

POST
/org-admin/{slug}/documents

Uploads a document for platform review as base64 JSON. It is stored privately and enters the review queue as pending. Uploading a doc_type the organization already has pending or approved marks the older one superseded. Approval of both ein_letter and 501c3_determination is what verifies the organization.

Size limit: 10 MB decoded by default, but the JSON body itself is capped at 10 MB, so in practice a file must stay under about 7.5 MB to fit once base64-encoded — larger bodies get 413 before the handler runs.

Requires permission: org.upload_documents

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"

Request Body​

application/json
JSON
{
"doc_type": "string",
"content_type": "string",
"original_filename": "string",
"file_base64": "string"
}

Responses​

Document uploaded

application/json
JSON
{
"data": {
"id": "string",
"org_id": "string",
"doc_type": "string",
"original_filename": "string",
"content_type": "string",
"size_bytes": 0,
"verification_status": "pending",
"uploaded_by_user_id": "string",
"created_at": "string",
"updated_at": "string"
}
}

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Download a verification document​

GET
/org-admin/{slug}/documents/{docId}/download

Streams the stored file with its original Content-Type and, when a filename was recorded, Content-Disposition: attachment. A document belonging to a different organization answers 404.

A w9, voided_check or other document can be downloaded only by a caller who also holds org.upload_documents; anyone else gets 404, as if it did not exist.

Requires permission: org.read

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"
docId*

A non-UUID answers 404 Document not found.

Type
string
Required
Format
"uuid"

Responses​

The file

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Delete a pending verification document​

DELETE
/org-admin/{slug}/documents/{docId}

Withdraws a document that is still pending. Approved and rejected documents are kept for the audit trail and cannot be deleted — they answer 404 like a missing document.

Requires permission: org.upload_documents

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"
docId*

A non-UUID answers 404 Document not found.

Type
string
Required
Format
"uuid"

Responses​

Document deleted

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Show or hide a document on the public profile​

PATCH
/org-admin/{slug}/documents/{docId}/public-visibility

Sets the document's public-visibility flag. The public profile (GET /organizations/{id}/documents/public) lists a document only when it is both flagged public and approved, so the flag can be set ahead of review.

Requires permission: org.upload_documents

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

slug*

The organization's slug (not its UUID).

Type
string
Required
Example"local-food-bank-a1b2c3"
Pattern
"^[a-z0-9][a-z0-9-]{0,254}$"
docId*

A non-UUID answers 404 Document not found.

Type
string
Required
Format
"uuid"

Request Body​

application/json
JSON
{
"is_publicly_visible": true
}

Responses​

Visibility updated

application/json
JSON
{
"data": {
"id": "string",
"is_publicly_visible": true
}
}

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Translations​


List a campaign's translations​

GET
/fundraisers/{id}/translations

The Translations tab's data for one campaign: its source text and language, one row per other supported locale (fields null and source: null where nothing has been translated yet), the row in the campaign's own language if one exists (original_row), and every milestone with its rows.
Only the campaign's owner may read it.

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

id*

The campaign's UUID.

Type
string
Required
Format
"uuid"

Responses​

Source text and per-locale translations

application/json
JSON
{
"data": {
"fundraiser_id": "string",
"source": {
"language": "string",
"title": "string",
"summary": "string",
"story_html": "string"
},
"translations": [
],
"original_row": {
"language": "string",
"title": "string",
"summary": "string",
"story_html": "string",
"source": "string",
"translated_at": "string"
},
"milestones": [
]
}
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Save a hand-edited campaign translation​

PUT
/fundraisers/{id}/translations/{lang}

Creates or overwrites the campaign's translation in lang with a hand-edited version and marks it source: "human", so automatic re-translation leaves it alone. Campaign owner only. Audit-logged.
lang may not be the campaign's stored source language; that text is edited on the campaign itself.

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

id*

The campaign's UUID.

Type
string
Required
Format
"uuid"
lang*
Type
string
Required
Valid values
"en""ru""uk""es"

Request Body​

application/json
JSON
{
"title": "string",
"summary": "string",
"story_html": "string"
}

Responses​

The saved row

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

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Discard a hand-edited version in the campaign's own language​

DELETE
/fundraisers/{id}/translations/{lang}

Deletes the hand-edited (source: "human") rows in the campaign's OWN language, both the campaign's row and its milestones' rows. Such a version exists when someone edited that language while the campaign was labelled with another one; readers of that language are served it instead of the original until it is discarded. Machine rows for fields written in another language are rebuilt in the background afterwards.
Only works for lang equal to the campaign's stored source language; a translation into another language is replaced with regenerate instead. Campaign owner only. The discarded text is written to the audit log.

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

id*

The campaign's UUID.

Type
string
Required
Format
"uuid"
lang*
Type
string
Required
Valid values
"en""ru""uk""es"

Responses​

What was discarded

application/json
JSON
{
"data": {
"language": "string",
"discarded": {
"campaign": 0,
"milestones": 0
}
}
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Regenerate a campaign translation​

POST
/fundraisers/{id}/translations/{lang}/regenerate

Re-runs machine translation of the campaign into lang and stores it as source: "machine". The locale's milestone rows are refreshed the same way. Campaign owner only. Audit-logged.
A hand-edited row is not overwritten unless force=1 (or true) is passed; without it the call answers 409. It also answers 409 when the campaign text or the row changed while the translation was being generated.

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

id*

The campaign's UUID.

Type
string
Required
Format
"uuid"
lang*
Type
string
Required
Valid values
"en""ru""uk""es"

Query Parameters

force

1 or true overwrites a hand-edited row.

Type
string
Valid values
"1""true"

Responses​

The regenerated row

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

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Save a hand-edited milestone translation​

PUT
/fundraisers/{id}/milestones/{milestoneId}/translations/{lang}

Creates or overwrites one milestone's translation in lang as source: "human". The milestone must belong to the campaign in the path. Campaign owner only. Audit-logged. lang may not be the campaign's source language.

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

id*

The campaign's UUID.

Type
string
Required
Format
"uuid"
milestoneId*
Type
string
Required
Format
"uuid"
lang*
Type
string
Required
Valid values
"en""ru""uk""es"

Request Body​

application/json
JSON
{
"title": "string",
"description": "string"
}

Responses​

The saved row

application/json
JSON
{
"data": {
"milestone_id": "string",
"language": "string",
"title": "string",
"description": "string",
"source": "string",
"translated_at": "string"
}
}

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


List translations of a campaign's updates​

GET
/fundraisers/{id}/updates/translations

Every live (not withdrawn) update of the campaign, newest first, with its original text and language and one row per other supported locale. Campaign owner only.

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

id*

The campaign's UUID.

Type
string
Required
Format
"uuid"

Responses​

Updates with their translations

application/json
JSON
{
"data": {
"fundraiser_id": "string",
"updates": [
]
}
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get one update's translations​

GET
/fundraisers/{id}/updates/{updateId}/translations

One update of the campaign: its original and its rows in the other three locales. Campaign owner only. A withdrawn update, or one belonging to another campaign, answers 404.

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

id*

The campaign's UUID.

Type
string
Required
Format
"uuid"
updateId*
Type
string
Required
Format
"uuid"

Responses​

The update and its translations

application/json
JSON
{
"data": {
"fundraiser_id": "string",
"update_id": "string",
"id": "string",
"created_at": "string",
"source": {
"language": "string",
"title": "string",
"content": "string",
"edited_at": "string"
},
"translations": [
]
}
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Save a hand-edited update translation​

PUT
/fundraisers/{id}/updates/{updateId}/translations/{lang}

Creates or overwrites an update's translation in lang as source: "human", so no automatic pass overwrites it. Campaign owner only. Audit-logged. Refused in the update's own language. When the update has a title, the translation must carry one too.

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

id*

The campaign's UUID.

Type
string
Required
Format
"uuid"
updateId*
Type
string
Required
Format
"uuid"
lang*
Type
string
Required
Valid values
"en""ru""uk""es"

Request Body​

application/json
JSON
{
"title": "string",
"content": "string"
}

Responses​

The saved row

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

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Regenerate an update translation​

POST
/fundraisers/{id}/updates/{updateId}/translations/{lang}/regenerate

Re-runs machine translation of one update into lang and stores it as source: "machine". A hand-edited row is only replaced with force=1. Campaign owner only. Audit-logged.

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

id*

The campaign's UUID.

Type
string
Required
Format
"uuid"
updateId*
Type
string
Required
Format
"uuid"
lang*
Type
string
Required
Valid values
"en""ru""uk""es"

Query Parameters

force

1 or true overwrites a hand-edited row.

Type
string
Valid values
"1""true"

Responses​

The regenerated row

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

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Deprecated

List a legacy update's translations​

GET
/updates/{updateId}/translations

Legacy. Campaign updates are translated through GET /fundraisers/{id}/updates/{updateId}/translations; use that instead.
Returns the update's source text and one row per other locale. The caller must own the parent campaign.

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

updateId*
Type
string
Required
Format
"uuid"

Responses​

Source and translations

application/json
JSON
{
"data": {
"update_id": "string",
"fundraiser_id": "string",
"source": {
"language": "string",
"title": "string",
"content": "string"
},
"translations": [
]
}
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Deprecated

Save a legacy update translation​

PUT
/updates/{updateId}/translations/{lang}

Legacy (see GET /updates/{updateId}/translations). Saves a hand-edited translation as source: "human". Owner of the parent campaign only. Audit-logged.

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

updateId*
Type
string
Required
Format
"uuid"
lang*
Type
string
Required
Valid values
"en""ru""uk""es"

Request Body​

application/json
JSON
{
"title": "string",
"content": "string"
}

Responses​

The saved row

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

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Endorsements​

Ambassadors publicly vouching for other people's campaigns, and creators asking ambassadors to promote theirs.


List a campaign's endorsers​

GET
/fundraisers/{id}/endorsements

Who stands behind a campaign: everyone who endorsed it, plus everyone whose share link for it recorded a visit, minus the organizer and profiles set to private. Ordered by impressions (human visits through their link). Authentication is optional; with a session, viewerHasEndorsed says whether the caller is on the list. A deleted campaign returns an empty list.

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)
or

Parameters​

Path Parameters

id*

The campaign's UUID; anything else answers 400.

Type
string
Required
Format
"uuid"

Responses​

Endorsers (unwrapped)

application/json
JSON
{
"endorsers": [
],
"viewerHasEndorsed": true
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Endorse a campaign​

POST
/fundraisers/{id}/endorse

Publicly vouches for a campaign as the signed-in user, with an optional note. Idempotent: endorsing again updates the note and answers 200 with created: false; a new endorsement answers 201 and notifies the campaign owner.
Only public campaigns that are active, paused or ended can be endorsed, and not your own.
Requires permission: endorse_campaigns

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

id*

The campaign's UUID; anything else answers 400.

Type
string
Required
Format
"uuid"

Request Body​

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

Responses​

Existing endorsement updated

application/json
JSON
"string"

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Withdraw an endorsement​

DELETE
/fundraisers/{id}/endorse

Revokes the caller's live endorsement of the campaign and notifies the owner.
Requires permission: endorse_campaigns

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

id*

The campaign's UUID; anything else answers 400.

Type
string
Required
Format
"uuid"

Responses​

Revoked

application/json
JSON
{
"revoked": true
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


List a campaign's endorsement requests​

GET
/fundraisers/{id}/endorsement-requests

Who the owner has asked to promote the campaign, newest first, and whether each has been emailed yet. Campaign owner only.

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

id*

The campaign's UUID; anything else answers 400.

Type
string
Required
Format
"uuid"

Responses​

Requests (unwrapped)

application/json
JSON
{
"requests": [
]
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Ask ambassadors to promote a campaign​

POST
/fundraisers/{id}/endorsement-requests

Asks up to 12 ambassadors at once to promote the caller's campaign. Campaign owner only; no special permission is needed. Requires a verified email address.
Ids that are not current ambassadors (and the caller's own id) are dropped and listed in rejected. When the campaign is public and active, the ambassadors are emailed now (status: "sent"); otherwise the requests are queued and sent when the campaign is approved (status: "queued"). Asking the same ambassador again refreshes the request rather than duplicating it.

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

id*

The campaign's UUID; anything else answers 400.

Type
string
Required
Format
"uuid"

Request Body​

application/json
JSON
{
"ambassadorIds": [
"string"
]
}

Responses​

Requests recorded

application/json
JSON
{
"requests": [
],
"notified": 0,
"queued": 0,
"rejected": [
"string"
],
"status": "string"
}

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Images​

Stock-photo search, AI cover generation and server-side image copying for the campaign builder, plus an allowlisted image proxy.


Proxy an allowlisted image​

GET
/images/proxy

Streams an image from the platform's CDN or images.unsplash.com, for local development. Public. The upstream body and Content-Type are passed through with a 24-hour cache header; the upstream status code is not, so an upstream error page also arrives as 200.

Parameters​

Query Parameters

url*
Type
string
Required
Format
"uri"

Responses​

The upstream image

image/*

Playground​

Server
Variables
Key
Value

Samples​


Which image features are available​

GET
/images/features

Whether stock-photo search and AI image generation are configured on this deployment. Public.

Responses​

Feature availability

application/json
JSON
{
"stockPhotos": true,
"aiGeneration": true
}

Playground​

Samples​


Search stock photos​

GET
/images/search

Searches Unsplash for landscape photos. Requires a bearer session. When a photo is chosen, call POST /images/track-download with its downloadLocation, as Unsplash's terms require.

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

q*
Type
string
Required
page
Type
integer
Minimum
1
Default
1
per_page
Type
integer
Minimum
1
Maximum
30
Default
20

Responses​

Search results

application/json
JSON
{
"results": [
],
"total": 0,
"totalPages": 0,
"page": 0
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Generate a cover image with AI​

POST
/images/generate

Generates a landscape campaign cover from a prompt (the first 500 characters are used, wrapped in a fixed style prompt). Requires a bearer session.
With the default gpt-image-* model the image is stored on the platform CDN immediately and persisted is true; that path is also gated by features.image_uploads and answers 403 when the flag is off. With a dall-e-* model the URL is OpenAI's temporary one (persisted: false) and should be copied with POST /images/save-from-url.
Limited to 10 generations an hour and 30 a day per user; past either limit the answer is 429 with Retry-After. Errors from the image provider are not passed through: a prompt the provider refuses answers 400, a temporarily unavailable provider 503, and any other provider failure 502, each with a generic message.

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
{
"prompt": "string"
}

Responses​

Generated image

application/json
JSON
{
"url": "string",
"revisedPrompt": "string",
"persisted": true
}

Playground​

Server
Authorization
Body

Samples​


Make a photo square with AI​

POST
/images/fit-square

Re-renders a photo as a square without cutting anyone out of it: the people and the setting are kept and the rest of the frame is composed to fill the square. A photo that is already square is rendered again, so calling twice gives a second rendering. Requires a bearer session.
The square comes back as base64 and nothing is stored. Upload it through the normal image upload to use it as a cover.
Shares the limits of POST /images/generate: 10 an hour and 30 a day per user; past either limit the answer is 429 with Retry-After. Errors from the image provider are not passed through: a photo the provider refuses answers 400, a temporarily unavailable provider 503, and any other provider failure 502, each with a generic message.

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
{
"imageBase64": "string"
}

Responses​

The square photo

application/json
JSON
{
"imageBase64": "string",
"contentType": "image/png",
"changed": true
}

Playground​

Server
Authorization
Body

Samples​


Record a stock-photo selection​

POST
/images/track-download

Tells Unsplash a photo was chosen, as its API guidelines require. Pass the downloadLocation from GET /images/search. Never fails the caller's action: a failed ping answers 200 with tracked: false. Requires a bearer session.

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
{
"downloadLocation": "string"
}

Responses​

Tracking outcome

application/json
JSON
{
"tracked": true
}

Playground​

Server
Authorization
Body

Samples​


Copy a generated image to the CDN​

POST
/images/save-from-url

Downloads an AI-generated image from OpenAI's image storage and stores it on the platform CDN, returning the permanent URL. A URL already on the platform CDN is returned unchanged. Requires a bearer session and the features.image_uploads flag.

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
{
"url": "string",
"bucket": "fundraiser-images"
}

Responses​

Stored image

application/json
JSON
{
"success": true,
"url": "string",
"fileName": "string"
}

Playground​

Server
Authorization
Body

Samples​


List a campaign's media​

GET
/fundraisers/{id}/media

The campaign's photos and videos in gallery order. Every reader sees the public list (DMCA-taken-down items removed); the owner also sees processing and taken-down items. Answers 403 for everyone while features.fundraiser_video is off. Readable exactly when GET /fundraisers/{id} is: a campaign that is not active, paused or ended, is private, or has been deleted answers 404 to everyone but its owner.

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)
or

Parameters​

Path Parameters

id*
Type
string
Required
Format
"uuid"

Responses​

Media items

application/json
JSON
{
"media": [
]
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Add media to a campaign​

POST
/fundraisers/{id}/media

Adds one item, by kind:

  • image — a URL from POST /storage/upload (other hosts are
    rejected). The first image becomes the cover unless isCover says
    otherwise. At most 10 images per campaign.
  • video_link — a YouTube, Vimeo, Wistia, Loom, Instagram, Facebook
    or TikTok URL. At most 3 videos per campaign.
  • video_upload — reserves a direct upload to the video host and
    returns its one-time uploadURL. Counts toward the 3 videos.

Campaign owner only. Behind features.fundraiser_video and the media-upload rate limit (30 per 15 minutes). Audit-logged.

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

id*
Type
string
Required
Format
"uuid"

Request Body​

application/json
JSON
{
"kind": "string",
"url": "string",
"position": 0,
"isCover": true,
"title": "string"
}

Responses​

Item created

application/json
JSON
{
"media": "string",
"uploadURL": "string"
}

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Preview a video link​

POST
/fundraisers/{id}/media/preview

Parses a video URL and returns what the gallery would embed, for the builder's preview card. Nothing is saved. Thumbnail and title come from the provider's oEmbed and may be null. Campaign owner only; behind features.fundraiser_video.

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)

Path Parameters

id*
Type
string
Required
Format
"uuid"
application/json
JSON
{
"url": "string"
}

Parsed link

application/json
JSON
{
"provider": "string",
"providerVideoId": "string",
"embedUrl": "string",
"aspectRatio": "string",
"thumbnailUrl": "string",
"title": "string"
}
Server
Authorization
Variables
Key
Value
Body

Reorder a campaign's media​

PATCH
/fundraisers/{id}/media/reorder

Sets the gallery order to the order of ids. Every id must belong to this campaign. Campaign owner only; behind features.fundraiser_video. Audit-logged.

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

id*
Type
string
Required
Format
"uuid"

Request Body​

application/json
JSON
{
"ids": [
"string"
]
}

Responses​

Reordered

application/json
JSON
{
"ok": true
}

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Set the cover image​

PATCH
/fundraisers/{id}/media/{mid}/cover

Makes one image the campaign's cover (clearing the previous one). Only images can be the cover. Campaign owner only; behind features.fundraiser_video. Audit-logged.

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

id*
Type
string
Required
Format
"uuid"
mid*
Type
string
Required
Format
"uuid"

Responses​

The new cover

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

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Remove a media item​

DELETE
/fundraisers/{id}/media/{mid}

Removes one item from the gallery. Campaign owner only; behind features.fundraiser_video. Audit-logged.

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

id*
Type
string
Required
Format
"uuid"
mid*
Type
string
Required
Format
"uuid"

Responses​

Removed

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get the badge catalogue​

GET
/achievements

Every badge on the platform with its copy, tier ladder, holder counts and rarity, plus header totals, series and the grid's slots, in the reader's language (?lang=, then Accept-Language, then the i18next cookie). The payload is the same for every reader; a token is accepted and ignored. Cached per language.

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)
or

Parameters​

Query Parameters

lang

Reader language; falls back to Accept-Language, then the i18next cookie, then English.

Type
string
Valid values
"en""ru""uk""es"

Responses​

Catalogue (bare object)

application/json
JSON
{
"items": [
],
"totals": {
"achievements": 0,
"earned_total": 0,
"collectors": 0,
"rarest": {
"slug": "string",
"title": "string",
"key": "string",
"label": "string",
"holders": 0
},
"computed_at": "string"
},
"language": "string",
"vocabulary": "string",
"series": [
{
"additionalProperties": "string"
}
],
"slots": [
{
"series_id": "string",
"series_number": 0,
"state": "string",
"slug": "string",
"track": "string"
}
],
"default_series_id": "string"
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get an achievement art sheet image​

GET
/achievements/art-sheets/{id}

The image of one badge art sheet, served immutably (one year) under its version token ?v=. A request without the current token is redirected (302, uncached) to the current versioned URL. Public.

Parameters​

Path Parameters

id*
Type
string
Required
Format
"uuid"

Query Parameters

size

Anything else is the full sheet.

Type
string
Valid values
"full""small""cutout""cutout_small"
Default
"full"
v

Version token. Cut-out sizes append -c.

Type
string

Responses​

The image (its stored content type)

image/*

Playground​

Server
Variables
Key
Value

Samples​


Get an achievement library image​

GET
/achievements/art-images/{id}

One image from the badge art library, served immutably under its version token ?v=; a request without the current token is redirected (302) to it. Public.

Parameters​

Path Parameters

id*
Type
string
Required

Query Parameters

size
Type
string
Valid values
"full""small"
Default
"full"
v
Type
string

Responses​

The image (its stored content type)

image/*

Playground​

Server
Variables
Key
Value

Samples​


Get the achievement vocabulary​

GET
/achievements/vocabulary

The labels and colours every badge card is drawn with (tiers, tracks, rarity frames and so on), in the reader's language. Public.

Parameters​

Query Parameters

lang

Reader language; falls back to Accept-Language, then the i18next cookie, then English.

Type
string
Valid values
"en""ru""uk""es"

Responses​

Vocabulary

application/json
JSON
{
"vocabulary": "string",
"language": "string"
}

Playground​

Server
Variables
Key
Value

Samples​


Get the "just earned" feed​

GET
/achievements/feed

The most recent cards issued or upgraded, platform-wide or for one badge (species). The size, maximum age and suggested refresh interval come from platform settings. An unknown, hidden or private badge answers an empty list. Public; sent with Cache-Control: no-store.

Parameters​

Query Parameters

species

A badge slug. Repeating the parameter answers an empty list.

Type
string
lang

Reader language; falls back to Accept-Language, then the i18next cookie, then English.

Type
string
Valid values
"en""ru""uk""es"

Responses​

Feed

application/json
JSON
{
"data": [
],
"refresh_seconds": 0
}

Playground​

Server
Variables
Key
Value

Samples​


Get one badge​

GET
/achievements/{slug}

One badge with its copy, ladder and rarity. Authentication is optional: a signed-in reader also gets their own standing (earned, tier, progress). With holder_type and holder_id, the badge is answered for that holder instead (a profile's or organization's badge); both must be given together.

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)
or

Parameters​

Path Parameters

slug*
Type
string
Required

Query Parameters

holder_type
Type
string
Valid values
"user""organization"
holder_id
Type
string
Format
"uuid"
lang

Reader language; falls back to Accept-Language, then the i18next cookie, then English.

Type
string
Valid values
"en""ru""uk""es"

Responses​

The badge

application/json
JSON
{
"data": "string",
"vocabulary": "string"
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get a badge share picture​

GET
/achievements/{slug}/share/{asset}

A PNG of the badge for sharing: og 1200×630, post 1080×1080, story and reel 1080×1920. A trailing .png on asset is accepted. ?tier= draws it at that tier when the tier exists. Drafts and private badges answer 404. Public; cached for 5 minutes.

Parameters​

Path Parameters

slug*
Type
string
Required
asset*
Type
string
Required
Valid values
"og""post""story""reel""og.png""post.png""story.png""reel.png"

Query Parameters

tier
Type
string
lang

Reader language; falls back to Accept-Language, then the i18next cookie, then English.

Type
string
Valid values
"en""ru""uk""es"

Responses​

PNG image

image/png

Playground​

Server
Variables
Key
Value

Samples​


Get an earned card​

GET
/cards/{code}

One earned card by its short code, as the card's public page shows it: the badge, holder, tier, dates, serial, evidence, ladder, rarity, the verify URL and share links. Authentication is optional; the holder's own session adds an owner block. Sent private, no-store.

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)
or

Parameters​

Path Parameters

code*

The card's short code.

Type
string
Required

Query Parameters

lang

Reader language; falls back to Accept-Language, then the i18next cookie, then English.

Type
string
Valid values
"en""ru""uk""es"

Responses​

The card

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

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get an earned card's share picture​

GET
/cards/{code}/share/{asset}

A PNG of one earned card: og 1200×630, post 1080×1080, story 1080×1920 (a trailing .png is accepted). Served only when the card is readable by a stranger. When the card's own picture is not rendered yet, the badge's generic picture is served with X-Card-Render: pending and no-store. Supports If-None-Match (304). Public; a per-IP limit (120 per minute by default) applies in addition to the public browsing limit.

Parameters​

Path Parameters

code*

The card's short code.

Type
string
Required
asset*
Type
string
Required
Valid values
"og""post""story""og.png""post.png""story.png"

Query Parameters

lang
Type
string

Responses​

PNG image. Content-Language names the language it was drawn in.

image/png

Playground​

Server
Variables
Key
Value

Samples​


Get an earned card's verify QR code​

GET
/cards/{code}/qr.svg

An SVG QR code pointing at the card's verify URL. Only for cards readable by a stranger. Public; same per-IP limit as the share pictures. Cached for 60 seconds.

Parameters​

Path Parameters

code*

The card's short code.

Type
string
Required

Responses​

SVG image

image/svg+xml
JSON
"string"

Playground​

Server
Variables
Key
Value

Samples​


Get a profile's achievements​

GET
/users/{id}/achievements

The achievements section of a profile: the badges the person has earned that visitors may see, each with its card, plus a public holder block, a summary counted over the returned rows, the profile's pinned card and the label vocabulary. id is a UUID or a profile slug.

The answer is the same for everyone, the owner included, except that the owner's own rows carry their counts (stats). A private or inactive profile read by anyone but its owner answers { "data": [], "withheld": true, "vocabulary": … }.

Authentication is optional. Rate limited at 300 requests/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)
or

Parameters​

Path Parameters

id*

Profile UUID or profile slug.

Type
string
Required

Query Parameters

lang

Locale for titles and labels; unsupported locales fall back to English.

Type
string

Responses​

The collection, or a withheld answer

application/json
JSON
{
"data": [
],
"withheld": true,
"holder": "string",
"summary": {
"additionalProperties": "string"
},
"pin": "string",
"vocabulary": "string"
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get my achievements​

GET
/me/achievements

The owner view: every achievement the caller holds — themselves and through organizations they administer — including those set to "only me", with private stats and progress; next_up, the closest badges not yet earned; the caller's pin; and how many new cards are waiting to be revealed.

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

lang
Type
string

Responses​

The owner collection

application/json
JSON
{
"data": [
],
"holder": {
"kind": "string",
"first_name": "string",
"short_name": "Vitaliy R.",
"handle": "string",
"profile_path": "string",
"source": "string",
"full_name": "string"
},
"summary": {
"additionalProperties": "string"
},
"next_up": [
{
"additionalProperties": "string"
}
],
"pin": {
"source": "string",
"slug": "string",
"code": "string",
"publicly_readable": true
},
"pin_writable": true,
"unrevealed_count": 0,
"vocabulary": "string"
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Pin an achievement card​

PUT
/me/achievements/pin

Pins one of the caller's own live cards (theirs, or an organization's they administer) to that holder's profile. A malformed, unknown, void or someone else's card all get the same 404 body, so the answer never says whether a code exists. Responses are private, no-store.

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
{
"card_code": "string"
}

Responses​

Pinned

application/json
JSON
{
"data": {
"pin": {
"source": "string",
"slug": "string",
"code": "string",
"publicly_readable": true
}
}
}

Playground​

Server
Authorization
Body

Samples​


Unpin an achievement card​

DELETE
/me/achievements/pin

Clears the caller's pin, or with organization that organization's pin when the caller administers it. Idempotent. The profile then shows the automatic choice.

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

organization
Type
string
Format
"uuid"

Responses​

Unpinned

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get my reveal pack​

GET
/me/achievements/reveals

Cards waiting to be "opened": with receipt, the ones a particular donation earned (the thank-you page — status: pending while the award is still being computed); with all=true, every unrevealed card. Pass exactly one. Someone else's receipt answers like a donation that earned nothing (status: none). Responses are private, no-store.

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

receipt

A Stripe PaymentIntent id.

Type
string
Pattern
"^pi_[A-Za-z0-9_]{1,255}$"
all
Type
string
Valid values
"true"

Responses​

The pack

application/json
JSON
{
"data": {
"status": "string",
"events": [
{
"id": 0,
"event_ids": [
0
],
"kind": "string",
"tier": {
"key": "string",
"label": "string"
},
"from_tier": {
"key": "string",
"label": "string"
},
"revealed": true,
"card": {
"additionalProperties": "string"
},
"tierup_line": "string"
}
]
}
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Mark reveal events as opened​

POST
/me/achievements/reveals/ack

Marks the caller's own reveal events as revealed. Ids that are not the caller's are ignored silently; the answer is 204 either way.

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
{
"event_ids": [
0
]
}

Responses​

Acknowledged

Playground​

Server
Authorization
Body

Samples​


Set an achievement's visibility​

PATCH
/me/achievements/{slug}

The holder's "Visible to: Everyone / Only me" control for one badge. default follows the badge's own visibility. When the caller wears the badge both personally and through an organization (or through two organizations), holder must say which; otherwise 409 with the list of holders.

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

slug*

The achievement's slug.

Type
string
Required

Request Body​

application/json
JSON
{
"visibility_override": "string",
"holder": {
"type": "string",
"id": "string"
}
}

Responses​

The updated award

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

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Storage​

Direct uploads of campaign images to the platform's CDN bucket.


Upload an image​

POST
/storage/upload

Stores a base64-encoded raster image on the platform CDN and returns its public URL, which the media gallery, outcome reports and the campaign form accept. Requires a bearer session. Only raster image types are accepted (no SVG or HTML), into one of four folders. Omit path and the server stores the file under a new unique path beginning with the caller's user id, returned as path. A supplied path must begin with the caller's own user id, profile id or Cognito sub, the same rule POST /storage/delete applies. An upload never replaces an existing file. The JSON body limit (10 MB) caps the file size.

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
{
"bucket": "string",
"path": "3f6c1b9e-7d2a-4c8e-9b1f-2a4d6e8f0c13/cover-1717171717.jpg",
"fileBase64": "string",
"contentType": "string"
}

Responses​

Stored

application/json
JSON
{
"success": true,
"url": "string",
"path": "string"
}

Playground​

Server
Authorization
Body

Samples​


Delete an uploaded image​

POST
/storage/delete

Deletes one uploaded file. The path's first segment must be the caller's own user id, profile id or Cognito sub; files uploaded under any other prefix cannot be deleted through this endpoint. Requires a bearer session.

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
{
"bucket": "string",
"path": "string"
}

Responses​

Deleted

application/json
JSON
{
"success": true
}

Playground​

Server
Authorization
Body

Samples​


API Keys​

Long-lived fh_live_… keys for CLI and agent access. A key is sent as Authorization: Bearer fh_live_… and authenticates as the user who created it, on every endpoint that accepts a bearer session.


List my API keys​

GET
/api-keys

The authenticated user's keys, newest first. Never includes the secret. Revoked keys are excluded unless include_revoked=true.

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

include_revoked
Type
string
Valid values
"true""false"
Default
"false"

Responses​

The caller's keys

application/json
JSON
{
"data": [
],
"total": 0
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Create an API key​

POST
/api-keys

Mints a new API key for the authenticated user. The full key is returned once, in api_key, and cannot be retrieved again. key.prefix (the first 12 characters) is what later listings show.

Requires a signed-in session (the session cookies, or a Cognito JWT in the Authorization header). A request authenticated with an API key, or made while an administrator is viewing the account as its owner, answers 403.

Every new key expires: one year after creation unless expires_at asks for sooner. A key stops working early if it is revoked, if its owner's account is suspended, banned or deactivated, or if an administrator signs the owner out of every device (which revokes all of the owner's keys).

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
{
"name": "CI deploy bot",
"expires_at": "string"
}

Responses​

Key created

application/json
JSON
{
"message": "string",
"api_key": "fh_live_3f9c2a1b0e7d4c5a8b6f1e2d3c4b5a69788766554433221100ffeeddccbbaa99",
"key": "string"
}

Playground​

Server
Authorization
Body

Samples​


Revoke an API key​

DELETE
/api-keys/{id}

Revokes one of the caller's own keys. Takes effect immediately. A key that belongs to someone else, does not exist, or is already revoked answers 404.

Requires a signed-in session: a request authenticated with an API key, or made while an administrator is viewing the account as its owner, answers 403.

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

id*
Type
string
Required
Format
"uuid"

Responses​

Key revoked

application/json
JSON
{
"message": "string",
"id": "string"
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Meta​

Crawler-facing discovery files (llms.txt, sitemaps), generated from live data and proxied by the frontend at the site's public paths.


Get llms.txt​

GET
/meta/llms.txt

The AI-crawler discovery file served at https://fundlyhub.org/llms.txt: live platform statistics, categories, trending campaigns, key pages and localised versions, in Markdown. Cached for an hour. No authentication.

Responses​

The file

text/plain
JSON
"string"

Playground​

Samples​


Get llms-full.txt​

GET
/meta/llms-full.txt

The long form of llms.txt: active campaigns, how the platform works, the money and trust model, FAQ, glossary and site structure. Cached for an hour. No authentication.

Responses​

The file

text/plain
JSON
"string"

Playground​

Samples​


Get the sitemap index​

GET
/meta/sitemap-index

A <sitemapindex> listing one sitemap per locale (/sitemaps/{en,ru,uk,es}.xml on the site). Cached for five minutes. No authentication.

Responses​

Sitemap index XML

application/xml
XML

Playground​

Samples​


Get a locale sitemap​

GET
/meta/sitemaps/{locale}

The <urlset> for one locale, with hreflang alternates. Accepts the bare locale or the locale with .xml. Cached for five minutes. No authentication.

Parameters​

Path Parameters

locale*
Type
string
Required
Valid values
"en""ru""uk""es""en.xml""ru.xml""uk.xml""es.xml"

Responses​

Sitemap XML

application/xml
XML

Playground​

Server
Variables
Key
Value

Samples​


Creator Subscriptions​


List a creator's tiers​

GET
/creators/{user_id}/tiers

A creator's active tiers, by sort_order then price. Empty for a private profile, except to its owner.

Authentication is optional; it only matters for the owner.

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)
or

Parameters​

Path Parameters

user_id*

The creator's profile UUID (slugs are not accepted).

Type
string
Required
Format
"uuid"

Responses​

Active tiers

application/json
JSON
{
"data": [
]
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


List my tiers​

GET
/me/tiers

The caller's tiers, archived ones included (active first). Empty for someone who has never created one.

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​

The caller's tiers

application/json
JSON
{
"data": [
]
}

Playground​

Server
Authorization

Samples​


Create a tier​

POST
/me/tiers

Creates a tier and its Stripe Product with a monthly Price (and an annual one when annual_amount_cents is given). Creating a first tier grants the caller the creator role; there is no separate "become a creator" step. Receiving payouts still needs Stripe Connect onboarding — fans can subscribe before then, and the money is held.

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
"string"

Responses​

Tier created

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

Playground​

Server
Authorization
Body

Samples​


Archive a tier​

DELETE
/me/tiers/{tier_id}

Archives one of the caller's tiers (is_active: false), hiding it from the public list. Reversible, and safe for tiers with subscribers. To remove a tier for good, use DELETE /me/tiers/{tier_id}/permanent.

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

tier_id*
Type
string
Required
Format
"uuid"

Responses​

Archived

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Update a tier​

PATCH
/me/tiers/{tier_id}

Partial update of one of the caller's tiers. Changing a price mints a new Stripe Price and deactivates the old one; existing subscribers keep their original price until renewal. Setting annual_amount_cents to null withdraws annual billing. Currency cannot be changed. A tier that is not the caller's is a 404.

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

tier_id*
Type
string
Required
Format
"uuid"

Request Body​

application/json
JSON
{
"name": "string",
"description": "string",
"amount_cents": 0,
"annual_amount_cents": 0,
"benefits": [
"string"
],
"cover_image": "string",
"sort_order": 0,
"subscriber_limit": 0
}

Responses​

Updated tier

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

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Delete a tier permanently​

DELETE
/me/tiers/{tier_id}/permanent

Deletes one of the caller's tiers outright. Only possible for a tier nobody has ever subscribed to — a cancelled subscription is still a billing record — otherwise 409 with code: TIER_HAS_SUBSCRIBERS; archive it instead.

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

tier_id*
Type
string
Required
Format
"uuid"

Responses​

Deleted

Playground​

Server
Authorization
Variables
Key
Value

Samples​


List my creator subscriptions​

GET
/me/subscriptions

Every subscription the caller holds, ended ones included, with tier and creator display fields. Active and trialing first, then past due, paused, and the rest; newest first within each.

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​

The caller's subscriptions

application/json
JSON
{
"data": [
]
}

Playground​

Server
Authorization

Samples​


Subscribe to a creator tier​

POST
/me/subscriptions

Creates a Stripe Subscription to an active tier, recorded locally as incomplete. Confirm the first payment in the browser with Stripe Elements using client_secret; the webhook then moves it to active.

Calling again while a previous attempt for the same tier is still incomplete or past_due resumes it — the same subscription and client_secret — rather than creating a second one. An active or trialing subscription to the tier is a 409. Subscribing to a different tier of the same creator is allowed.

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
{
"tier_id": "string",
"interval": "string"
}

Responses​

Subscription created or resumed

application/json
JSON
{
"data": {
"subscription_id": "string",
"stripe_subscription_id": "string",
"client_secret": "string",
"status": "string"
}
}

Playground​

Server
Authorization
Body

Samples​


Cancel a creator subscription​

POST
/me/subscriptions/{id}/cancel

An active or trialing subscription is set to cancel at the end of the paid period. One that is incomplete, past_due, unpaid or paused is cancelled immediately. Already cancelled or already scheduled is a no-op. A subscription that is not the caller's is a 404.

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

id*

The local subscription id (subscription_id), not the Stripe id.

Type
string
Required
Format
"uuid"

Responses​

Cancelled or scheduled

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Resume a creator subscription​

POST
/me/subscriptions/{id}/resume

Undoes a scheduled cancellation while the subscription is still running. A no-op when nothing is scheduled. A subscription that has already ended cannot be resumed — subscribe again.

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

id*
Type
string
Required
Format
"uuid"

Responses​

Resumed (or nothing to undo)

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Email Preferences​

Public, token-authorised unsubscribe and resubscribe for any address FundlyHub mails, including guest donors with no account.


Preview an unsubscribe link​

GET
/unsubscribe/preview

Validates the signed token from an email's unsubscribe link and says which (masked) address and which scope it would silence. Changes nothing.

No authentication: the signed token is the authorisation. Rate limited at 300 requests/minute per IP.

Parameters​

Query Parameters

token*
Type
string
Required

Responses​

The token is valid

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

Playground​

Server
Variables
Key
Value

Samples​


Unsubscribe​

POST
/unsubscribe

Suppresses mail to the token's address for the token's scope, or for everything when all is true. Idempotent.

No authentication: the signed token is the authorisation. No feature flag can switch this off. Rate limited at 10 requests/minute per IP.

Request Body​

application/json
JSON
"string"

Responses​

Unsubscribed

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

Playground​

Server
Body

Samples​


Resubscribe​

POST
/unsubscribe/resubscribe

Lifts the suppression for the token's address and scope (or for all). The undo for POST /unsubscribe.

No authentication: the signed token is the authorisation. Rate limited at 10 requests/minute per IP.

Request Body​

application/json
JSON
"string"

Responses​

Resubscribed

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

Playground​

Server
Body

Samples​


Request a fresh unsubscribe link​

POST
/unsubscribe/request

Mails a new signed unsubscribe link to email — the repair path for old emails whose link carried no token. Sent only to an address FundlyHub has previously mailed, at most once per address per hour.

Always answers { "data": { "sent": true } }, whatever happened, so it cannot be used to test whether an address is known.

No authentication. Rate limited at 10 requests/minute per IP.

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

Accepted

application/json
JSON
{
"data": {
"sent": true
}
}
Server
Body

Redeem an ambassador invitation​

POST
/ambassador-invites/redeem

Accepts an ambassador invitation for the signed-in account — the path for Google and Apple sign-ups, which cannot carry the token through POST /cognito/signup. The invitation is matched against the account's own registered email address; someone else's token is declined with email_mismatch.

A declined redemption is still a 200 with granted: false and a reason, so a client can always call this after sign-up even when the token was already spent. No special permission is needed.

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
{
"token": "string"
}

Responses​

Granted, or declined with a reason

application/json
JSON
{
"granted": true,
"reason": "string"
}

Playground​

Server
Authorization
Body

Samples​


Apply to be an ambassador​

POST
/ambassador-applications

Files an application to the ambassador programme for review by FundlyHub. Works signed out; when a session is present, the application records which account filed it.

One pending application per address: a second is 409, as is an address that already holds the ambassador role.

Authentication is optional. Rate limited at 5 requests/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)
or

Request Body​

application/json
JSON
{
"fullName": "string",
"email": "string",
"location": "string",
"socialMedia": "string",
"experience": "string",
"motivation": "string"
}

Responses​

Application received

application/json
JSON
{
"received": true
}

Playground​

Server
Authorization
Body

Samples​


List ambassadors (public directory)​

GET
/ambassadors

Ambassador role-holders with a public profile, ordered by the money their referral links have driven (the amounts themselves are not returned). Feeds the front-page rail.

No authentication. Rate limited at 300 requests/minute per IP.

Parameters​

Query Parameters

limit
Type
integer
Minimum
1
Maximum
60
Default
24

Responses​

The directory

application/json
JSON
{
"ambassadors": [
{
"userId": "string",
"name": "string",
"avatar": "string",
"href": "string",
"location": "string"
}
]
}

Playground​

Server
Variables
Key
Value

Samples​


List ambassadors for the endorsement picker​

GET
/ambassadors/selectable

Ambassadors a campaign creator may ask to endorse their campaign: role-holders with a public profile, excluding the caller, with the lifetime money each has driven in cents. Authenticated because it carries those amounts.

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
Minimum
1
Maximum
60
Default
24

Responses​

The picker list

application/json
JSON
{
"ambassadors": [
{
"userId": "string",
"name": "string",
"avatar": "string",
"referredCents": 0
}
]
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get an ambassador's referral analytics​

GET
/ambassadors/{id}/analytics

All-time referral analytics for one ambassador: clicks by traffic type, conversions, attributed funds per currency, and breakdowns by campaign, UTM source and day.

Callers may read their own analytics; anyone else's answers 403.

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

id*

The ambassador's profile UUID.

Type
string
Required
Format
"uuid"

Responses​

The analytics (bare object)

application/json
JSON
"string"

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get or create my referral code​

POST
/referrals/codes

Returns the caller's referral code — the profile-level one, or the one for fundraiser_id — creating it on first use. Idempotent. Share links take the form /r/{code} on the site. Every signed-in user can hold a code; the ambassador role is not required.

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
{
"fundraiser_id": "string"
}

Responses​

The code

application/json
JSON
{
"code": "aB3dE5fG7h"
}

Playground​

Server
Authorization
Body

Samples​


Record a referral-link click​

POST
/referrals/clicks

Called by the FundlyHub web app when a visitor opens a referral link (/r/{code}); not for third-party clients. Returns where to redirect and the visitor id to set as a cookie. Records a click classified as human, bot or unknown, and stamps the code into utm_content. When the visitor is signed in, the code is also remembered on their profile for attribution.

An unknown code still answers 200 with resolved: false and a target_path of the home page.

Authentication is optional. Rate limited per caller: 120 requests/minute, on top of the global per-IP limiter. Past the limit the answer is 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)
or

Request Body​

application/json
JSON
{
"code": "string",
"user_agent": "string",
"request_method": "GET",
"referer": "string",
"visitor_id": "string",
"ip": "string",
"utm_source": "string",
"utm_medium": "string",
"utm_campaign": "string",
"utm_content": "string",
"entry_point": "redirect"
}

Responses​

Click processed

application/json
JSON
"string"

Playground​

Server
Authorization
Body

Samples​


Get my referral summary​

GET
/me/referrals/summary

The ambassador portal's headline: totals, the click-to-gift funnel and a daily series for the caller's own referral links over a window (default: the 28 days ending to). Every portal route reads only the session's own rows.

Requires permission: view_own_referral_portal.

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

from

Window start. Defaults to 28 days before to. Must be before to and not earlier than 2020-01-01.

Type
string
Format
"date-time"
to

Window end. Defaults to now.

Type
string
Format
"date-time"

Responses​

The summary

application/json
JSON
{
"data": "string",
"range": "string"
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


List campaigns I referred to​

GET
/me/referrals/campaigns

Per-campaign clicks, visitors, driven gifts and money raised from the caller's referral links in the window.

Requires permission: view_own_referral_portal.

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

from

Window start. Defaults to 28 days before to. Must be before to and not earlier than 2020-01-01.

Type
string
Format
"date-time"
to

Window end. Defaults to now.

Type
string
Format
"date-time"

Responses​

The campaigns

application/json
JSON
{
"data": [
{
"fundraiser_id": "string",
"fundraiser_title": "string",
"fundraiser_slug": "string",
"clicks_human": 0,
"clicks_bot": 0,
"clicks_unknown": 0,
"distinct_human_visitors": 0,
"driven_gifts": 0,
"raised_cents": 0,
"last_click_at": "string"
}
],
"range": "string"
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get what my referral link did for one campaign​

GET
/me/referrals/campaigns/{fundraiserId}

All-time figures for the caller's own referral link on one campaign: impressions (visits not identified as a bot), clicks by traffic type, distinct human visitors, driven gifts (paid, not self-referred), distinct donors, and the value of those gifts (donation + tip) per currency in cents. The same definitions as the per-campaign rows of the ambassador analytics. Also returns the caller's referral code and link for the campaign when one exists; this read never creates one. Feeds the ambassador bar on the campaign page.

A campaign the caller may not open (draft, pending, private or deleted, and not their own) is a 404, as its page is.

Requires permission: view_own_referral_portal.

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

fundraiserId*

The campaign's id.

Type
string
Required
Format
"uuid"

Responses​

The caller's figures for the campaign

application/json
JSON
{
"data": {
"fundraiser_id": "string",
"impressions": 0,
"clicks_by_traffic_type": {
"human": 0,
"bot": 0,
"unknown": 0
},
"distinct_human_visitors": 0,
"driven_gifts": 0,
"distinct_donors": 0,
"funds_attributed": [
{
"currency": "string",
"amount_cents": 0
}
],
"referral_code": "string",
"referral_url": "https://fundlyhub.org/r/AbC123xYz0",
"last_click_at": "string",
"last_gift_at": "string",
"as_of": "string"
}
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get my referral traffic breakdown​

GET
/me/referrals/traffic

Where the caller's referral clicks came from — by UTM source, referer and medium — plus traffic type, and country and device splits from Google Analytics when it is configured (ga_note says why those are null otherwise).

Requires permission: view_own_referral_portal.

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

from

Window start. Defaults to 28 days before to. Must be before to and not earlier than 2020-01-01.

Type
string
Format
"date-time"
to

Window end. Defaults to now.

Type
string
Format
"date-time"

Responses​

The breakdown

application/json
JSON
{
"data": "string",
"range": "string"
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


List gifts I drove​

GET
/me/referrals/gifts

The donations attributed to the caller's referral links in the window, refunded, failed and self-referred gifts included. Each row carries exactly the fields of AmbassadorGift: no donor email, card details or receipt reference, and no donor name on an anonymous gift.

Requires permission: view_own_referral_portal.

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

from

Window start. Defaults to 28 days before to. Must be before to and not earlier than 2020-01-01.

Type
string
Format
"date-time"
to

Window end. Defaults to now.

Type
string
Format
"date-time"
limit
Type
integer
Minimum
1
Maximum
200
Default
50
offset
Type
integer
Minimum
0
Default
0

Responses​

One page of gifts

application/json
JSON
{
"data": [
],
"total": 0,
"drivenTotal": 0,
"range": "string"
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


Get my ambassador standing​

GET
/me/referrals/standing

The caller's rank among ambassadors by money raised in the window, and the leaderboard (up to 200 rows; truncated when there are more). Other ambassadors with private profiles appear without name or avatar.

Requires permission: view_own_referral_portal.

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

from

Window start. Defaults to 28 days before to. Must be before to and not earlier than 2020-01-01.

Type
string
Format
"date-time"
to

Window end. Defaults to now.

Type
string
Format
"date-time"

Responses​

The standing

application/json
JSON
{
"data": {
"rank": 0,
"total_ambassadors": 0,
"leaderboard": [
{
"rank": 0,
"ambassador_user_id": "string",
"display_name": "string",
"avatar_url": "string",
"raised_cents": 0,
"driven_gifts": 0,
"is_me": true
}
],
"truncated": true
},
"range": "string"
}

Playground​

Server
Authorization
Variables
Key
Value

Samples​


List my own campaigns (ambassador portal)​

GET
/me/campaigns

The campaigns the caller owns, with totals and how many clicks on their own referral links led to them (self-referrals, which do not count as driven). Takes no date range.

Requires permission: view_own_referral_portal.

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​

The caller's campaigns

application/json
JSON
{
"data": [
{
"id": "string",
"title": "string",
"slug": "string",
"status": "string",
"goal_amount_cents": 0,
"total_raised_cents": 0,
"donation_count": 0,
"created_at": "string",
"self_referred_clicks": 0
}
]
}

Playground​

Server
Authorization

Samples​


DMCA​

DMCA §512 takedown notices and counter-notices. Currently dark behind the features.dmca_workflow flag.


File a DMCA takedown notice​

POST
/dmca/notice

Files a §512(c) takedown notice against a campaign or one of its media files. No account is needed to file. Both attestations must be true, and either mediaId or fundraiserId is required. Returns only a reference id; the claimant is emailed a confirmation and updates.

No authentication. Behind features.dmca_workflow, which is currently disabled (403). Rate limited at 5 requests/minute per IP.

Request Body​

application/json
JSON
{
"claimantName": "string",
"claimantOrganization": "string",
"claimantEmail": "string",
"claimantPhone": "string",
"claimantAddress": "string",
"mediaId": "string",
"fundraiserId": "string",
"infringingUrl": "string",
"copyrightedWorkDescription": "string",
"copyrightedWorkUrl": "string",
"goodFaithStatement": true,
"authorityStatement": true,
"electronicSignature": "string"
}

Responses​

Notice received

application/json
JSON
{
"ok": true,
"complaintId": "string",
"submittedAt": "string",
"message": "string"
}

Playground​

Server
Body

Samples​


File a DMCA counter-notice​

POST
/dmca/complaints/{id}/counter-notice

The uploader of media taken down under a notice files a §512(g) counter-notice. Only the media's original uploader may file, and only against a complaint in valid status. All three statements must be true. FundlyHub forwards it to the claimant.

Behind features.dmca_workflow, which is currently disabled (403).

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

id*

The complaint id.

Type
string
Required
Format
"uuid"

Request Body​

application/json
JSON
{
"goodFaithStatement": true,
"consentToJurisdiction": true,
"perjuryStatement": true,
"electronicSignature": "string",
"contactName": "string",
"contactAddress": "string",
"contactPhone": "string",
"contactEmail": "string"
}

Responses​

Counter-notice received

application/json
JSON
{
"ok": true,
"counterNoticeId": "string",
"submittedAt": "string",
"message": "string"
}

Playground​

Server
Authorization
Variables
Key
Value
Body

Samples​


Support​

Live-chat (Chatwoot) identity for the signed-in user.


Get the live-chat identity hash​

GET
/chatwoot/identity-hash

The caller's identity hash for the support chat widget's setUser(…, { identifier_hash }), so the chat knows which signed-in user it is talking to.

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​

The hash

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

Playground​

Server
Authorization

Samples​


Powered by VitePress OpenAPI

Built with VitePress