Invoicing
[billing] [admin]
Stripe Connect based billing: licensio = platform, providers = connected accounts. Flat platform fee: 10 % in the beta (resolveProvisionPercent, overridable per provider, see Access & terms). Stripe Tax automatic.
Who it is for
Admins. The "Invoicing" tab collects all data that Stripe needs for correct invoices, VAT and payment processing.
What you set
Legal name + legal form
- e.g. "Plant Technology GmbH"
- Set in Stripe as
business_profile.name - Appears on every invoice as the sender
Address
- Street, zip, city, country
- Stripe attempts to set this as
company.address(Express accounts often only accept it via onboarding)
Tax
- VAT ID: added to the Stripe
tax_ids - Tax number: informational, printed on invoices
- Stripe Tax must be enabled separately in the Stripe dashboard (Tax tab → Automatic Tax ON)
Contact
- Email (for Stripe mails)
- Phone number
Invoice logo
Your own logo that appears on Stripe invoices. Upload via:
- licensio storage (for the preview in the admin)
- Stripe Files API with
purpose: 'business_icon' accounts.updateon the connected account withsettings.branding.logo
Recommended: square PNG, ≥256x256, < 200 KB.
Step by step
1. Enable Stripe Connect
Settings → Stripe → Create account → Stripe onboarding (Express account). Provides your bank data, person verification etc.
2. Fill the invoicing tab
Fill in all fields + upload a logo. Save automatically triggers the Stripe sync (best-effort).
3. Enable Stripe Tax in the dashboard
- dashboard.stripe.com → Tax → Settings
- Automatic Tax to ON
- Tax registrations → add Germany
- The company address must be complete
4. Test the first package
Create packages → on save a Stripe product + price is created. Visible in the Stripe dashboard under Products of the connected account.
5. First payment
Two paths, depending on who starts it:
- Admin "Activate" (Freischalten): activation always creates a Stripe
send_invoiceinvoice (14-day due date,auto_advance, payment methods derived by preflight from the connected account's Connect capabilities —card/sepa_debit; none active → error). There is no checkout on the admin path. The customer stayspending_paymentand only becomesactivevia theinvoice.paidwebhook. - End-customer self-service (
/join): the customer goes through the Stripe checkout (subscription for monthly packages or a single charge for one-off ones).
Webhook events confirm the payment in licensio.
Operational note (required per provider Stripe account): disable Stripe's own invoice/subscription emails in the Stripe dashboard (Settings → Billing → Invoices / Subscriptions and emails), otherwise the customer receives a duplicate mail. The licensio mail with the hosted-invoice link is the only customer mail.
Stripe Tax: logic
| Sender | Recipient | VAT ID | Result |
|---|---|---|---|
| DE | DE | any | 19 % VAT |
| DE | EU | with VAT ID | Reverse charge 0 % |
| DE | EU | without VAT ID | Local rate of the recipient country |
| DE | non-EU | any | 0 % |
Stripe applies this automatically when automatic_tax: { enabled: true } and tax_behavior: 'exclusive' (net prices).
Webhook events (incoming)
There are two Stripe webhooks with different purposes: confusing them leads to signature errors and broken plan updates.
Provider portal webhook: /api/stripe/webhook (<slug>.licensio.io)
Processes payments from your end customers (Stripe Connect):
checkout.session.completed: first payment successfulsetup_intent.succeeded: payment method saved (Flow B)invoice.paid: recurring paymentinvoice.payment_failed: payment failed (notification + dunning)charge.refunded: refundcustomer.subscription.updated/.deleted: subscription lifecycleaccount.updated: connected account status
Secret in ENV: STRIPE_WEBHOOK_SECRET (portal Vercel project).
licensio platform webhook: /api/stripe/licensio-webhook (admin.licensio.io)
Processes your own paid plan subscription at licensio (an upgrade done later inside the admin — registration itself is always the free access):
checkout.session.completed: new paid plan subscriptioncustomer.subscription.updated: plan change, renewalscustomer.subscription.deleted: cancellation → provider falls back to the free access (plan = free)invoice.payment_failed: payment error on your plan invoice
Secret in ENV: LICENSIO_STRIPE_WEBHOOK_SECRET (admin Vercel project). Writes directly into tenants.plan, plan_started_at, licensio_stripe_customer_id, licensio_subscription_id.
Invoices in the portal
Customers see their Stripe invoices directly in the portal account tab "License & contract" → invoices tile with PDF download (via the Stripe Invoices API).
Frequently asked questions
How high is the platform fee?
A flat 10 % in the beta (application_fee_percent on every Stripe subscription, resolved by resolveProvisionPercent; overridable per provider via settings.provision_percent). The rest goes to you. Visible in the Stripe dashboard as an application fee. Details: Access & terms.
Who sees my Stripe data? Only you. licensio platform admins have read access for support cases, but no modification rights.
What if the Stripe webhook fails?
The webhook endpoint validates signatures with STRIPE_WEBHOOK_SECRET. On failure Stripe retries automatically (~several hours). Error logs are visible in the Vercel logs.
Can I also send invoices without Stripe? Currently everything runs via Stripe. Manual invoicing (PDF generation outside Stripe) is not implemented.
Reverse charge for EU customers: how?
Stripe Tax detects EU VAT IDs automatically (validated via VIES). If the customer enters a VAT ID at checkout, reverse charge is applied. tax_id_collection is enabled in our checkouts.