Skip to content

Fundraisers​

Create and manage fundraising campaigns


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​


Powered by VitePress OpenAPI

Built with VitePress