Payments Overview
The Batchmates payment system processes donations through Maya — the primary gateway — with PayMongo support alongside it, covering hosted checkout flows as well as direct charges against vaulted cards.
Stack
| Layer | Technology |
|---|---|
| Backend | Laravel 12 |
| Frontend | React 19 + TypeScript |
| Database | PostgreSQL |
| Payment gateways | Maya (PayMaya), PayMongo |
Two Payment Paths
| Path | When used | Gateways |
|---|---|---|
| Hosted Checkout | One-time donations (GCash, Maya wallet, card) | Maya, PayMongo |
| Charge saved card | One-time with a vaulted card | Maya, PayMongo |
Recurring / subscription billing is currently disabled pending gateway support. The subscription models and endpoints exist, but unattended recurring charges are not yet wired to a gateway.
Key Backend Services
| File | Responsibility |
|---|---|
app/Services/MayaService.php | Raw HTTP calls to Maya API |
app/Services/MayaTransactionService.php | Maya business logic — initiate, charge, webhook handling |
app/Services/PayMongoService.php | Raw HTTP calls to PayMongo API |
app/Services/PayMongoTransactionService.php | PayMongo business logic — initiate, charge, vault, webhook handling |
app/Services/FeeCalculator.php | Gateway-agnostic fee computation |
Checkout Flow (High Level)
- User selects a campaign and donation amount on
/donate - Frontend posts to
POST /api/v1/donationswithpayment_gateway: 'maya'(or'paymongo') - Backend creates a
pendingDonation record and calls the selected gateway's checkout API - Backend returns
{ redirectUrl }— frontend redirects the browser to the hosted payment page - User completes payment
- Gateway redirects back and fires a webhook
- Webhook handler marks the donation
completedand increments campaign balances
See Donation Flow for the full step-by-step sequence.
Saved Card Flow (High Level)
Maya
- Frontend tokenizes the card directly against Maya's API (
/payments/v1/payment-tokens) using the public key — card data never touches Batchmates servers - Frontend sends the resulting
paymentTokenIdtoPOST /api/v1/payment-methods/maya/link-card - Backend creates a Maya customer (or reuses existing) and vaults the card token
- User donates via
POST /api/v1/donations/charge-saved/mayawith the saved payment method ID - If 3DS is required, an
action_urlis returned — user completes authentication, then the success redirect finalises the donation
PayMongo
- Frontend tokenizes the card directly against PayMongo's API (
/payment_methods) using the public key — card data never touches Batchmates servers — producing apm_...id - Frontend sends the
pm_...id toPOST /api/v1/payment-methods/paymongo/link-card - Backend creates a PayMongo customer (or reuses existing) and runs a ₱25 card verification charge with
setup_future_usageto vault the card (PayMongo has no zero-amount setup intent) - User donates via
POST /api/v1/donations/charge-saved/paymongowith the saved payment method ID and the card CVC (PayMongo requires CVC re-entry on every charge) - If 3DS is required, an
action_urlis returned — user authenticates, then the intent-return redirect finalises the donation
See Maya Saved Cards for Maya vaulting, and PayMongo Saved Cards for PayMongo.
API Endpoint Reference
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /api/v1/donations | Sanctum | Create donation + initiate Maya or PayMongo checkout |
| POST | /api/v1/donations/charge-saved/maya | Sanctum | Charge a vaulted Maya card |
| POST | /api/v1/donations/charge-saved/paymongo | Sanctum | Charge a vaulted PayMongo card (requires CVC) |
| POST | /api/v1/donations/{id}/pay/paymongo | Sanctum | Retry a failed/expired PayMongo donation |
| POST | /api/v1/payment-methods/maya/link-card | Sanctum | Vault a Maya payment token |
| POST | /api/v1/payment-methods/paymongo/link-card | Sanctum | Vault a PayMongo card (via pm_... id) |
| GET | /api/v1/payment-methods | Sanctum | List user's saved cards |
| DELETE | /api/v1/payment-methods/{id} | Sanctum | Remove a saved card |
| POST | /api/v1/payment-methods/{id}/set-default | Sanctum | Set default card |
| GET | /api/v1/payments/maya/success | Public | Maya post-checkout / post-3DS success redirect |
| GET | /api/v1/payments/maya/failure | Public | Maya post-checkout failure redirect |
| GET | /api/v1/payments/maya/cancel | Public | Maya post-checkout cancel redirect |
| POST | /api/v1/payments/maya/webhook | IP allowlist | Maya event webhook |
| GET | /api/v1/payments/paymongo/success | Public | PayMongo post-checkout success redirect |
| GET | /api/v1/payments/paymongo/cancel | Public | PayMongo post-checkout cancel redirect |
| GET | /api/v1/payments/paymongo/intent-return | Public | PayMongo saved-card 3DS return |
| GET | /api/v1/payments/paymongo/vault-return | Public | PayMongo card-vaulting 3DS return |
| POST | /api/v1/payments/paymongo/webhook | Webhook sig | PayMongo event webhook |
Further Reading
- Donation Flow — complete checkout lifecycle
- Maya Checkout · Maya Saved Cards
- PayMongo Checkout · PayMongo Saved Cards
- Webhooks — event handling across gateways
- Fee Structure — convenience and system fee calculation