Payments failing
Fix failed payments and billing states — AutoPay problems, provider configuration, webhook delivery, reconciliation alerts and the grace-to-suspension lifecycle.
Payments failing
A payment failed, AutoPay will not set up, or a workspace got restricted/suspended over billing. The commercial billing stack has two sides: the workspace (paying, fixing a failed method) and the super admin (provider configuration, webhook health, reconciliation). Identify which side the problem is on before changing anything.
Who this is for: workspace admins getting billing right, and super admins running commercial billing.
Problem
A charge did not go through, a subscription state changed against expectations, or the tenant portal shows a payment problem that will not clear.
What you see
| Symptom | Where |
|---|---|
| Payment-failed messaging and a retry/re-check flow | Tenant Admin → Billing (/admin/billing) |
Redirect to /admin/subscription-required (reason=suspended) |
Tenant users after suspension |
| Restriction to the billing page only | Tenant during restriction (e.g. trial expired) |
| AutoPay shows unapproved, or REQUIRES_NEW_AUTHORIZATION | Admin → Billing → Agreement (/admin/billing/agreement) |
payment_failures / grace_period / restricted / suspended counts rising |
Super Admin Billing → Commercial (/super-admin/billing/commercial) |
| A reconciliation alert on the billing overview | Billing overview → Needs Attention (BillingReconciliationAlert, raised every 30 minutes) |
| Webhook deliveries absent or rejected | Provider dashboard / server log |
Likely causes
- The payment method itself: card declined, expired, insufficient limit, or bank-side block.
- AutoPay mandate not approved — a mandate that needs a new authorisation shows as REQUIRES_NEW_AUTHORIZATION and must be re-authorised, not "retried".
- Provider configuration drift (super admin): wrong environment (
sandboxvsproduction), wrong or rotated keys, or a webhook secret that no longer matches — the classic cause of "money moved but the CRM does not know". - Webhooks not delivered: provider cannot reach
POST /api/webhooks/razorpayorPOST /api/webhooks/cashfree(firewall, DNS, cron.php/.htaccessweirdness on shared hosts). - Status drift: provider and CRM disagree — exactly what the reconciliation alert exists to flag.
- Lifecycle timing: even a fixed payment does not teleport the workspace out of suspension instantly — lifecycle jobs run on a daily schedule.
Quick fix
- Workspace: open Admin → Billing (
/admin/billing), read the banner, and complete the offered action — usually re-authorising AutoPay or paying the open invoice. The page's "re-check" flow re-queries the provider; use it before panicking. - Super admin: open Super Admin → Billing → Commercial (
/super-admin/billing/commercial) → Payments (/super-admin/billing/commercial-payments) and find the failed attempt; the provider's message is attached. - Clear reconciliation alerts deliberately — each one records a real disagreement between provider and CRM.
Step-by-step fix
- Classify the failure. Workspace-level (a person must act: pay, re-authorise) or platform-level (configuration/webhooks). If several workspaces fail at once, assume platform-level and go to step 3.
- Workspace actions:
- Admin → Billing shows the current state and the required action. Pay the outstanding invoice under Billing → Invoices (
/admin/billing/invoices); review history under Billing → Payments (/admin/billing/payments). - AutoPay: check the agreement status.
REQUIRES_NEW_AUTHORIZATIONmeans the old mandate is dead — set up AutoPay again from the billing home. - After acting, use the re-check action so the CRM asks the provider for fresh status rather than waiting for the next reconciliation pass.
- Admin → Billing shows the current state and the required action. Pay the outstanding invoice under Billing → Invoices (
- Provider configuration (super admin): Billing → Commercial Providers (
/super-admin/billing/commercial-providers). Verify the enabled toggle (commercial_billing_enabled), the provider (razorpayorcashfree), the environment (sandboxvsproduction— check twice), keys (Razorpay key id/secret; Cashfree app id/secret/webhook secret), andgrace_period_days(default 7). - Webhooks: confirm the provider is configured to send webhooks to this install's
POST /api/webhooks/razorpay/POST /api/webhooks/cashfree, and that they are being accepted — signatures are verified, and duplicates are ignored safely (idempotent processing, tracked for 90 days). A silent webhook endpoint means the CRM never learns the payment succeeded; the reconciliation alert then fires. - Understand the lifecycle: when a payment stays failed, the workspace moves grace → restriction → suspension. These transitions run on the daily schedule — grace application 07:15, restriction 07:30, and the subscription lifecycle sweep at 06:00 — so a fix applied today may not reflect until the next run. Do not "fix" it by manual database edits.
- Suspension behavior to expect (and to explain): logged-in users are redirected to
/admin/subscription-required, and mobile/sign-in might still work while the workspace is blocked at the door — login itself stays allowed so people can reach the billing pages. Once paid and reconciled, access returns. - Invoices and renewals: renewal invoices are generated on schedule (06:30) and recurring invoices processed at 07:00 (
invoices:process-recurring); upcoming renewals are checked at the same time. If an invoice is missing, it may simply not be due yet — check the next renewal date first.
Do not chase single events — read the alert queue One payment failure is an incident for one customer. Several simultaneous failures, or a reconciliation alert that keeps re-raising, is a platform problem. Treat them differently.
Admin fix
- Tenant admins can do everything on
/admin/billingand sub-pages: pay, re-authorise AutoPay, use re-check, review invoices/payments. - If the billing page offers nothing to click, the decision is not theirs to make — the workspace owner/super admin must verify the provider configuration.
Developer fix
- Webhooks:
POST /api/webhooks/razorpayandPOST /api/webhooks/cashfree; signature-verified; idempotency viaprocessed_billing_events(retained 90 days — duplicates arriving late are ignored, not double-counted). - Reconciliation: runs every 30 minutes; disagreements become
BillingReconciliationAlertrows shown on the billing overview's "Needs Attention". - Lifecycle:
leadhub:subscription-lifecycledaily 06:00;ApplyGracePeriod07:15;ApplyRestriction07:30;ApplyRestriction/suspension behavior enforced byEnforceNotSuspended+EnforceSubscriptionwith state fromTenantSubscriptionState. - Suspension redirect target:
/admin/subscription-requiredwithreason=suspended; when reconciling a workspace state, check what the provider actually says before overriding anything.
Logs to check
storage/logs/laravel.log— webhook signature failures, provider API errors, reconciliation errors.- Billing → Commercial → Payments — per-attempt provider messages.
processed_billing_eventsrow timestamps — confirm whether the provider's webhook reached you at all.- Provider dashboards (Razorpay/Cashfree) — the ground truth on charge attempts and webhook delivery.
When to escalate
- Webhooks are delivered by the provider but rejected by the server — secret mismatch or signature bug; a developer should compare payload and signature.
- Money collected but the workspace never reactivated after a reconciliation cycle — treat as SEV1, escalate to the super admin with the payment id.
- Multiple workspaces failing simultaneously — platform-level (provider config, keys, webhook endpoint), escalate immediately.
Related guides
Was this page helpful?
Thanks — noted. ✦