Documentation for larsasub v0.38.2.
On an older version? Your release notes ship with the package (CHANGELOG.md).
Routes and webhooks
Every route the package registers, with its verb, default URL and name. Use this page when you link to a bundled page, register a webhook or redirect URI at Mollie, or put your own middleware in front of the billing pages.
- Before you start
- Subscriber dashboards
- Management dashboards
- Post-payment redirects
- Mollie Connect
- Provider webhooks
- Middleware
Before you start
Every URL below is the default. The route names are stable: link to those, never to a hard-coded path.
- Each dashboard's prefix is configurable under
larsasub.standalone.url. - Each dashboard can be switched off under
larsasub.standalone.dashboards; its routes are then not registered at all, so checkRoute::has()before you link to one. - The redirect routes, the Connect routes and the webhooks are not dashboard
routes: no
standalone.urlorstandalone.dashboardskey affects them.
| Dashboard | Toggle (standalone.dashboards.*) |
URL key (standalone.url.*) |
Default prefix |
|---|---|---|---|
| Subscription | subscription |
subscription-dashboard |
billing/dashboard |
| Payments | payments |
payments-dashboard |
billing/payments |
| Payment methods | payment_methods |
payment-methods-dashboard |
billing/payment-methods |
| Credit | credit |
credit-dashboard |
billing/credit |
| Profile | profile |
profile-dashboard |
billing/profile |
| Invoices | invoices |
invoices-dashboard |
billing/invoices |
| Plans (admin) | tenant_subscriptions |
tenant-subscriptions-dashboard |
billing/admin/subscriptions |
| Subscribers (admin) | tenant_subscribers |
tenant-subscribers-dashboard |
billing/admin/subscribers |
| Charges (admin) | tenant_charges |
tenant-charges-dashboard |
billing/admin/charges |
| Invoices (admin) | tenant_invoices |
tenant-invoices-dashboard |
billing/admin/invoices |
| Mollie connection (admin, Connect only) | tenant_connect |
tenant-connect-dashboard |
billing/admin/connect |
| Application fees (admin, Connect only) | tenant_fees |
tenant-fees-dashboard |
billing/admin/fees |
The two invoice dashboards also need larsasub.invoicing.enabled (off by
default), and the two Connect-only dashboards need connect.enabled. See
Standalone dashboards.
Subscriber dashboards
The pages a customer uses to manage their own subscription, payments, payment methods, credit, profile and invoices.
| Verb | URL | Route name |
|---|---|---|
| GET | /billing/dashboard |
larsasub.my-subscription.view |
| POST | /billing/dashboard/create |
larsasub.my-subscription.create |
| PUT | /billing/dashboard/cancel/{subscription} |
larsasub.my-subscription.cancel |
| DELETE | /billing/dashboard/terminate/{subscription} |
larsasub.my-subscription.terminate |
| POST | /billing/dashboard/retry-first-payment/{subscription} |
larsasub.my-subscription.retry-first-payment |
| PUT | /billing/dashboard/change/{currentSubscription}/{newSubscription} |
larsasub.my-subscription.change |
| GET | /billing/dashboard/terms |
larsasub.my-subscription.terms |
| GET | /billing/payments |
larsasub.my-payments.view |
| GET | /billing/payments/charges/{charge}/start-payment |
larsasub.my-payments.manual-charge-payment |
| GET | /billing/payments/single-payments/{singlePayment}/start-payment |
larsasub.my-payments.single-payment |
| GET | /billing/payments/charges/{charge}/invoice |
larsasub.my-payments.charge-invoice |
| GET | /billing/payments/single-payments/{singlePayment}/invoice |
larsasub.my-payments.single-payment-invoice |
| GET | /billing/payment-methods |
larsasub.my-payment-methods.view |
| POST | /billing/payment-methods/{paymentMethod} |
larsasub.my-payment-methods.create |
| DELETE | /billing/payment-methods/{mandateId} |
larsasub.my-payment-methods.delete |
| PATCH | /billing/payment-methods/subscription/{subscriptionId}/mandate/{mandateId} |
larsasub.my-payment-methods.switch-mandate |
| GET | /billing/credit |
larsasub.my-credit.view |
| GET | /billing/profile |
larsasub.my-profile.view |
| PUT | /billing/profile |
larsasub.my-profile.update |
| GET | /billing/invoices |
larsasub.my-invoices.view |
| GET | /billing/invoices/invoices/{invoice}/download |
larsasub.my-invoices.download |
| GET | /billing/invoices/credit-notes/{creditNote}/download |
larsasub.my-invoices.download-credit-note |
The route named
terminatedeletes, and only a failed first payment. It callsBillableSubscriptionService::terminateFailedSubscription(), which deletes a subscription whose first payment failed — and refuses while a claimed payment attempt is still live. The admin hammerterminateSubscription()is deliberately not routed. See Subscriptions.
The retry-first-payment route refuses a plan that is deleted or no longer
active, because the frozen price is no longer on sale; the dashboard hides
the button in that case and offers the plan picker instead.
my-payment-methods.create starts the €0,01 mandate verification. A repeat
click while that verification is still being started answers a JSON request
with 409 and a "wait a moment and reload" message (a browser request gets
the message back as a validation error) — see
Setting up a mandate.
Management dashboards
The operator pages: plans, subscribers, charges and invoices. They are
mode-aware: in Connect mode they belong to the tenant owner and show that
tenant's data; in simple mode they are operator management, authorized through
policies.admin_role. See
Admin dashboard authorization.
| Verb | URL | Route name |
|---|---|---|
| GET | /billing/admin/subscriptions |
larsasub.tenant-subscriptions.view |
| POST | /billing/admin/subscriptions |
larsasub.tenant-subscriptions.store |
| PUT | /billing/admin/subscriptions/{subscription} |
larsasub.tenant-subscriptions.update |
| PATCH | /billing/admin/subscriptions/{subscription}/toggle |
larsasub.tenant-subscriptions.toggle |
| DELETE | /billing/admin/subscriptions/{subscription} |
larsasub.tenant-subscriptions.destroy |
| POST | /billing/admin/subscriptions/{subscription}/change-targets |
larsasub.tenant-subscriptions.change-targets |
| GET | /billing/admin/subscribers |
larsasub.tenant-subscribers.view |
| GET | /billing/admin/charges |
larsasub.tenant-charges.view |
| GET | /billing/admin/charges/lookup |
larsasub.tenant-charges.lookup |
| GET | /billing/admin/invoices |
larsasub.tenant-invoices.view |
| GET | /billing/admin/invoices/invoices/{invoice}/download |
larsasub.tenant-invoices.download |
| GET | /billing/admin/invoices/credit-notes/{creditNote}/download |
larsasub.tenant-invoices.download-credit-note |
Connect mode only:
| Verb | URL | Route name |
|---|---|---|
| GET | /billing/admin/connect |
larsasub.tenant-connect.view |
| PATCH | /billing/admin/connect/payment-methods/{paymentMethod} |
larsasub.tenant-connect.toggle-payment-method |
| GET | /billing/admin/fees |
larsasub.tenant-fees.view |
tenant-connect.toggle-payment-method switches a payment method on or off for
the tenant; what it checks is under
Tenant availability.
Post-payment redirects
Where the customer's browser lands when it comes back from the provider. These routes are always registered, whatever the dashboard toggles say.
| Verb | URL | Route name |
|---|---|---|
| GET | /larsasub/redirects/first-payment/{charge} |
larsasub.redirect.first-payment |
| GET | /larsasub/redirects/manual-charge-payment/{charge} |
larsasub.redirect.manual-charge-payment |
| GET | /larsasub/redirects/mandate-setup/{charge?} |
larsasub.redirect.mandate-setup |
| GET | /larsasub/redirects/single-payment/{singlePayment} |
larsasub.redirect.single-payment |
These URLs are embedded in payments at the provider, so they run on the plain
web middleware, outside standalone.middleware and standalone.domain.
A customer returning from their bank in a fresh browser session has to land
somewhere.
Each one forwards to the destination configured under larsasub.redirect: a
named route (the default) or an invokable class that computes the URL from the
context that key carries — a RecurringCharge on the three charge keys, a
SinglePayment on single_payment, the tenant model on connect_callback.
The table under Redirect routes is the
authority on which key gets what.
These endpoints are unauthenticated, and the bound model is not ownership-checked. Route on the model; never render its data. Read the security note under Redirect routes.
{charge?} on the mandate-setup route is optional and must stay so: that
URL is baked into every €0,01 mandate verification before the customer leaves
for their bank, so any verification still open when you deploy carries the
old, segment-less URL.
Mollie Connect
The OAuth onboarding and disconnect endpoints. They are registered only when
connect.enabled is true, under the /api prefix.
| Verb | URL | Route name |
|---|---|---|
| GET | /api/larsasub/connect/mollie/authorize/{tenant} |
larsasub.mollie.connect.authorize |
| GET | /api/larsasub/connect/mollie/callback |
larsasub.mollie.connect.callback |
| GET | /api/larsasub/connect/mollie/complete |
larsasub.mollie.connect.complete |
| DELETE | /api/larsasub/connect/mollie/disconnect |
larsasub.mollie.connect.disconnect |
| POST | /api/larsasub/connect/mollie/cancel-disconnect |
larsasub.mollie.connect.cancel-disconnect |
The OAuth routes
authorize is throttled (10 per minute) and only lets the tenant's owner in.
It also takes a tenant that is already connected: that is how a tenant
re-authorises to grant a scope added since — see
Re-authorising a connected tenant.
connect.authorize_route names this route by default; point it at your own
route if you wrap the start of the flow.
callback is the redirect URI you register in your Mollie Connect app:
https://your-app.example/api/larsasub/connect/mollie/callback
It is built from config('app.url') (or from LARSASUB_NGROK_DOMAIN in a
local/development environment). It deliberately runs without the
dashboard middleware and without the standalone.domain constraint, because
the OAuth return can arrive on a different origin than the one the user
authorized from. It does not complete the connection: it hands off to
complete, which runs on the authenticated origin. See
The OAuth flow.
The disconnect routes
disconnect and cancel-disconnect require the tenant owner and take the
tenant's key as tenant, in the query string or the body. This is the URL the
bundled dashboard is given:
route('larsasub.mollie.connect.disconnect', ['tenant' => $tenant->getKey()]);
disconnect takes mode:
mode |
What it does |
|---|---|
drain (default) |
Requests the disconnect: the account drains, or goes at once when nothing is under way |
now |
Removes the connection at once and flags what is still under way |
cancel-disconnect calls a draining disconnect off.
Both answer {"success": true, "disconnect": {…}} with
DisconnectImpact::toArray(), or 422 with a translated error when there is
nothing to disconnect, nothing draining, or an unknown mode. Key on the
status code, not the message. See
Disconnecting a tenant.
Provider webhooks
The URLs Mollie calls when a payment changes status. The package puts the right webhook URL on every payment it creates, so there is nothing to register at Mollie for these.
They are unauthenticated by design — the provider calls them — with CSRF
verification removed and an IP throttle from larsasub.webhooks.rate_limit
(LARSASUB_WEBHOOK_RATE_LIMIT, default '300,1'; null disables it). A
throttled-away webhook is a missed status until Mollie retries, so keep the
limit generous.
POST /api/larsasub/webhooks/mollie/{method}/first-payment
POST /api/larsasub/webhooks/mollie/{method}/recurring-charge
POST /api/larsasub/webhooks/mollie/{method}/single-payment
POST /api/larsasub/webhooks/mollie/{method}/manual-charge-payment
{method} is the Mollie method key. The route names follow the same pattern:
larsasub.mollie.{method}.process-first-payment,
…process-recurring-charge, …process-single-payment and
…process-manual-charge-payment.
The set registered depends on what the method supports:
| Method | {method} |
Webhooks |
|---|---|---|
| Credit card, PayPal — recurring in their own right | creditcard, paypal |
first-payment, recurring-charge, single-payment, manual-charge-payment |
| SEPA Direct Debit | directdebit |
first-payment, recurring-charge |
| iDEAL, Bancontact, Apple Pay, KBC/CBC, Belfius, EPS, TWINT | ideal, bancontact, applepay, kbc, belfius, eps, twint |
single-payment, manual-charge-payment |
iDEAL opening a SEPA mandate does not land on the iDEAL routes. When
first_payment_method_idpoints at iDEAL (the default for direct debit), the checkout runs at Mollie in iDEAL but the charge belongs to Direct Debit, so its webhook arrives onlarsasub.mollie.directdebit.process-first-payment. The same holds for Bancontact as the mandate opener. Only credit card and PayPal own afirst-paymentroute under their own key.
Mandate-setup payments (the €0,01 verification) have no dedicated webhook:
they arrive on the recurring method's first-payment webhook.
There is deliberately no public route that starts a manual charge payment.
That is a money action and lives behind auth and policy in the payments
dashboard (larsasub.my-payments.manual-charge-payment), never in the webhook
group.
The routes come from the provider configured in larsasub.provider. A
provider of your own registers its own webhook routes — see
Adding your own provider.
Middleware
Which middleware each group runs on, and which config keys reach it.
| Routes | Middleware | standalone.domain applies |
|---|---|---|
| Every dashboard route | standalone.middleware — the complete stack |
Yes |
Connect authorize, complete, disconnect, cancel-disconnect |
web (always, from the outer route group) plus standalone.middleware, and throttle:10,1 on authorize. Removing web from standalone.middleware does not make these stateless |
Yes |
Connect callback |
web only |
No |
| Post-payment redirects | web only |
No |
| Provider webhooks | The webhook throttle only, no CSRF | No |
standalone.middleware (default ['web', 'auth', 'verified']) is the
complete stack for every dashboard route — nothing is wrapped around it.
standalone.guard selects the guard the package reads the user from, and
standalone.domain can constrain the dashboards to their own hostname. See
Standalone dashboards.