Skip to content
Getting Started

API: Create your first invoice and download its PDF

API: Create your first invoice and download its PDF – HTTP requests and examples for the local Billance API.

2 min readDesktopLast updated on October 1, 2026

Create an invoice through the Local Automation API

This guide uses API HTTP requests, not manual invoice creation. Requirements: Premium, the running Billance desktop app, the enabled local API, and a fully configured active company profile. Examples use Bash, cURL and Python 3. They create real local drafts. Use a separate test profile and unique invoice numbers.

1. Check the API connection

Use the displayed base URL if you changed the port. Enter the token without echoing it; never store it in scripts or Git.

BASE_URL="http://127.0.0.1:47115/api/integration/v1"
read -r -s -p "Billance API token: " BILLANCE_API_TOKEN
printf '\n'
export BILLANCE_API_TOKEN
curl --fail-with-body -sS -H "Authorization: Bearer $BILLANCE_API_TOKEN" "$BASE_URL/health"

Expected: HTTP 200 with status: "ok", apiVersion, appVersion and capabilities. Even /health returns HTTP 401 without a valid token.

2. Create a draft through the API

The simple API takes seller details from the active company profile. Unit prices are net. This example produces EUR 100 net and EUR 119 gross.

NUMBER="API-$(date +%Y%m%d-%H%M%S)"
DATE="$(date +%Y-%m-%d)"
CREATE_KEY="create-$NUMBER"
cat > invoice-request.json <<JSON
{
  "invoiceNumber": "$NUMBER",
  "invoiceDate": "$DATE",
  "paymentDueDays": 14,
  "currency": "EUR",
  "outputMode": "pdf",
  "recipient": {
    "name": "ACME GmbH", "street": "Kundenweg 2",
    "postcode": "20095", "city": "Hamburg", "country": "DE"
  },
  "items": [{"name": "Beratung", "quantity": 1, "unit": "HUR", "unitPrice": 100, "taxPercent": 19}]
}
JSON
curl --fail-with-body -sS -X POST "$BASE_URL/invoices/simple" \
  -H "Authorization: Bearer $BILLANCE_API_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $CREATE_KEY" \
  --data-binary @invoice-request.json > invoice-response.json
INVOICE_ID="$(python3 -c 'import json; print(json.load(open("invoice-response.json"))["id"])')"

Expected: HTTP 201. The saved response includes id, status: "draft", grandTotal: 119, currency: "EUR" and normalized formData, plus further fields. Stop if a request fails. To retry after a timeout, keep the request file and CREATE_KEY unchanged; do not restart the entire script.

3. Download the PDF through the API

curl --fail-with-body -sS \
  -H "Authorization: Bearer $BILLANCE_API_TOKEN" \
  "$BASE_URL/invoices/$INVOICE_ID/export?format=pdf" \
  --output invoice.pdf

Expected: HTTP 200, Content-Type: application/pdf. Each binary export generates a fresh artifact and removes temporary export files. invoice.pdf is your downloaded copy. Export neither finalizes the draft nor persists a generated document path. An error response may save problem JSON into the output file; inspect cURL’s exit code and HTTP status.

Optional: Generate and persist the output in Billance

curl --fail-with-body -sS -X POST \
  -H "Authorization: Bearer $BILLANCE_API_TOKEN" \
  -H "Idempotency-Key: generate-$NUMBER" \
  "$BASE_URL/invoices/$INVOICE_ID/generate"

generate uses stored output settings, persists the generated path and responds with HTTP 200 containing file, xmlFile and invoiceNumber. These are local paths, not file bytes. It does not finalize the document. Only POST /invoices/{id}/finalize triggers the document-type finalization workflow.

PDF designs and full form data

GET /invoice-designs returns items containing design IDs. Add top-level designTemplateId to select one; otherwise the profile default applies. For additional e-invoice fields or other document types, use POST /invoices with documentType and formData. Find the field reference and API examples under Settings → Integrations → Local Automation API.