Donor Endpoints
Donor endpoints serve the miranda.gives portal. They require Supabase authentication with the donor role in the JWT’s app_metadata.roles.
All endpoints are prefixed with /api/donor and use the middleware stack: auth.supabase:relaxed, role:donor.
Authentication
Section titled “Authentication”Donors authenticate via Supabase and must have "donor" in their JWT app_metadata.roles array:
curl -X GET https://app.miranda.foundation/api/donor/profile \ -H "Authorization: Bearer {supabase_jwt_with_donor_role}"Impact Dashboard
Section titled “Impact Dashboard”| Method | Path | Description |
|---|---|---|
| GET | /donor/impact | Get the donor’s impact summary |
Returns aggregate giving data across all foundations the donor supports.
Donations
Section titled “Donations”| Method | Path | Description |
|---|---|---|
| GET | /donor/donations | List the donor’s donation history |
| POST | /donor/donations | Make a new donation |
POST /donor/donations
Section titled “POST /donor/donations”Creates a donation through the DonationService::processDonorDonation() flow:
{ "foundation_id": "uuid", "amount": 50.00, "payment_method_id": "pm_abc123", "save_payment_method": true, "donor_covers_fees": false, "donation_page_id": "uuid"}Returns:
{ "donation": { "id": "uuid", "amount": 5000, "status": "pending", ... }, "client_secret": "pi_xxx_secret_yyy", "status": "requires_confirmation"}The client_secret is used by Stripe.js on the frontend to confirm the payment if the PaymentIntent requires further action.
Foundations
Section titled “Foundations”| Method | Path | Description |
|---|---|---|
| GET | /donor/foundations | List foundations the donor supports |
Returns all foundations where the donor has a DonorFoundationLink, including giving stats per foundation.
Recurring Donations
Section titled “Recurring Donations”| Method | Path | Description |
|---|---|---|
| GET | /donor/recurring | List active recurring subscriptions |
| PATCH | /donor/recurring/{id} | Update a recurring donation (amount, interval, pause, cancel) |
Newsletter Preferences
Section titled “Newsletter Preferences”| Method | Path | Description |
|---|---|---|
| GET | /donor/newsletters | List newsletter subscriptions across foundations |
| PATCH | /donor/newsletters/{foundationId} | Update newsletter preferences for a foundation |
Profile
Section titled “Profile”| Method | Path | Description |
|---|---|---|
| GET | /donor/profile | Get donor profile |
| PATCH | /donor/profile | Update donor profile |
Payment Methods
Section titled “Payment Methods”| Method | Path | Description |
|---|---|---|
| GET | /donor/payment-methods | List saved payment methods |
| POST | /donor/payment-methods | Save a new payment method |
| DELETE | /donor/payment-methods/{id} | Remove a payment method |
GET /donor/payment-methods
Section titled “GET /donor/payment-methods”Returns saved cards from the donor’s platform Stripe Customer:
[ { "id": "pm_abc123", "brand": "visa", "last4": "4242", "exp_month": 12, "exp_year": 2027 }]Payment methods are stored on Miranda’s platform Stripe account (not on individual foundation connected accounts), so donors can use saved cards across any foundation.
Scholarship Applications
Section titled “Scholarship Applications”| Method | Path | Description |
|---|---|---|
| POST | /donor/applications | Submit a scholarship application |
Donors can submit applications to any scholarship that is in accepting status.
Two-layer Stripe architecture
Section titled “Two-layer Stripe architecture”The donor portal uses a two-layer Stripe model:
- Layer 1 (Platform): The donor’s Stripe Customer lives on Miranda’s platform account. Payment methods are attached here.
- Layer 2 (Destination): When a donation is made, a PaymentIntent is created on the platform account with
transfer_data.destinationrouting funds to the foundation’s connected account.
This means:
- Donors manage one set of payment methods across all foundations
- Each foundation receives funds directly in their connected Stripe account
- Miranda collects the platform fee via
application_fee_amount