Run your workspace
Buy services (one-time add-ons)
The Services page at
/app/billing/addons is where workspace Owners and
Admins buy one-time professional services — the Blengi team
handles delivery off-platform once the charge clears Stripe.
Today the catalog has one entry: Professional AI Setup
(€499). The platform admin can add more from
/admin/addons (see One-time add-ons).
What happens when you click "Buy now"
- The price is charged to the workspace's saved payment method
via Cashier's
invoiceFor()helper. No second Stripe Checkout session is opened — the charge happens server-to-server. - A row is written to
workspace_addon_purchaseswithstatus=paid(orstatus=pendingif the card needs 3DS / SCA — Stripe redirects you to confirm and the webhook completes the flow). - The delivery team is paged via email
(
BLENGI_TEAM_NOTIFY_EMAIL) so they can start the work. - The Purchase history table at the bottom of the page reflects the new row with the appropriate status badge.
Pay by invoice (bank transfer)
When the operator has enabled Pay by invoice
(/settings/system → the same
stripe_invoice_billing_enabled switch the plan checkout
uses), "Buy now" first asks card or invoice — mirroring the
plan flow. Choosing invoice opens a billing-details form (legal
company name, address, optional EU VAT id) and then issues a
one-time Stripe send_invoice invoice via
StripeInvoiceCheckout::startOneTime():
- The invoice is a single line item priced in the add-on's own currency (amount + currency directly — no Stripe Price needed), finalized and emailed immediately so the buyer gets the hosted bank-transfer page at once rather than after Stripe's ~1-hour auto-finalize grace period.
- For EUR (and every non-USD/GBP currency) the IBAN funding
instructions are attached per-invoice via the API
(
customer_balance+eu_bank_transfer) — the same mechanism the plan invoice flow uses. - The pending purchase row is anchored on the Stripe
invoice_id; theinvoice.payment_succeededwebhook flips it topaidand pages the delivery team when the bank transfer lands. - Cancel on a pending invoice purchase voids the outstanding Stripe invoice (no Checkout session exists for this path) so Stripe stops emailing payment reminders.
The same per-workspace lock + idempotency guard as the card path prevents a double-submit from minting two invoices for one add-on.
No saved card — Stripe Checkout flow
When the workspace has no saved payment method, "Buy now" opens a
hosted Stripe Checkout session (mode=payment) that
collects the card, charges it, and saves it for future inline buys.
The pending row flips to paid through two independent,
idempotent paths:
- Success redirect — Stripe sends the buyer back
to
/app/billing/addons/success, which verifies the session (status=complete+payment_status=paid) synchronously. checkout.session.completedwebhook — payment-mode sessions create no Stripe invoice, soinvoice.payment_succeedednever fires for them. The webhook handler matches sessions whose metadata carrieskind=addon_purchaseand flips the row server-side even when the buyer closes the tab before the redirect.
Abandoned sessions expire after 30 minutes
(checkout.session.expired webhook, plus a 35-minute
self-release guard on the next Buy click) so a closed Stripe tab
never locks the buyer out of retrying.
Status meanings
| Status | What it means |
|---|---|
| Pending (yellow) | Charge initiated; awaiting Stripe confirmation. Usually takes seconds; can take longer if 3DS verification is required. |
| Paid (blue) | Stripe confirmed the payment. Delivery team has been paged and will start work. |
| Delivered (green) | Team marked the service as complete. The platform admin sets this manually after delivering the work. |
| Failed (red) | Card was declined or the payment otherwise didn't clear. You can retry by clicking Buy now again. |
| Cancelled (grey) | You or the team cancelled the purchase before delivery. |
Why I can't see the page
- You don't have billing access. Only workspace Owners and Admins can see the Services page — same gating as the Billing page. Editors and viewers get a 403.
- The platform hasn't enabled any add-ons. When
no add-on has
is_active=true, the page renders with an empty state ("No services available"). - You're a platform super_admin. The Services
entry is hidden from your sidebar (you use the
/admin/addonsCRUD instead).
Re-purchasing the same service
You can't double-purchase the same add-on while a prior purchase is in Pending, Paid, or Delivered state — the Buy button is disabled. Once a purchase falls into Failed or Cancelled, the button re-enables so you can try again or buy the same service a second time.
A stuck Pending purchase never strands you:
- Cancel and try again — the pending card shows a cancel button that releases the purchase immediately and (best-effort) expires the open Stripe Checkout session. If the payment actually completed, the webhook still records it as Paid — you are never charged twice.
- Automatic release — pending rows older than 35
minutes flip to Failed on the next page load or Buy click, and
the
checkout.session.expiredwebhook does the same server-side when the 30-minute session dies.
If you genuinely need a repeat purchase of a delivered service, contact support — we can flip the prior row's status so the catalog re-opens for you.