Skip to content

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​

Powered by VitePress OpenAPI

Built with VitePress