Invoices for your Bolt app
Bolt (bolt.new) builds your app and connects Stripe in one click, but it does not create a legally valid e-invoice. Rechnungskit fills the gap: in the Supabase Edge Function that Bolt sets up for your Stripe webhooks, you send the order to Rechnungskit with one API call. As soon as the Stripe payment arrives, a GoBD-compliant ZUGFeRD invoice under EN 16931 is created automatically, with your own number sequence, a DATEV export and archiving.
One API call from the Supabase Edge Function that Bolt already generates for your Stripe webhooks, and every sale in your Bolt app becomes a compliant e-invoice with a DATEV export.
Writing invoices is easy. Writing compliant ones is not.
The difference between a PDF and a compliant e-invoice matters at the next tax audit. Rechnungskit closes exactly this gap.
Four steps to a compliant e-invoice.
- 01Create an API keyIn Rechnungskit, go to Connections → API and create a key with the orders:write permission (plus invoices:read for fetching invoices). Use rk_test_ for testing and rk_live_ for live operation. Store the value in Bolt or Supabase as a secret, never in the frontend.
- 02Connect Stripe onceYour Bolt app uses your own Stripe account. Connect that same account once in Rechnungskit under Connections → Connect and set your API orders as the sales basis. Rechnungskit then matches the Stripe payment to the order you reported via the API. It's a click in the dashboard, not code.
- 03Report the order from the Edge FunctionFor Stripe, Bolt sets up a Supabase Edge Function that processes webhooks (payments, subscriptions, refunds). That's where you add a call to POST /v1/orders, with the buyer address, line items in whole cents and the Stripe payment reference. The key stays on the server, and the call is a single fetch.
- 04The invoice is created automaticallyOnce the Stripe payment reaches Rechnungskit and matches the order, the e-invoice is created: validated against EN 16931, with the correct tax rate, archived to GoBD standards and ready for the DATEV export. For physical goods you also report the shipment via POST /v1/fulfillments so the date of supply (Leistungsdatum) is right. GET /v1/orders/{orderNo} returns the finished invoice.
Bolt builds the checkout, not the invoice
With Bolt you can build an app in minutes and turn on Stripe in one click, including webhook processing for payments and subscriptions. What's missing afterwards: Bolt creates a payment, but not an invoice in the sense of German law. There's no structured document under EN 16931, no GoBD archive (GoBD being the German rules for keeping digital records), no VAT logic per country and no DATEV export.
Rechnungskit closes that gap where Bolt already handles the payment: in the Supabase Edge Function behind your Stripe webhook. One API call turns the sale into a ZUGFeRD invoice with your own number sequence, archived in an audit-proof way and ready for booking in DATEV.
Why Bolt is a good fit
Bolt generates a real full-stack app: a React frontend plus server-side functions based on Supabase Edge Functions, along with the native Stripe connection and its webhooks. That's the environment the connection needs: a server-side function where your API key is stored safely and where you add a call to Rechnungskit when a checkout succeeds. You don't build new infrastructure; you use what Bolt has already set up.
The call you add
In the Edge Function that processes your Stripe webhook, add a fetch to POST /v1/orders
in the success branch. Amounts go in whole cents, the Stripe payment reference goes in
paymentRef, and the key comes from the secrets:
// Supabase Edge Function (Bolt), in the Stripe webhook after a successful payment
const res = await fetch('https://api.rechnungskit.de/v1/orders', {
method: 'POST',
headers: {
'Authorization': `Bearer ${Deno.env.get('RECHNUNGSKIT_API_KEY')}`,
'Content-Type': 'application/json',
'Idempotency-Key': session.id
},
body: JSON.stringify({
orderNo: session.id,
paymentRef: session.payment_intent, // pi_... from Stripe
email: session.customer_details?.email,
billingAddress: {
name: session.customer_details?.name,
country_code: session.customer_details?.address?.country, // required for VAT
postal_code: session.customer_details?.address?.postal_code,
city: session.customer_details?.address?.city,
street: session.customer_details?.address?.line1
},
items: [{ name: 'Pro plan', quantity: 1, unitGrossCents: 2900, taxRate: 19 }]
})
})
One thing to know about Bolt: check that your function verifies the webhook's Stripe signature before it derives an order. According to the Bolt docs, the Stripe integration does this automatically, but after changes to the generated code it is worth a look. On the Rechnungskit side this is covered, because Rechnungskit verifies the signature of the Stripe payment itself when it comes in.
Where does the API key come from?
You create the key in Rechnungskit under Connections → API (directly at
app.rechnungskit.de/settings/api) with the orders:write permission. It's shown exactly
once. Store the value in Bolt or Supabase as a secret (for example
RECHNUNGSKIT_API_KEY), never in the frontend, and read it in the Edge Function with
Deno.env.get('RECHNUNGSKIT_API_KEY').
One-time setup, stated plainly
The code is simple, but you set up a few things once:
- Connect Stripe in the dashboard and set it to API. You connect your Stripe account once in Rechnungskit under Connections → Connect, with API orders as the sales basis. It's a click, not code.
- Send the country code. Without
country_codein the billing address the order is rejected, because the VAT can't be determined otherwise. - Set an Idempotency-Key. Every POST needs the header; otherwise a duplicate webhook creates two orders. The Stripe session ID is a good value.
- Check the Stripe signature in Bolt. Make sure your function verifies the webhook before it derives the order.
- Retry on 5xx. Retry the call after a short pause so no order gets lost.
Show your AI the docs
Rechnungskit publishes a complete OpenAPI 3.1 specification at
api.rechnungskit.de/v1/openapi.json. Give it to Bolt's AI and ask it to report an order to
Rechnungskit in the Stripe webhook after a successful payment. The full reference with
working examples is in the API documentation.
Building with Lovable, Replit or v0 instead? It works the same way, see
invoices for no-code and AI app builders.
FAQ
Rechnungskit is not a tax advisory or law firm. This article explains general principles and does not replace advice from a tax advisor (Steuerberater, § 5 StBerG) or a lawyer (§ 3 RDG). Rechnungskit is built for businesses based in Germany and prepares documents, tax rates and bookings automatically. How your specific case is treated remains your decision, ideally together with your tax advisor or a lawyer.
Ready for the e-invoicing mandate?
Create an account, connect your payment provider, check everything in free test mode. Billing starts when you go live.
Try it now