Public Donation Page
Public Donation Page
Component Files: src/features/events/components/PublicDonationPage.tsx, src/features/donors/components/DonorLandingPage.tsx, src/features/donors/components/DonorLandingEmbeddedCheckout.tsx Canonical Route: https://donate.alignmint.app/{org-key-or-prefix}/{nonprofit-slug}/{page-slug} Access Level: Public Last Updated: July 24, 2026
Overview
This is the live donor-facing route for custom giving pages. It loads a published donor_pages record, resolves organization and Stripe state, renders the donation experience, and initializes payment through the create-payment-intent edge function.
Page Resolution
Primary load path: 1. Parse org-key-or-prefix, nonprofit-slug, and page-slug 2. Call get-public-donation-page 3. Build a DonorLandingPageConfig 4. Render the public donation page
Fallback path: 1. Call fetchDonorPageBySlug 2. Load stats, Stripe state, and admin contact info client-side 3. Build the same DonorLandingPageConfig
Availability rules
- only
publishedpages resolve - inactive organizations are blocked by both the public edge function and the fallback slug query
- ambiguous slug matches return an explicit error instead of guessing
Payment Flow
The live flow uses embedded Stripe PaymentElement, not a new-tab Stripe Checkout redirect.
1. Donor selects an amount 2. Donor can choose one-time or monthly recurring giving 3. Donor can optionally cover processing fees 4. The page calls create-payment-intent 5. DonorLandingEmbeddedCheckout lazy-loads Stripe React components once a clientSecret exists 6. Payment completes inline 7. Webhooks create the donation record and downstream bookkeeping side effects
Inactive fund enforcement
create-payment-intentandcreate-checkout-sessionreject inactive organizations (inactive_org_blocked)stripe-webhookdonation insert paths skip non-active orgs- database trigger
donations_block_inactive_org_writesrejects any direct donation insert for inactive orgs
Purpose / Fund Attribution
organizationIdmust be the real organization UUIDpurposeIdis optional and flows into payment-intent metadata- the public config uses
organization_idfrom the donor page record, not the donor page id
Media Rules
- Hero images render as images
- Hero videos from YouTube / Vimeo / VideoBlast render as embeds
- Uploaded media files now render with a native
<video>player instead of an iframe
Embed Mode
URL format
https://donate.alignmint.app/{org-key-or-prefix}/{nonprofit-slug}/{page-slug}?embed=trueCurrent embed behavior
- transparent page background
postMessageheight updates from the child iframe- optional color customization via URL params
- recurring giving and purpose selectors supported
- Stripe remains embedded inline
Recommended host listener
window.addEventListener('message', (e) => {
if (e.data?.type === 'alignmint-donation-resize') {
const iframe = document.querySelector('iframe[src*="donate.alignmint.app"]');
if (iframe) {
iframe.style.height = `${e.data.height}px`;
}
}
});The generated embed snippet from the manager also includes:
allow="payment *; publickey-credentials-get *"
Performance Notes
main.tsxdoes not eagerly load the authenticated app shell for/donate/*- Stripe React components are lazy-loaded only when the donor opens the payment step
- the edge function path replaces several client-side round trips on first load
Donor-Facing Error States
- invalid URL
- page not found / unavailable
- ambiguous URL
- failed page load
- Stripe not connected for the target org
The public route now uses less misleading titles for load failures versus unavailable pages.
Related Files
src/lib/db/marketing.tssupabase/functions/get-public-donation-page/index.tssupabase/functions/create-payment-intent/index.tssrc/lib/donorPageUrls.ts
Related Documentation
Synced from IFMmvp-Frontend documentation: pages/donor-hub/10-PUBLIC-DONATION-PAGE.md
Ready to Get Started?
See how Alignmint can simplify your nonprofit's operations. Schedule a free demo with our team and we'll walk you through everything.
Questions? Email us at steven@getalignmint.org