Skip to content
Rechnungskit
E-invoicing software · made in Germany

Invoices for your Lovable app

Lovable builds your app and takes payments through Stripe Checkout, but it does not create a legally valid e-invoice. Rechnungskit fills that gap: in an edge function of your app, for example the one that starts the Stripe checkout, you send the order to Rechnungskit with one API call. Rechnungskit gets the payment from your connected Stripe account. As soon as it matches the order, 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 an edge function in your app, and every sale in your Lovable app becomes a compliant e-invoice with a DATEV export. You don't have to build any accounting logic yourself.

No credit card · set up in under an hour · personal onboarding
Your Lovable app
Espresso set Stripe Checkout · paid
€49.00
POST /v1/orders
RE-2026-0517 E-invoice created
Espresso set €41.18
Date of supply = shipping day · plus 19% VAT
ZUGFeRD to EN 16931 · GoBD-archived
Shipping date from /v1/fulfillments (§ 13 UStG)
DATEV export · VAT rate per EU country
The gap

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.

Without RechnungskitWith Rechnungskit
Lovable creates the Stripe payment, but only a confirmation, no invoice One API call in the Edge Function, and the invoice is created automatically
No EN 16931 e-invoice, no GoBD archive, no VAT logic at all Every payment becomes a ZUGFeRD invoice with your own number sequence
German tax rates per country and reverse charge would be yours to build Tax rate per country, OSS for B2C and reverse charge for B2B handled automatically
No ready-made DATEV export for your tax advisor (Steuerkanzlei) GoBD archive and a ready DATEV export, without accounting logic of your own
How it works

Four steps to a compliant e-invoice.

  1. 01
    Create an API key
    In Rechnungskit, go to Connections → API and create a key with the orders:write permission (plus invoices:read if you want to fetch the finished invoice). For testing, use an rk_test_ key; the code stays the same later. Store the key in Lovable under Cloud, Secrets (with your own Supabase project, in its edge function secrets), never in the frontend.
  2. 02
    Connect Stripe once
    Your Lovable app already uses your own Stripe account. Connect that same account once in Rechnungskit under Connections → Connect and set your API orders as the sales basis. That tells Rechnungskit that the Stripe payment belongs to the order you reported via the API. This step needs no code; you do it once in the dashboard.
  3. 03
    Report the order from the Edge Function
    Lovable builds Stripe Checkout with edge functions, without a webhook by default. Add the call to POST /v1/orders with the buyer address and line items in whole cents either in the function that starts the checkout (then your order number goes into the payment metadata) or after payment, with the Stripe payment reference (payment_intent). The key stays on the server, and the call is a single fetch.
  4. 04
    The invoice is created automatically
    Once the Stripe payment reaches Rechnungskit and matches the reported 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; digital products skip this step. If you need it, GET /v1/orders/{orderNo} returns the finished invoice, including PDF and XML, to your app.

Lovable builds the app, not the invoice

With Lovable you can build a shop or a SaaS in hours and take payments through Stripe Checkout (Lovable docs on the Stripe integration). What's missing only shows up when the tax office or your tax advisor (Steuerkanzlei) asks: Lovable 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. Rebuilding all of that in your app is exactly the kind of work you picked an AI app builder to avoid.

Rechnungskit closes that gap where your app already handles the purchase: in an edge function. One API call reports the order, the payment comes from your connected Stripe account, and the sale turns into a ZUGFeRD invoice with your own number sequence, archived in an audit-proof way and ready for booking in DATEV.

Why this fits Lovable well

A Lovable app already has what the connection needs. By default it runs on the built-in backend Lovable Cloud with edge functions and secrets, or on your own Supabase project if you prefer (Lovable docs). Edge functions are the clean way to call an external API: on the server with the key in the secrets, not from the browser. Lovable's Stripe integration uses them as well (Lovable docs).

Lovable doesn't set up a webhook by default. Your app checks the payment status directly with Stripe. That is fine for Rechnungskit, because Rechnungskit gets the payment itself through your connected Stripe account. Your app only has to report the order, and there are two places to do it:

  • When the checkout starts. In the edge function that creates the Checkout Session, report the order with your order number and put the same number into payment_intent_data.metadata as order_no. If the buyer abandons the checkout, no payment arrives and no invoice is created.
  • After payment. In the function that checks the payment status, or in a webhook if you have Lovable set one up, report the order with the Stripe payment reference as paymentRef. If that function only runs when the buyer returns to your success page, an order can go missing when they close the window first. Rechnungskit then shows the payment as an unmatched payment task, and you assign it by hand.

