Create Donation
Creates a donation record, calculates fees, and returns a Stripe PaymentIntent client secret for completing the payment on the frontend.
The campaign must be in ACTIVE status. The org must have completed Stripe Connect onboarding before donations can be processed.
Request Body
The ID of the campaign to attribute this donation to.
Donation amount in cents. Minimum 100 ($1.00). For event campaigns with a fixed ticket price, this is the per-ticket amount multiplied by ticketCount.
Three-letter ISO currency code. Currently only "usd" is supported.
Giving frequency. One of: "one_time", "monthly", "quarterly", "annual".
Payment method type. One of: "card", "ach", "apple_pay", "google_pay".
Whether the donor is covering processing and platform fees. When true, the total charged to the donor is grossed up so the nonprofit receives the full amount.
Donor contact information. Donor email address. Used for receipt delivery and donor record matching.
When true, the donor’s name is hidden from the public donor roll on the campaign page.
Optional tribute dedication. If provided, type and name are required. Either "in_honor" or "in_memory".
Name of the person being honored or remembered. Max 200 characters.
Optional tribute message. Max 500 characters.
Name of a person to notify about this tribute (e.g., a family member). Max 200 characters.
Email address to send a tribute notification to. A notification email is sent when the donation succeeds.
A public message from the donor, shown on the campaign’s donor roll. Max 280 characters.
Whether the donor opts in to future email communications from the organization.
Responses to campaign-specific custom fields. Show Custom field response object
The ID of the custom field being answered.
The donor’s response value.
The ID of a pre-configured giving level to associate with this donation. Optional.
For event campaigns with a fixed ticket price, the number of tickets being purchased (1–20). The total amount is derived from ticketCount × campaign.ticketPriceCents.
UTM source parameter for attribution tracking (e.g., "email", "facebook"). Max 100 characters.
UTM medium parameter (e.g., "newsletter", "cpc"). Max 100 characters.
UTM campaign parameter (e.g., "year-end-2026"). Max 100 characters.
The full URL of the referring page. Max 500 characters.
Response
The created donation record. Donation amount in cents (the intended gift, before fee adjustment).
Always "PENDING" on creation. Updated to "SUCCEEDED" or "FAILED" via Stripe webhook.
One of "ONE_TIME", "MONTHLY", "QUARTERLY", "ANNUAL".
The Stripe PaymentIntent client secret. Pass this to Stripe Elements or the Stripe.js confirmPayment() method on the frontend to complete payment collection.
The calculated fee breakdown for this donation. The intended donation amount in cents.
Stripe processing fee in cents (2.2% +
0.30 f o r c a r d s ; 0.8 0.30 for cards; 0.8% capped at 0.30 f orc a r d s ; 0.8 5 for ACH).
GiveLink platform fee in cents (1% of donation; waived for the first $10,000 raised).
Total amount charged to the donor’s card in cents. Equals donationAmount when coverFees is false; grossed up when true.
Amount the nonprofit receives in cents after all fees.
Example
curl -X POST https://givelink-api-production.up.railway.app/api/donations \
-H "Content-Type: application/json" \
-d '{
"campaignId": "clx9876543210",
"amount": 5000,
"currency": "usd",
"frequency": "monthly",
"paymentMethod": "card",
"coverFees": true,
"donor": {
"email": "jane@example.com",
"firstName": "Jane",
"lastName": "Smith",
"anonymous": false
},
"publicMessage": "Happy to support this cause!",
"emailOptIn": true,
"utmSource": "email",
"utmMedium": "newsletter",
"utmCampaign": "spring-2026"
}'
{
"donation" : {
"id" : "clx1111111111" ,
"amountCents" : 5000 ,
"status" : "PENDING" ,
"frequency" : "MONTHLY"
},
"clientSecret" : "pi_1234_secret_5678" ,
"fees" : {
"donationAmount" : 5000 ,
"processingFee" : 142 ,
"platformFee" : 51 ,
"totalCharged" : 5193 ,
"netToOrg" : 5000
}
}
Use the clientSecret with Stripe Elements on the frontend to collect payment details and confirm the PaymentIntent. The donation status remains PENDING until Stripe confirms payment via webhook.
Error Responses
Status Error Description 400 Campaign not foundThe campaignId does not exist. 400 Campaign is not activeThe campaign must be in ACTIVE status. 400 Minimum donation is $XThe amount is below the campaign’s minimum. 400 Organization has not completed payment setupStripe Connect onboarding is incomplete. 400 Sorry, not enough tickets availableEvent is sold out or insufficient capacity. 400 Validation failedOne or more fields failed schema validation.