Fee Structure

How donation fees are calculated, what rates apply per payment method, and how the total charged amount is derived.

Source files: app/Services/FeeCalculator.php · config/fees.php · app/Http/Controllers/Api/DonationController.php


Two components, always kept separate

Every donation carries two distinct fee lines, stored separately on the Donation record and never summed into one "fee":

ComponentMeaningColumn
convenience_feeThe payment gateway's own processing fee (MDR), passed through to the donordonations.convenience_fee
system_feeBatchmates' platform service feedonations.system_fee

convenience_fee is a pass-through cost, not platform income — see Financial Reports for how reporting keeps this separate from actual revenue (system_fee).


Fee Rates — by gateway and method

Donors select a payment method in the UI before checkout, so the exact published rate for that method is charged — there is no more flat "hosted checkout" rate.

PayMongo — by method

MethodRateFixedEnv keys
Card (domestic Visa/MC)3.125%₱13.39PAYMONGO_CARD_RATE, PAYMONGO_CARD_FIXED
GCash2.23%—PAYMONGO_GCASH_RATE, PAYMONGO_GCASH_FIXED
Maya (e-wallet)1.79%—PAYMONGO_PAYMAYA_RATE, PAYMONGO_PAYMAYA_FIXED
GrabPay1.96%—PAYMONGO_GRABPAY_RATE, PAYMONGO_GRABPAY_FIXED
QR Ph1.34%—PAYMONGO_QRPH_RATE, PAYMONGO_QRPH_FIXED
unknown (fallback only)3.125%₱13.39PAYMONGO_FALLBACK_RATE, PAYMONGO_FALLBACK_FIXED

Platform service fee

Env keyDefault
APP_SERVICE_FEE_RATE1.5%

Environment Variables

# .env

APP_SERVICE_FEE_RATE=0.015

# PayMongo — per method (paymongo.com/pricing)
PAYMONGO_CARD_RATE=0.03125
PAYMONGO_CARD_FIXED=13.39
PAYMONGO_GCASH_RATE=0.0223
PAYMONGO_GCASH_FIXED=0.0
PAYMONGO_PAYMAYA_RATE=0.0179
PAYMONGO_PAYMAYA_FIXED=0.0
PAYMONGO_GRABPAY_RATE=0.0196
PAYMONGO_GRABPAY_FIXED=0.0
PAYMONGO_QRPH_RATE=0.0134
PAYMONGO_QRPH_FIXED=0.0
PAYMONGO_FALLBACK_RATE=0.03125
PAYMONGO_FALLBACK_FIXED=13.39

# Platform operating cost — reporting only, never charged to donors
PAYMONGO_PAYOUT_FEE=10.0

Usage

// app/Services/FeeCalculator.php

$fees = FeeCalculator::calculate('paymongo', 1000.00, 'gcash');
// [
//   'convenience_fee' => 22.30,   // 2.23% × 1000
//   'system_fee'      => 15.00,   // 1.5% × 1000
//   'total_amount'    => 1037.30,
// ]

POST/api/v1/donations/quote

Fee Quote Endpoint

Server-authoritative fee preview. Creates and persists nothing — it calls the exact same FeeCalculator::calculate() path the real charge uses, so the quoted total can never drift from what's actually charged. Safe to call on every keystroke; rate-limited to guard against abuse.

Authentication: Not required (same public/optional-auth route group as donation creation)

Rate limit: throttle:30,1 (30 requests/minute)

Request Body

  • Name
    amount
    Type
    number
    Description

    Base donation amount, ₱1–₱99,999,999.99, up to 2 decimal places

  • Name
    payment_gateway
    Type
    string
    Description

    Must be paymongo

  • Name
    payment_method
    Type
    string
    Description

    card | gcash | paymaya | grab_pay | qrph

Request

{
  "amount": 1000,
  "payment_gateway": "paymongo",
  "payment_method": "gcash"
}

Response

{
  "success": true,
  "data": {
    "amount": 1000,
    "convenience_fee": 22.30,
    "system_fee": 15.00,
    "total_amount": 1037.30,
    "breakdown": {
      "gateway_label": "GCash",
      "rate_percent": 2.23,
      "fixed_fee": 0,
      "service_fee_percent": 1.5
    }
  }
}

Error (missing method for PayMongo)

{
  "message": "The given data was invalid.",
  "errors": {
    "payment_method": ["The payment method field is required."]
  }
}

Worked Examples

PayMongo — ₱1,000 donation, GCash

ComponentCalculationAmount
Base amount—₱1,000.00
Transaction Fee/s (convenience)₱1,000 × 2.23%₱22.30
Platform Service Fee (system)₱1,000 × 1.5%₱15.00
Total charged₱1,037.30
Campaign receives—₱1,000.00

PayMongo — ₱1,000 donation, Card

ComponentCalculationAmount
Base amount—₱1,000.00
Transaction Fee/s₱1,000 × 3.125% + ₱13.39₱44.64
Platform Service Fee₱1,000 × 1.5%₱15.00
Total charged₱1,059.64
Campaign receives—₱1,000.00

Recurring (Subscription) Donations

PayMongo subscriptions bill the fee-inclusive total, not just the base pledge — the PayMongo Plan is created for FeeCalculator::calculate('paymongo', $amount, 'card')['total_amount'] (subscriptions are always billed against a vaulted card, so the card tier applies). Each subscription.invoice.paid webhook re-derives the same convenience_fee/system_fee/total_amount split from the subscription's stored base amount, and credits the campaign by the base amount only — fees are platform revenue, same as one-time donations.

See app/Services/PayMongoSubscriptionService.php (createSubscription(), handleInvoicePaid()).


What Gets Sent to the Gateway

'amount' => (int) round($fees['total_amount'] * 100), // integer centavos

PayMongo hosted checkout also narrows payment_method_types to a single-element array containing the donor's chosen method — the amount quoted is guaranteed to be the only method PayMongo's page will actually offer:

'payment_method_types' => [$donation->payment_method], // e.g. ['gcash']

What Gets Credited to the Campaign

Campaign balances are incremented by the base donation amount only — fees are excluded, for both one-time and recurring donations:

$campaign->increment('raised_amount', $donation->amount);   // base amount
$campaign->increment('available_amount', $donation->amount); // base amount

Donation Record Fields

FieldValue
amountBase donation (what the donor intended to give; what the campaign is credited)
payment_methodThe method actually charged — card, gcash, paymaya, grab_pay, qrph
convenience_feeGateway processing fee for that method
system_feePlatform service fee
total_amountSum of the above three — what is actually charged

Was this page helpful?