Storefront donations
Donation flows for a storefront: list the donation campaigns and their progress, read the funds and dedication types a donation form offers, start a donation (which returns a payment intent), read a donation back for a thank-you page, and email a donor a link to manage their monthly donations. Authenticated with the sales-channel id (vc_*) in the path and the browser Origin header.
Start a donation and mint a payment intent for it
Starts a donation and creates a payment intent for it. It is gated on the store switch for donations, not on the cart or order scopes. A clientRequestId makes a double click return the same donation. Limited to 5 requests per minute per IP.
For /api/vc/{connectionId}/* routes the connectionId (vc_*) is in the URL path — not a header. Live-mode requests must also send a matching Origin header.
In: header
Path Parameters
Sales channel ID (vc_*), the canonical salesChannelId. connectionId is the deprecated name of the same value and is still the literal path segment.
Header Parameters
Origin of the storefront page making the call, for example https://shop.example.com. Required: a request with no Origin header is refused with 403. On a LIVE channel its host must equal the channel's registered domain (or one of its subdomains) or match an allowed origin. A TEST channel with no domain accepts any origin; once a domain is set it is matched as on LIVE.
Version of the calling SDK (the Brainerce SDK sends it automatically). Informational: it is recorded on the channel and never changes the response.
The gift itself, in the store base currency. EXCLUDES feeCoverAmount — this is the figure the donor is credited with and the figure a receipt is written for.
0.01 <= value <= 1000000Processing fee the donor volunteered to absorb. Charged on top of amount, never subtracted from it and never a line item. Around 55-60% of donors accept this when offered.
00 <= value <= 1000000The donor's email. Also how their giving history is found later.
length <= 320The donor's name, as they want it recorded.
length <= 200Hides the donor name on public surfaces (a donor wall, a thank-you page). Does NOT anonymise the record — the merchant still sees the donor in their own reporting.
falseTribute gift. tributeName is required when this is set.
"IN_HONOR" | "IN_MEMORY"Who the gift honours or remembers.
length <= 200The donor's own words. Stored and displayed as plain text, never as HTML.
length <= 2000Which storefront the donation came through. Drives the return URL the payment provider sends the donor back to.
Where to land the donor after payment, as a PATH on the sales channel’s own domain (e.g. /thank-you). A full URL is rejected: the provider redirects a browser here, so accepting one would make this an open redirect.
^\/(?!\/)[A-Za-z0-9\-._~!$&'()*+,;=:@%/?#[\]]*$length <= 512The donation campaign this gift is for (its id, from the public campaign read). Omit for a general gift. Refused unless the campaign is active and inside its dates, and the amount fits the campaign’s limits: 404 campaign_not_found, 409 campaign_not_started / campaign_paused / campaign_ended, 400 amount_below_minimum / amount_above_maximum / amount_not_offered.
length <= 64The fund (designation) the gift is for, from getDonationOptions(). Defaults to the campaign’s fund when giving to a campaign; the donor may choose another. 400 fund_not_available for an unknown or archived fund.
length <= 64One of the store’s own dedication types, from getDonationOptions() (e.g. "For the recovery of"). Requires tributeName (the honoree). Use instead of tributeType, not with it. 400 dedication_not_available for an unknown or retired type.
length <= 64The name the receipt is made out to, when it differs from the donor (a spouse, a company).
length <= 200Donor phone number, for the receipt and the organisation.
^[+0-9 ()-]{6,24}$National ID or company number of the donor, for a tax receipt. Stored encrypted; never returned publicly, and the organisation sees only the last four characters.
^[0-9A-Za-z-]{4,20}$The name the donor allows on public surfaces (a donor wall, a thank-you page). Ignored when isAnonymous is true; defaults to donorName.
length <= 200Make this a monthly donation: this first gift is charged now and the card is saved for the following months. Refused before any charge with 409 recurring_not_supported when the store’s payment provider cannot charge a saved card, or 409 provider_mode_unknown when its live/test mode is not declared. A covered fee applies to this first gift only.
One random id per donation-form attempt (e.g. crypto.randomUUID()), resent unchanged on every submit of that attempt. A double-click or a network retry with the same id returns the SAME donation and payment page instead of opening a second one. Reusing an id with different amounts, email, channel or return path is refused with 409 idempotency_key_mismatch; once an attempt has failed or ended, its id answers 409 donation_attempt_closed, so start the next attempt with a new id.
^[A-Za-z0-9_-]{16,100}$curl -X POST "https://api.brainerce.com/api/vc/string/donations" \ -H "origin: string" \ -H "X-SDK-Version: string" \ -H "Content-Type: application/json" \ -d '{ "amount": 180, "donorEmail": "[email protected]" }'{
"donationId": "string",
"status": "PENDING",
"amount": "36.00",
"feeCoverAmount": "0.00",
"chargeAmount": "36.00",
"currency": "USD",
"payment": {
"intentId": "string",
"clientSecret": "string",
"clientSdk": {},
"redirectUrl": "string",
"providerType": "string"
}
}{
"statusCode": 400,
"code": "VALIDATION_FAILED",
"message": "name should not be empty, price must be a positive number",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/donations"
}{
"statusCode": 403,
"code": "INSUFFICIENT_SCOPE",
"message": "API key does not have the required scope: products:write",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/donations"
}{
"statusCode": 404,
"code": "RESOURCE_NOT_FOUND",
"message": "Resource not found",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/donations"
}{
"statusCode": 409,
"code": "CONFLICT",
"message": "The request conflicts with the current state of the resource",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/donations"
}{
"statusCode": 429,
"code": "RATE_LIMITED",
"message": "Too many requests",
"details": {
"retryAfterSeconds": 12
},
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/donations"
}{
"statusCode": 503,
"code": "INTERNAL_SERVER_ERROR",
"message": "Internal server error",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/donations"
}Read a donation back for a thank-you page
Reads a donation back for a thank-you page. Limited to 5 requests per minute per IP, because an id that either resolves or 404s would be an enumeration oracle.
For /api/vc/{connectionId}/* routes the connectionId (vc_*) is in the URL path — not a header. Live-mode requests must also send a matching Origin header.
In: header
Path Parameters
Sales channel ID (vc_*), the canonical salesChannelId. connectionId is the deprecated name of the same value and is still the literal path segment.
Donation id, returned by donations.
Header Parameters
Origin of the storefront page making the call, for example https://shop.example.com. Required: a request with no Origin header is refused with 403. On a LIVE channel its host must equal the channel's registered domain (or one of its subdomains) or match an allowed origin. A TEST channel with no domain accepts any origin; once a domain is set it is matched as on LIVE.
Version of the calling SDK (the Brainerce SDK sends it automatically). Informational: it is recorded on the channel and never changes the response.
curl -X GET "https://api.brainerce.com/api/vc/string/donations/string" \ -H "origin: string" \ -H "X-SDK-Version: string"{
"id": "string",
"status": "PENDING",
"amount": "36.00",
"feeCoverAmount": "0.00",
"currency": "USD",
"donorName": "string",
"tributeType": "IN_HONOR",
"tributeName": "string",
"dedicationLabel": "string",
"monthly": true,
"isTest": true,
"paidAt": "2019-08-24T14:15:22Z"
}{
"statusCode": 403,
"code": "INSUFFICIENT_SCOPE",
"message": "API key does not have the required scope: products:write",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/donations/{donationId}"
}{
"statusCode": 404,
"code": "RESOURCE_NOT_FOUND",
"message": "Resource not found",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/donations/{donationId}"
}{
"statusCode": 429,
"code": "RATE_LIMITED",
"message": "Too many requests",
"details": {
"retryAfterSeconds": 12
},
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/donations/{donationId}"
}List visible donation campaigns with their progress
Lists the visible donation campaigns (active and paused, at most 50, newest first) with their progress. Empty when the store has donations closed. Sent with Cache-Control: public, max-age=30.
For /api/vc/{connectionId}/* routes the connectionId (vc_*) is in the URL path — not a header. Live-mode requests must also send a matching Origin header.
In: header
Path Parameters
Sales channel ID (vc_*), the canonical salesChannelId. connectionId is the deprecated name of the same value and is still the literal path segment.
Query Parameters
Language code, for example he. Used only when no Accept-Language header is sent. A language the store does not support, or the store's default language, returns the default text.
Header Parameters
Origin of the storefront page making the call, for example https://shop.example.com. Required: a request with no Origin header is refused with 403. On a LIVE channel its host must equal the channel's registered domain (or one of its subdomains) or match an allowed origin. A TEST channel with no domain accepts any origin; once a domain is set it is matched as on LIVE.
Preferred language, for example he. Its first tag is used when it is one of the store's supported languages other than the default; translated fields are then returned in that language. Falls back to the locale query parameter.
Version of the calling SDK (the Brainerce SDK sends it automatically). Informational: it is recorded on the channel and never changes the response.
curl -X GET "https://api.brainerce.com/api/vc/string/donation-campaigns?locale=string" \ -H "origin: string" \ -H "accept-language: string" \ -H "X-SDK-Version: string"{
"data": [
{
"id": "string",
"slug": "building-fund",
"name": "string",
"description": "string",
"image": "string",
"state": "active",
"fundId": "string",
"startsAt": "2019-08-24T14:15:22Z",
"endsAt": "2019-08-24T14:15:22Z",
"currency": "USD",
"goalAmount": "50000.00",
"raisedAmount": "12450.00",
"donationCount": 213,
"percentOfGoal": 24,
"suggestedAmounts": [
"18.00",
"36.00",
"100.00"
],
"allowCustomAmount": true,
"minAmount": "string",
"maxAmount": "string"
}
]
}{
"statusCode": 403,
"code": "INSUFFICIENT_SCOPE",
"message": "API key does not have the required scope: products:write",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/donation-campaigns"
}{
"statusCode": 404,
"code": "RESOURCE_NOT_FOUND",
"message": "Resource not found",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/donation-campaigns"
}{
"statusCode": 429,
"code": "RATE_LIMITED",
"message": "Too many requests",
"details": {
"retryAfterSeconds": 12
},
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/donation-campaigns"
}Read one donation campaign by slug, with its progress
Returns one donation campaign by slug with its progress. Pass the returned id as campaignId to donations. Sent with Cache-Control: public, max-age=30.
For /api/vc/{connectionId}/* routes the connectionId (vc_*) is in the URL path — not a header. Live-mode requests must also send a matching Origin header.
In: header
Path Parameters
Sales channel ID (vc_*), the canonical salesChannelId. connectionId is the deprecated name of the same value and is still the literal path segment.
Campaign slug.
Query Parameters
Language code, for example he. Used only when no Accept-Language header is sent. A language the store does not support, or the store's default language, returns the default text.
Header Parameters
Origin of the storefront page making the call, for example https://shop.example.com. Required: a request with no Origin header is refused with 403. On a LIVE channel its host must equal the channel's registered domain (or one of its subdomains) or match an allowed origin. A TEST channel with no domain accepts any origin; once a domain is set it is matched as on LIVE.
Preferred language, for example he. Its first tag is used when it is one of the store's supported languages other than the default; translated fields are then returned in that language. Falls back to the locale query parameter.
Version of the calling SDK (the Brainerce SDK sends it automatically). Informational: it is recorded on the channel and never changes the response.
curl -X GET "https://api.brainerce.com/api/vc/string/donation-campaigns/string?locale=string" \ -H "origin: string" \ -H "accept-language: string" \ -H "X-SDK-Version: string"{
"id": "string",
"slug": "building-fund",
"name": "string",
"description": "string",
"image": "string",
"state": "active",
"fundId": "string",
"startsAt": "2019-08-24T14:15:22Z",
"endsAt": "2019-08-24T14:15:22Z",
"currency": "USD",
"goalAmount": "50000.00",
"raisedAmount": "12450.00",
"donationCount": 213,
"percentOfGoal": 24,
"suggestedAmounts": [
"18.00",
"36.00",
"100.00"
],
"allowCustomAmount": true,
"minAmount": "string",
"maxAmount": "string"
}{
"statusCode": 403,
"code": "INSUFFICIENT_SCOPE",
"message": "API key does not have the required scope: products:write",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/donation-campaigns/{slug}"
}{
"statusCode": 404,
"code": "RESOURCE_NOT_FOUND",
"message": "Resource not found",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/donation-campaigns/{slug}"
}{
"statusCode": 429,
"code": "RATE_LIMITED",
"message": "Too many requests",
"details": {
"retryAfterSeconds": 12
},
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/donation-campaigns/{slug}"
}The funds and dedication types a donation form offers
Returns what a donation form offers: the active funds and the dedication wording. Empty lists when the store offers none or has donations closed. Sent with Cache-Control: public, max-age=60.
For /api/vc/{connectionId}/* routes the connectionId (vc_*) is in the URL path — not a header. Live-mode requests must also send a matching Origin header.
In: header
Path Parameters
Sales channel ID (vc_*), the canonical salesChannelId. connectionId is the deprecated name of the same value and is still the literal path segment.
Query Parameters
Language code, for example he. Used only when no Accept-Language header is sent. A language the store does not support, or the store's default language, returns the default text.
Header Parameters
Origin of the storefront page making the call, for example https://shop.example.com. Required: a request with no Origin header is refused with 403. On a LIVE channel its host must equal the channel's registered domain (or one of its subdomains) or match an allowed origin. A TEST channel with no domain accepts any origin; once a domain is set it is matched as on LIVE.
Preferred language, for example he. Its first tag is used when it is one of the store's supported languages other than the default; translated fields are then returned in that language. Falls back to the locale query parameter.
Version of the calling SDK (the Brainerce SDK sends it automatically). Informational: it is recorded on the channel and never changes the response.
curl -X GET "https://api.brainerce.com/api/vc/string/donation-options?locale=string" \ -H "origin: string" \ -H "accept-language: string" \ -H "X-SDK-Version: string"{
"funds": [
{
"id": "string",
"slug": "string",
"name": "string",
"description": "string"
}
],
"dedicationTypes": [
{
"id": "string",
"label": "string"
}
],
"receiptTaxIdRequired": true
}{
"statusCode": 403,
"code": "INSUFFICIENT_SCOPE",
"message": "API key does not have the required scope: products:write",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/donation-options"
}{
"statusCode": 404,
"code": "RESOURCE_NOT_FOUND",
"message": "Resource not found",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/donation-options"
}{
"statusCode": 429,
"code": "RATE_LIMITED",
"message": "Too many requests",
"details": {
"retryAfterSeconds": 12
},
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/donation-options"
}Email a donor a link to manage their monthly donations
Emails a donor a link to manage their monthly donations. Always answers 202 with the same body, whether or not the address donates monthly here, so it cannot be used to find donors. Limited to 3 requests per minute per IP.
For /api/vc/{connectionId}/* routes the connectionId (vc_*) is in the URL path — not a header. Live-mode requests must also send a matching Origin header.
In: header
Path Parameters
Sales channel ID (vc_*), the canonical salesChannelId. connectionId is the deprecated name of the same value and is still the literal path segment.
Header Parameters
Origin of the storefront page making the call, for example https://shop.example.com. Required: a request with no Origin header is refused with 403. On a LIVE channel its host must equal the channel's registered domain (or one of its subdomains) or match an allowed origin. A TEST channel with no domain accepts any origin; once a domain is set it is matched as on LIVE.
Version of the calling SDK (the Brainerce SDK sends it automatically). Informational: it is recorded on the channel and never changes the response.
The donor email. An address that is not a valid email still gets the 202.
Email address the donor gave with their monthly donation. Trimmed and cut to 320 characters.
emaillength <= 320curl -X POST "https://api.brainerce.com/api/vc/string/donor-manage/request-link" \ -H "origin: string" \ -H "X-SDK-Version: string" \ -H "Content-Type: application/json" \ -d '{}'{
"accepted": true
}{
"statusCode": 403,
"code": "INSUFFICIENT_SCOPE",
"message": "API key does not have the required scope: products:write",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/donor-manage/request-link"
}{
"statusCode": 404,
"code": "RESOURCE_NOT_FOUND",
"message": "Resource not found",
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/donor-manage/request-link"
}{
"statusCode": 429,
"code": "RATE_LIMITED",
"message": "Too many requests",
"details": {
"retryAfterSeconds": 12
},
"timestamp": "2026-08-23T10:15:00.000Z",
"path": "/api/vc/{connectionId}/donor-manage/request-link"
}