Filekin for Business API
Create XRechnung, ZUGFeRD and Factur-X invoices from your own software, and check any e-invoice against the official rules, with plain-language explanations of every error. Every account can use it: the free Developer plan includes 20 invoices and 100 calls a month, no card needed, and the Business + API and API Plus plans include thousands.
Getting started
- Fill in your company details: they go on every invoice the API makes.
- Create an API key on your account page. It's shown once: keep it secret, like a password.
- Send it with every call:
Authorization: Bearer fk_…
Create an invoice
POST https://app.filekin.io/api/v1/invoices with a JSON body. Your company, bank and invoice defaults come from your company details;
a saved customer number or product code fills in the rest, just like in a spreadsheet.
curl https://app.filekin.io/api/v1/invoices \
-H "Authorization: Bearer $FILEKIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"number": "RE-2026-0042",
"issue_date": "2026-11-02",
"customer": {"name": "Beispiel GmbH", "street": "Marktplatz 3", "postcode": "80331",
"city": "München", "country": "DE", "vat_id": "DE987654321"},
"buyer_reference": "04011000-12345-03",
"lines": [{"description": "Webdesign", "quantity": 12, "unit": "HUR", "price": 85, "vat_rate": 19}]
}'
The answer (201) is JSON with the file in base64:
{"number": "RE-2026-0042", "file_name": "Rechnung RE-2026-0042.pdf", "content_type": "application/pdf",
"file": "JVBERi0xLjcK…", "invoices_left": 1999}
Add ?download=1 to get the file itself instead. Every invoice is checked against the official rules before it's returned.
Fields
| Field | What it is |
|---|---|
number | Invoice number. Leave it out to use your automatic numbering. A number can be used once; send "replace": true to make it again. |
issue_date, due_date, delivery_date | Dates as YYYY-MM-DD. Issue date defaults to today; the due date to your usual payment terms. |
customer | code (a saved customer number), or name, street, postcode, city, country (2 letters), vat_id, email. |
buyer_reference | Leitweg-ID for German public authorities, or the buyer's reference. |
order_reference, notes | Purchase order number, and a note printed on the invoice. |
lines | Up to 200 lines: product_code (a saved product), or description, quantity, unit (HUR, DAY, MON, C62…), price (net), vat_rate, and an optional discount in percent. |
discount | A discount on the whole invoice: {"percent": 5} or {"amount": 50}, with an optional reason. It's split across the VAT rates as EN 16931 requires. |
charges | Up to 5 surcharges, such as shipping: [{"reason": "Versand", "amount": 4.90, "vat_rate": 19}] (net; the rate defaults to the invoice's highest). |
skonto | Early-payment discounts, up to two: [{"percent": 2, "days": 10}]. Printed with the date and amount, and coded for German software (#SKONTO#). Send [] for none when your account has a default. |
document, prepayments | "partial" for a down-payment invoice (type 326), or "final" for a final invoice with the down payments it deducts: [{"number": "AR-1", "date": "2026-09-01", "net": 1000, "vat": 190}]. |
paid_amount, payment_method, card_digits | What's paid already, and how it's paid: transfer (the default, to your IBAN), card, online or cash. A fully paid invoice shows nothing left to pay. |
format, language, currency | Optional, to override your defaults: zugferd, xrechnung or simple; de, fr or en; a currency code like EUR. |
Validate an e-invoice
POST https://app.filekin.io/api/v1/validate with the file as the body: an XRechnung or UBL XML, or a ZUGFeRD / Factur-X PDF.
Add ?lang=de or ?lang=fr for messages in German or French.
curl https://app.filekin.io/api/v1/validate?lang=de \
-H "Authorization: Bearer $FILEKIN_KEY" \
--data-binary @rechnung.xml
The answer is a report: the format found, whether it passes, whether it counts as an e-invoice in Germany and France, and every error and warning with where it is, how to fix it, and a link to a full explanation.
{"format": "XRechnung 3.0 (CII)", "valid": false, "germany": "…", "france": "…",
"errors": [{"rule": "BR-DE-15", "message": "…", "where": "…", "help": "…",
"explanation_url": "https://filekin.io/de/e-rechnung-fehler/br-de-15"}], "warnings": []}
Python
import base64, os, requests
key = os.environ["FILEKIN_KEY"]
r = requests.post("https://app.filekin.io/api/v1/invoices", timeout=60,
headers={"Authorization": f"Bearer {key}"},
json={"customer": {"code": "K-1001"}, "lines": [{"product_code": "WEB", "quantity": 3}]})
r.raise_for_status()
invoice = r.json()
open(invoice["file_name"], "wb").write(base64.b64decode(invoice["file"]))
Usage
GET https://app.filekin.io/api/v1/usage returns your plan, this month's use and your allowance.
Limits
- Each call counts as one API call; creating an invoice also counts as one invoice. Calls refused before any work don't count.
- 5 calls a second, and one call at a time, per account.
- 2 MB per request; 200 lines per new invoice; 1,000 lines per validated invoice.
- When a monthly allowance is used up, calls are refused until the 1st (UTC). You're never charged for more.
Errors
Errors come back as JSON: {"error": "code", "message": "what happened"}.
| Status | Code | Meaning |
|---|---|---|
| 400 | bad_json, empty | The request body isn't what the endpoint expects. |
| 401 | unauthorized | The API key is missing, wrong or revoked. |
| 403 | no_plan | The account's plan has no API access. |
| 409 | duplicate, no_company | The invoice number was used before, or the company details aren't filled in. |
| 413 | too_many_lines, too_large | Over a size limit. |
| 422 | invalid, not_an_invoice | The invoice can't be made as given (the message says why), or the file isn't an e-invoice. |
| 429 | slow_down, busy, limit | Too fast, a call is still running, or the month's allowance is used up. |