Charity Donations
Search vetted charities, record donations, and list donation history. The charity donations API is open to any app, not just Shopify. Sign up at app.thegoodapi.com and grab your API key. All endpoints use the base URL https://app.thegoodapi.com.
Before you go live
Section titled “Before you go live”Use this checklist before you take donations in production.
Funds flow
Section titled “Funds flow”- We collect via Stripe.
- Funds go through Our Change Foundation, a 501(c)(3) that grants to nonprofits. We name your platform in the grant info.
- We pay out monthly on the 28th. Nonprofit receive timing depends on grantor portal settings. Nonprofits get a dashboard and CA AB 488 reports.
- You get the tax receipt.
GoodAPI charges no donation processing fees and takes no cut of the donation. GoodAPI covers state fees, bonds, and filings.
- Donation costs are the Lead plan at $49/month for API access, Stripe collection (about 2 to 3 percent for cards, or about 0.8 percent for ACH if set up), and the foundation’s 1.9 percent grant fee (to them, not GoodAPI).
- Example: collect $100, receipt for $97 after card fees, nonprofit gets $95.10 after the grant fee.
Pricing and agreement
Section titled “Pricing and agreement”- Lead plan is $49/month for API access.
- No minimum commitment and no cancellation limits.
- Access is month-to-month under the Terms and Conditions.
- No sales agreement is required unless you have custom requirements. Those go on a custom plan.
- Request our compliance pack for registrations and filings.
Compliance
Section titled “Compliance”GoodAPI acts as the commercial co-venturer for giving that runs through it.
- All 50 states require an agreement between the for-profit and the nonprofit.
- 39 require that agreement registered, and GoodAPI is registered in all 39.
- 6 of those also require GoodAPI itself to register: Alabama, California, Hawaii, Massachusetts, Mississippi, and South Carolina. Those filings are done.
- Brand Partners, including API platforms, are already covered by GoodAPI’s agreement with Our Change Foundation. They do not need to file separately for California or Hawaii. Our registrations cover Brand Partner obligations.
- California public CCV profile
Naming a nonprofit
Section titled “Naming a nonprofit”Each API call names a nonprofit by EIN or nonprofit ID from 1.3M+ verified 501(c)(3)s. Use ein or nonprofit_id on POST /charities/donate.
Required disclosure
Section titled “Required disclosure”Show this copy next to the donation or behind an info icon:
Our donation platform, GoodAPI, partners with Our Change Foundation (EIN: 86-3353394), a nonprofit Section 501(c)(3) organization that makes grants to the nonprofits you suggest here. Learn more about how we process donations
All endpoints require an API key via the Authorization header:
Authorization: <your_api_key>Search charities
Section titled “Search charities”GET https://app.thegoodapi.com/charities/search
Search for charities by name or EIN, or fetch a single charity directly by nonprofit ID.
Query parameters
Section titled “Query parameters”| Name | Type | Required | Description |
|---|---|---|---|
name | string | No | Search by charity name |
q | string | No | Alias for name (used when name is not set) |
id | string | No | Change nonprofit ID (n_...) for direct lookup (detail mode) |
ein | string | No | Employer Identification Number |
page_size | integer | No | Results per page (1-20, default 20) |
page | integer | No | Page number (minimum 1, default 1) |
Response — 200 OK
Section titled “Response — 200 OK”{ "total_items": 42, "total_pages": 3, "charities": [ { "nonprofit_id": "n_abc123", "name": "American Red Cross", "ein": "53-0196605", "description": "Prevents and alleviates human suffering", "website": "https://www.redcross.org", "icon_url": "https://example.com/redcross-icon.png" } ]}Charity fields
Section titled “Charity fields”| Field | Type | Description |
|---|---|---|
nonprofit_id | string | Provider-specific nonprofit ID |
name | string | Charity name |
ein | string | Employer Identification Number |
description | string | Charity description or mission |
website | string | Charity website URL |
icon_url | string | Charity icon image URL |
Direct lookup (detail mode)
Section titled “Direct lookup (detail mode)”Pass id with a Change nonprofit ID (n_...) to fetch that charity directly instead of searching. This is how partners check a nonprofit’s written-consent status (direct / via_change), which paginated search results do not include. Direct lookup requires the Change provider (the default); PayPal-only accounts do not support it.
A name or q value that is itself a Change nonprofit ID (n_..., with no spaces) is also auto-detected as a direct lookup. An auto-detected ID that fails to resolve falls back to a normal free-text search; an explicitly requested id that fails does not fall back — it returns 502.
Response — 200 OK (detail mode)
Section titled “Response — 200 OK (detail mode)”{ "mode": "detail", "nonprofit": { "nonprofit_id": "n_abc123", "name": "American Red Cross", "ein": "53-0196605", "description": "Prevents and alleviates human suffering", "website": "https://www.redcross.org", "icon_url": "https://example.com/redcross-icon.png", "logo_url": "https://example.com/redcross-logo.png", "written_consent": { "direct": true, "via_change": true } }, "custom_logo_url": "https://example.com/redcross-custom-logo.png"}custom_logo_url is included only when GoodAPI has a custom logo on file for the nonprofit.
Detail fields
Section titled “Detail fields”| Field | Type | Description |
|---|---|---|
nonprofit_id | string | Provider-specific nonprofit ID |
name | string | Charity name |
ein | string | Employer Identification Number |
description | string | Charity description or mission |
website | string | Charity website URL |
icon_url | string | Charity icon image URL |
logo_url | string | Charity logo image URL from the provider |
written_consent | object | Written consent state: direct and via_change booleans |
Errors
Section titled “Errors”| Status | Reason |
|---|---|
403 | Invalid or missing API key |
500 | Charity search failed / nonprofit response could not be parsed |
501 | Direct lookup not supported by the configured charity provider (e.g. PayPal) |
502 | Change API returned an error for an explicitly requested id |
Example
Section titled “Example”curl -H "Authorization: <your_api_key>" \ "https://app.thegoodapi.com/charities/search?name=red+cross"Detail lookup by nonprofit ID:
curl -H "Authorization: <your_api_key>" \ "https://app.thegoodapi.com/charities/search?id=n_abc123"Subscribe to donations
Section titled “Subscribe to donations”POST https://app.thegoodapi.com/charities/subscribe
Provisions the Stripe subscription items for flat-rate and metered billing on your organization’s existing subscription. This must be called once before making any live donations.
Response — 200 OK
Section titled “Response — 200 OK”{ "success": true, "message": "Successfully activated donation subscription"}Errors
Section titled “Errors”| Status | Reason |
|---|---|
403 | Invalid or missing API key |
500 | Internal server error / Stripe integration error |
Example
Section titled “Example”curl -X POST -H "Authorization: <your_api_key>" \ "https://app.thegoodapi.com/charities/subscribe"Create donation
Section titled “Create donation”POST https://app.thegoodapi.com/charities/donate
Record a charity donation for your organization.
Request body
Section titled “Request body”{ "amount_cents": 5000, "ein": "53-0196605", "nonprofit_id": "n_abc123", "charity_name": "American Red Cross", "idempotency_key": "order-12345-donate", "attribution": "checkout-flow", "metadata": { "order_id": "12345", "customer_email": "customer@company.com" }}Request fields
Section titled “Request fields”| Field | Type | Required | Description |
|---|---|---|---|
amount_cents | integer | Yes | Donation amount in cents (must be > 0) |
ein | string | * | Employer Identification Number of the charity |
nonprofit_id | string | * | Provider-specific nonprofit identifier |
charity_name | string | No | Human-readable charity name (auto-filled from search if omitted) |
idempotency_key | string | No | Unique key to prevent duplicate donations |
attribution | string | No | Attribution tag (e.g. checkout, campaign-xyz) |
metadata | object | No | Arbitrary key-value pairs for your records |
Response — 200 OK
Section titled “Response — 200 OK”{ "donation_id": "abc123def456", "amount_cents": 5000, "charity_name": "American Red Cross", "ein": "53-0196605", "nonprofit_id": "n_abc123", "total_donations": 15, "donation_details": [ { "id": "abc123def456", "amount_cents": 5000, "currency": "USD", "ein": "53-0196605", "nonprofit_id": "n_abc123", "charity_name": "American Red Cross", "created_at": "2025-06-15T10:30:00Z", "idempotency_key": "order-12345-donate", "attribution": "checkout-flow", "metadata": { "order_id": "12345", "customer_email": "customer@company.com" }, "refunded": false } ]}Response fields
Section titled “Response fields”| Field | Type | Description |
|---|---|---|
donation_id | string | Unique ID of the created donation |
amount_cents | integer | Donation amount in cents |
charity_name | string | Charity name (auto-filled from search if omitted) |
ein | string | EIN (if provided) |
nonprofit_id | string | Nonprofit ID (if provided) |
total_donations | integer | Total non-refunded donations for your org |
donation_details | array | Array containing the created donation record |
Idempotency
Section titled “Idempotency”When idempotency_key is provided and a donation with the same key already exists for your organization:
- The existing donation is returned.
- The response includes the header
Idempotent-Replayed: true. - No new donation is created.
Charity validation
Section titled “Charity validation”The provided ein or nonprofit_id is validated against the charity search provider. If no matching charity is found, the request is rejected with a 400 error. When a charity is found and charity_name was not provided, it’s automatically populated from the search result.
Errors
Section titled “Errors”| Status | Reason |
|---|---|
400 | Missing ein and nonprofit_id |
400 | amount_cents is missing or <= 0 |
400 | Invalid request body |
400 | No charity found for the provided ein |
400 | No charity found for the provided nonprofit_id |
400 | Donation subscription not active |
403 | Invalid or missing API key |
500 | Internal server error |
Examples
Section titled “Examples”Basic donation by EIN:
curl -X POST -H "Authorization: <your_api_key>" \ -H "Content-Type: application/json" \ -d '{"amount_cents": 5000, "ein": "53-0196605"}' \ "https://app.thegoodapi.com/charities/donate"Donation with idempotency and attribution:
curl -X POST -H "Authorization: <your_api_key>" \ -H "Content-Type: application/json" \ -d '{ "amount_cents": 2500, "nonprofit_id": "n_abc123", "idempotency_key": "order-789-donate", "attribution": "checkout", "metadata": {"order_id": "789"} }' \ "https://app.thegoodapi.com/charities/donate"List donations
Section titled “List donations”GET https://app.thegoodapi.com/charities/donations
Retrieve paginated donations for your organization with optional filtering.
Query parameters
Section titled “Query parameters”| Name | Type | Required | Description |
|---|---|---|---|
attribution | string | No | Filter by attribution tag |
metadata_key | string | No | Filter by metadata key existence |
metadata_value | string | No | Filter by metadata value (requires metadata_key) |
start_date | string | No | Filter on or after this date (YYYY-MM-DD) |
end_date | string | No | Filter on or before this date (YYYY-MM-DD) |
page | integer | No | Page number (minimum 1, default 1) |
page_size | integer | No | Results per page (1-100, default 20) |
Response — 200 OK
Section titled “Response — 200 OK”{ "total_items": 50, "total_pages": 5, "page": 1, "page_size": 10, "donations": [ { "id": "abc123def456", "amount_cents": 5000, "currency": "USD", "ein": "53-0196605", "nonprofit_id": "n_abc123", "charity_name": "American Red Cross", "created_at": "2025-06-15T10:30:00Z", "idempotency_key": "order-12345-donate", "attribution": "checkout-flow", "metadata": { "order_id": "12345" }, "refunded": false } ]}Response fields
Section titled “Response fields”| Field | Type | Description |
|---|---|---|
total_items | integer | Total number of matching donations |
total_pages | integer | Total number of pages (0 if no results) |
page | integer | Current page number |
page_size | integer | Number of items per page |
donations | array | Array of donation records |
Donation fields
Section titled “Donation fields”| Field | Type | Description |
|---|---|---|
id | string | Unique donation ID |
amount_cents | integer | Donation amount in cents |
currency | string | Currency code (always USD) |
ein | string | EIN of the charity |
nonprofit_id | string | Provider-specific nonprofit ID |
charity_name | string | Human-readable charity name |
created_at | string | ISO 8601 timestamp |
idempotency_key | string | Idempotency key (if provided) |
attribution | string | Attribution tag |
metadata | object | Arbitrary key-value pairs |
refunded | boolean | Whether the donation has been refunded |
Errors
Section titled “Errors”| Status | Reason |
|---|---|
400 | Invalid date format |
403 | Invalid or missing API key |
500 | Internal server error |
Examples
Section titled “Examples”List all donations:
curl -H "Authorization: <your_api_key>" \ "https://app.thegoodapi.com/charities/donations"Filter by attribution with pagination:
curl -H "Authorization: <your_api_key>" \ "https://app.thegoodapi.com/charities/donations?attribution=checkout&page=1&page_size=10"Filter by date range:
curl -H "Authorization: <your_api_key>" \ "https://app.thegoodapi.com/charities/donations?start_date=2025-01-01&end_date=2025-06-30"Filter by metadata:
curl -H "Authorization: <your_api_key>" \ "https://app.thegoodapi.com/charities/donations?metadata_key=order_id&metadata_value=12345"Refund donation
Section titled “Refund donation”POST https://app.thegoodapi.com/refund/donations
Refund a charity donation by setting its status to refunded.
Request body
Section titled “Request body”{ "id": "don_abc123", "reason": "Customer cancelled order", "idempotency_key": "refund-order-12345", "metadata": { "refund_processed_by": "admin" }}Request fields
Section titled “Request fields”| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The unique donation ID to refund |
reason | string | No | Human-readable reason for the refund |
idempotency_key | string | No | Unique key to prevent duplicate refund processing |
metadata | object | No | Arbitrary key-value pairs stored with the refund |
Response — 200 OK
Section titled “Response — 200 OK”{ "refunded_amount_cents": 5000, "total_donations": 14, "refund_details": [ { "id": "don_abc123", "amount_cents": 5000, "currency": "USD", "ein": "53-0196605", "nonprofit_id": "n_abc123", "charity_name": "American Red Cross", "created_at": "2025-06-15T10:30:00Z", "idempotency_key": "order-12345-donate", "attribution": "checkout-flow", "metadata": { "order_id": "12345", "customer_email": "customer@company.com" }, "refunded": true } ], "refund_id": "refund-don_abc123"}Response fields
Section titled “Response fields”| Field | Type | Description |
|---|---|---|
refunded_amount_cents | integer | Amount refunded in cents |
total_donations | integer | Total non-refunded donations remaining for your organization |
refund_details | array | Array containing the refunded donation record |
refund_id | string | Unique identifier for this refund (refund-<donation_id>) |
Errors
Section titled “Errors”| Status | Reason |
|---|---|
400 | Missing id (donation ID) |
400 | Invalid request body |
403 | Invalid or missing API key |
404 | Donation not found |
500 | Internal server error |
Example
Section titled “Example”curl -X POST -H "Authorization: <your_api_key>" \ -H "Content-Type: application/json" \ -d '{"id": "don_abc123"}' \ "https://app.thegoodapi.com/refund/donations"API FAQ
Section titled “API FAQ”Can I tag donations and filter history?
Section titled “Can I tag donations and filter history?”Yes. Pass attribution plus a metadata object on POST /charities/donate, then filter GET /charities/donations with attribution, metadata_key, and metadata_value.
Can we hold funds and release them at a milestone?
Section titled “Can we hold funds and release them at a milestone?”No. Milestone or staged grant release is not supported. You must control timing on your end. Once funds go on the 28th, the foundation is required by law to start granting to the designated nonprofits.
If my company funds the gifts, can we send one donation per nonprofit?
Section titled “If my company funds the gifts, can we send one donation per nonprofit?”Yes. If the company funds the donation, you may total contributions internally and send one donation per nonprofit periodically. The same compliance rules apply.
Who gets the tax receipt?
Section titled “Who gets the tax receipt?”We name your platform in the grant info. You get the tax receipt.
What fees apply to donations?
Section titled “What fees apply to donations?”See Fees. GoodAPI charges no donation processing fees and takes no cut of the donation. Donation costs are the Lead plan at $49/month for API access, Stripe collection (about 2 to 3 percent for cards, or about 0.8 percent for ACH if set up), and the foundation’s 1.9 percent grant fee (to them, not GoodAPI). Example: collect $100, receipt for $97 after card fees, nonprofit gets $95.10 after the grant fee.
Do I need my own state registrations?
Section titled “Do I need my own state registrations?”Brand Partners, including API platforms, are already covered by GoodAPI’s agreement with Our Change Foundation. They do not need to file separately for California or Hawaii. Our registrations cover Brand Partner obligations.
How do I request registrations and filings?
Section titled “How do I request registrations and filings?”Request our compliance pack. If you need something beyond the standard month-to-month Terms and Conditions, that is a custom plan.