What this is for#
AcelleMail's Cashier (the subscription billing layer) supports Stripe as the first-class payment gateway. PayPal and other gateways were removed in the recent Cashier consolidation — Stripe + Offline (manual) are what's supported today.
This guide walks the connection end-to-end. If you're setting up a full SaaS platform, Stripe is one step in that larger setup; this article covers the Stripe-specific configuration in depth.
Prerequisites#
- An AcelleMail install with the Extended License (required for SaaS / paid-subscription use)
- A Stripe account (https://dashboard.stripe.com) — start in test mode, switch to live after validating
- Comfortable with the Stripe Dashboard's basic navigation
Step 1 — Get your Stripe API keys#
In Stripe Dashboard:
- Click Developers → API keys
- Note your Publishable key (
pk_test_... in test mode, pk_live_... in live mode)
- Click Reveal test key next to "Secret key" to see your Secret key (
sk_test_... / sk_live_...)
Test mode first, always. Set up the whole integration in test mode (test cards, test webhooks). Validate every flow end-to-end. THEN switch to live mode — never go straight to live with new gateway code.
Step 2 — Configure Stripe in AcelleMail#
In AcelleMail Admin:
- Payment Gateways → Stripe → Edit
- Paste:
- Publishable Key — from Step 1
- Secret Key — from Step 1
- Mode —
test (for now)
- Currency — must match your Stripe account default currency
- Save (leave Webhook Secret blank for now — we'll set it after creating the webhook in Step 3)
- Click Enable on the Stripe gateway
Disable other gateways you're not using. AcelleMail shows every enabled gateway in the customer's plan-checkout flow. Leaving inactive ones enabled creates confusing UX.
Step 3 — Set up the Stripe webhook#
This is the most-skipped step, and without it, renewals + cancellations don't sync back to AcelleMail.
- AcelleMail Admin → Payment Gateways → Stripe → after saving, AcelleMail shows the webhook URL you'll use. Format:
https://your-acellemail-domain.com/stripe/webhook. Copy it.
- Stripe Dashboard → Developers → Webhooks → Add endpoint
- Endpoint URL — paste the URL from step 1
- Events to send — select these 6 events (each one matters):
| Stripe event |
Why AcelleMail needs it |
customer.subscription.created |
Initial subscription activation — flips customer's plan status to active |
customer.subscription.updated |
Plan changes, status changes (trialing → active) |
customer.subscription.deleted |
Cancellation — downgrades customer to default free plan |
invoice.paid |
Successful renewal — extends customer's billing period |
invoice.payment_failed |
Failed renewal — triggers dunning (retry + customer notification) |
payment_intent.succeeded |
One-off payment confirmation (for non-subscription flows) |
- After clicking "Add endpoint", Stripe shows you a Signing Secret (
whsec_...). Copy it.
- Back in AcelleMail → Payment Gateways → Stripe → paste the Signing Secret into the Webhook Secret field
- Save
Step 4 — Test the round-trip#
In test mode:
- Acelle: Admin → Plans → Add new — create a test plan, e.g.
Test Plan at $1/month
- Log in as a test customer (or use a different browser)
- Customer Dashboard → Subscribe to the test plan
- Stripe Checkout opens → use test card
4242 4242 4242 4242, any future expiry, any CVC, any ZIP
- Click Pay
- You should be redirected back to AcelleMail with subscription active
Verify each side:
- Stripe Dashboard → Customers — new customer with active subscription
- Stripe Dashboard → Developers → Webhooks → click your endpoint — should show 3 successful POST attempts (
customer.subscription.created, invoice.paid, payment_intent.succeeded) within seconds
- AcelleMail → Customers → your test customer — Plan = Test Plan, Status = Active
If all three are green, the integration is working. Make a refund in Stripe (Test Customer → Refund) to verify the cancellation flow as well.
Step 5 — Switch to live mode#
When test mode is fully validated:
- Stripe Dashboard → toggle Test mode to Live mode (top-right)
- Get your live keys (Developers → API keys)
- Create a NEW webhook endpoint in live mode (test webhooks don't carry over) — same URL, same 6 events
- Get the live webhook signing secret
- AcelleMail → Payment Gateways → Stripe → swap to live keys + live webhook secret
- Save + repeat the Step 4 test using a real card (smallest amount — refund it after)
- Watch the live webhook deliveries on Stripe Dashboard for the first day to catch any issues
Plan design considerations#
In AcelleMail's plan editor:
- Price + currency — must match the currency of your Stripe account
- Frequency —
1 month, 1 year, 3 months, etc. — Stripe creates the right recurring price internally
- Trial period — e.g.
14 + day — Stripe handles the trial; customers aren't charged until trial end
- Plans visible — toggle off to hide a plan from the public pricing page (useful for legacy / promo plans)
Tip: create both monthly + annual variants of each plan, with annual at ~17% discount. Annual conversion meaningfully reduces churn — see the Building Your SaaS guide for pricing-ladder advice.
Plan migrations#
When you change a plan's price or limits in Stripe:
- Existing subscribers stay on their old terms until their next renewal
- New subscribers get the new terms immediately
- Acelle's
subscription:monitor daily task reconciles state — usually within 24 hours
When you change a plan's options JSON (quotas) in Acelle:
- Changes apply to ALL subscribers (active and new) immediately
- This is one-way: dropping the customer's quota mid-billing-period is bad UX; bump quotas on new plans only
Refunds + disputes#
- Refund issued in Stripe → triggers
charge.refunded event. AcelleMail does NOT auto-cancel the subscription on refund (refunding the latest charge doesn't necessarily end service). To stop service, also cancel the subscription in Stripe.
- Dispute / chargeback → triggers
charge.dispute.created. Manual review required. Acelle doesn't auto-suspend on dispute, but you should suspend manually pending the dispute outcome.
One-off payments (not subscriptions)#
For Acelle's sending-credit / email-verification-credit products, Stripe handles one-off Payment Intents (not subscriptions). The webhook event for these is payment_intent.succeeded (you subscribed to it in Step 3).
Common issues#
| What you see |
Likely cause |
Fix |
| Stripe Checkout opens but customer is never charged |
Test card declined OR webhook not configured (Acelle doesn't know it succeeded) |
Use 4242 4242 4242 4242 for testing; verify Stripe Dashboard → Webhooks shows your endpoint with deliveries |
| Customer paid in Stripe but Acelle subscription status stays "new" |
Webhook signing secret mismatch — Acelle rejects the webhook |
Re-copy whsec_... from Stripe to AcelleMail; verify exact match |
| Renewal happens in Stripe but Acelle doesn't extend the period |
invoice.paid event missing from webhook subscription |
Edit webhook in Stripe → Add invoice.paid event |
| Failed payment doesn't trigger dunning emails |
invoice.payment_failed missing OR Acelle's mail templates not configured |
Add the event; verify Admin → System Emails → Payment Failed template exists |
| Customer downgrades plan but quotas don't drop |
Acelle's subscription:monitor cron hasn't run yet |
Wait for the next run (hourly), or trigger manually: php artisan subscription:monitor |
| 404 on the webhook URL |
Acelle install URL changed OR APP_URL in .env is wrong |
Check https://your-domain/stripe/webhook is reachable; verify APP_URL |
| Webhook works in test mode, breaks in live mode |
Forgot to set up a separate live-mode webhook |
Create live webhook in Stripe Dashboard live mode; swap signing secret |
| Stripe says "no such event" |
Stripe API version mismatch — your account's default API version is too old |
Stripe Dashboard → Developers → API version → Update to latest |
| Customer with 2FA on Stripe can't pay |
3DS challenge not handled correctly |
Use Stripe's modern Checkout (default in 2026) which handles 3DS natively |
FAQ#
Why is PayPal not supported? The current Acelle Cashier (post-refactor) supports Stripe + Offline only. PayPal recurring subscriptions are operationally messier (no webhook for failed payments, currency conversion overhead, no first-class trial support). If you need PayPal, use Offline mode with manual reconciliation, OR set up Stripe's PayPal pass-through (Stripe can charge PayPal as a payment method on their side).
Can I use Stripe Tax? Yes — enable in Stripe Dashboard. Acelle's invoice flow uses Stripe's tax calculation automatically once enabled.
Can I use Stripe Billing's coupons? Yes — configure coupons in Stripe Dashboard; pass the coupon code via the customer's checkout URL. AcelleMail's UI doesn't have a coupon field directly; you'd need to extend the checkout flow (see extending source code).
Charging in multiple currencies? Each AcelleMail plan has one currency. Create parallel plans in each currency (e.g. "Pro $79" and "Pro €72"). Customer's billing currency is locked to the plan they signed up on.
Migrating from another billing system? Export Stripe customer + subscription records via Stripe's CSV export. Acelle has no built-in import for Stripe data; you'd need a one-off script that creates Acelle customer records + links them via stripe_customer_id metadata field. Talk to support before doing this at scale.
GDPR / right-to-erasure? When a customer requests deletion: Stripe's data retention is governed by Stripe's own GDPR processes (you can request deletion via Stripe Dashboard → Customer → Actions → Forget). AcelleMail-side data deletion is via Admin → Customers → Delete.
Is there a TestStripe / Stripe sandbox UI for verification? Use Stripe's test mode (Step 1's pk_test_ / sk_test_ keys). Test cards from https://stripe.com/docs/testing.
Related articles#