The call you add

The example shows the after-payment route: in the edge function that handles the paid Stripe checkout, add a fetch to POST /v1/orders. Amounts go in whole cents, the Stripe payment reference goes in paymentRef, and the API key comes from the secrets:

// Edge function, after a paid Stripe checkout (session retrieved via the Stripe API)
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 // Stripe session ID: prevents duplicate documents
  },
  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 }
    ]
  })
})

That's all the code. The invoice itself isn't created by this call. It's created as soon as the Stripe payment reaches Rechnungskit and matches the order. There is deliberately no paid field: the payment status always comes from your payment provider, never from the sender. So an abandoned order can never become a real invoice.

Where does the API key come from?

You create the key in Rechnungskit under Connections → API (directly at app.rechnungskit.de/settings/api). Click to create a key, grant the orders:write permission (and invoices:read if you want to fetch finished invoices), and the full key is shown to you exactly once. For trying things out, use an rk_test_ key; for live operation, rk_live_. Store the value in Lovable under Cloud, Secrets (for example as RECHNUNGSKIT_API_KEY), never in the frontend. In the Edge Function you read it with Deno.env.get('RECHNUNGSKIT_API_KEY'), as in the example above.

Selling physical goods? One more step

For purely digital products and SaaS, the call above is all you need: the invoice is created once the payment matches. If you ship real goods, a second call comes in, because the date of supply (Leistungsdatum) on the invoice is the shipping date, not the payment date: a supply by dispatch is carried out when the dispatch begins (section 13.1(2) UStAE, the German VAT application decree). As soon as you ship the order, report it with POST /v1/fulfillments:

// When the goods go out (e.g. in your app's "mark as shipped" flow)
await fetch('https://api.rechnungskit.de/v1/fulfillments', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${Deno.env.get('RECHNUNGSKIT_API_KEY')}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': `fulfill-${orderNo}`
  },
  body: JSON.stringify({
    orderNo,                       // the same order number as in /v1/orders
    status: 'fulfilled',
    shippedAt: new Date().toISOString(),
    trackingNumber: 'DHL-1234567'  // optional
  })
})

For this, set requiresShipping: true when you create the order. Rechnungskit then waits for the fulfillment report before it creates the invoice with the correct date of supply. If you leave requiresShipping out (the default), there's no waiting stage and you never need /v1/fulfillments.

One-time setup, stated plainly

The code is simple, but you set up a few things once, or you'll wonder why no invoice appears. No fetch does these for you:

  • Connect Stripe in the dashboard and set it to API. You connect your Stripe account once in Rechnungskit under Connections → Connect and choose your API orders as the sales basis. Only then does Rechnungskit bring payment and order together. It's a click, not code.
  • Send the country code. Without country_code in the billing address the VAT can't be determined, and the order is rejected. An email-only checkout isn't enough.
  • Set an Idempotency-Key. Every POST needs the header; otherwise a duplicate call (such as a reloaded success page) creates two orders. The Stripe session ID is a good value.
  • Retry on 5xx. Deployments cause brief outages. Retry the call after a short pause so no order gets lost while the payment has already arrived.
  • Check your products' tax rates. Rechnungskit assigns new products automatically, and you confirm the assignment once. If it's missing, the document is held back rather than issued incorrectly.

Show your AI the docs

Rechnungskit publishes a complete OpenAPI 3.1 specification at api.rechnungskit.de/v1/openapi.json. You can hand it to the AI in Lovable or ChatGPT and ask it to generate an edge function that reports an order to Rechnungskit for the Stripe checkout. Because the specification includes the required fields and even the retry rule, the result is usually a correct function. The one step the AI can't know from the code, connecting Stripe in the dashboard, is described above. The full reference with working examples is in the API documentation. Building with Bolt, Replit or another builder instead? It works the same way, see invoices for no-code and AI app builders.

FAQ

FAQ

Yes, and it does so the standard way. A Lovable app doesn't call external APIs straight from the React frontend (the browser blocks that via CORS). It goes through an edge function that acts as a server-side proxy. Edge functions are part of Lovable Cloud, the built-in backend, or of your own Supabase project if you connect one (Lovable docs), and Lovable's Stripe integration runs on them too. You add a single fetch call to Rechnungskit there. Store the API key in Lovable under Cloud, Secrets so it never ends up in the browser.
Last reviewed:

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
de en