Description
Overview
The Invoices module provides comprehensive functionality for managing invoices, including:
- Creation and management of invoices with line items
- Automatic invoice numbering with configurable formats
- OCR processing of invoice documents
- QR code generation and reading (Swiss QR-bill compatible)
- PDF generation with embedded QR codes
- Management of common receivers and senders
- Support for multiple currencies and VAT calculations
Endpoints
Create Invoice V3
POST /v3/invoices
Create or update selector-based invoices using source and destination counterparties instead of inline address payloads.
V3 request shape:
source.counterparty_idanddestination.counterparty_idare required.- Optional
cp_account_idmust belong to selected counterparty and be active. - Optional
cp_address_idmust be an active address on selected counterparty. If omitted, API picks active preferred billing/fallback address. - Request-side invoice amounts are grouped under
amount, includingamount.currency, and use minor units without repeating precision. - Request-side rate inputs are grouped under
rates. - Item
priceis sent and returned in minor units. - Item
total_priceis returned in minor units. amount.shippingis sent and returned in minor units.rates.discountandrates.vatare rates in percent, not monetary amounts.- Invoice-level response
amountis compact: sharedcurrencyandprecisionare declared once, and each monetary field is returned as a minor-unit string. - Item
priceandtotal_priceare minor-unit strings. Useamount.currency+amount.precisionfor conversion:major = minor / 10^amount.precision.
Request Body:
{
"invoice_number": "INV-V3-000001",
"description": "Monthly services",
"reference": "REF-2024-04",
"status": "draft",
"customer_id": "550e8400-e29b-41d4-a716-446655440000",
"source": {
"counterparty_id": "11111111-1111-1111-1111-111111111111",
"cp_account_id": "22222222-2222-2222-2222-222222222222",
"cp_address_id": "33333333-3333-3333-3333-333333333333"
},
"destination": {
"counterparty_id": "44444444-4444-4444-4444-444444444444"
},
"amount": {
"currency": "CHF",
"shipping": "1000"
},
"rates": {
"discount": 10,
"vat": 7.70
},
"items": [
{
"title": "Service A",
"description": "Monthly subscription",
"quantity": 1,
"price": "10000"
}
],
"metadata": {
"department": "IT",
"project_code": "P123"
}
}Success Response (201):
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"invoice_number": "INV-V3-000001",
"status": "draft",
"source": {
"counterparty_id": "11111111-1111-1111-1111-111111111111",
"cp_account_id": "22222222-2222-2222-2222-222222222222",
"cp_address_id": "33333333-3333-3333-3333-333333333333"
},
"destination": {
"counterparty_id": "44444444-4444-4444-4444-444444444444",
"cp_account_id": null,
"cp_address_id": "66666666-6666-6666-6666-666666666666"
},
"amount": {
"currency": "CHF",
"precision": 2,
"subtotal": "10000",
"shipping": "1000",
"discount_amount": "1000",
"vat_amount": "693",
"total": "10693"
},
"rates": {
"discount": 10,
"vat": 7.7
},
"items": [
{
"id": "987fcdeb-51a2-43d7-9012-345678901234",
"title": "Service A",
"quantity": 1,
"price": "10000",
"total_price": "10000"
}
]
}Interpretation example:
amount.currency = "CHF"amount.precision = 2- item
price = "1050"means CHF 10.50 - item
total_price = "2100"means CHF 21.00
Create Invoice
POST /v2/invoices
Create a new invoice with automatic numbering and PDF generation.
Request Body:
{
"description": "Monthly services",
"status": "draft",
"party_type": "receiver",
"due_date": "2024-04-01T00:00:00Z",
"currency": "CHF",
"iban": "CH93 0076 2011 6238 5295 7",
"customer_id": "550e8400-e29b-41d4-a716-446655440000",
"name_from": "Sender Company AG",
"address_from": "Bahnhofstrasse 1",
"zip_from": "8001",
"city_from": "Zürich",
"country_from": "Switzerland",
"name_to": "Receiver GmbH",
"address_to": "Hauptstrasse 10",
"zip_to": "3000",
"city_to": "Bern",
"country_to": "Switzerland",
"shipping": 10.00,
"discount": 5.00,
"vat": 7.70,
"items": [
{
"title": "Service A",
"description": "Monthly subscription",
"quantity": 1,
"unit_price": 100.00
}
],
"active": true,
"metadata": {
"department": "IT",
"project_code": "P123"
}
}Success Response (201):
{
"invoice": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"invoice_number": "INV-2024-000001",
"status": "draft",
"total": 112.31,
"created_at": "2024-03-21T10:00:00Z"
},
"items": [
{
"id": "987fcdeb-51a2-43d7-9012-345678901234",
"title": "Service A",
"quantity": 1,
"unit_price": 100.00,
"total": 100.00
}
]
}Error Responses:
- 400: Invalid input data
- 401: Unauthorized
- 403: Insufficient permissions
- 500: Internal server error
Process Invoice OCR
POST /v1/invoices/ocr
Extract invoice details from documents using OCR technology.
Request Body:
{
"base64_file": "JVBERi0xLjcKCjEgMCBvYmogICUgZW50...",
"options": {
"language": "en",
"extract_items": true,
"detect_qr": true
}
}Success Response (200):
{
"extracted_data": {
"invoice_number": "INV-2024-000123",
"date": "2024-03-21",
"total": 112.31,
"currency": "CHF",
"iban": "CH93 0076 2011 6238 5295 7",
"recipient": {
"name": "Receiver GmbH",
"address": "Hauptstrasse 10",
"zip": "3000",
"city": "Bern"
},
"items": [
{
"description": "Service A",
"quantity": 1,
"price": 100.00
}
]
},
"confidence_score": 0.95
}Error Responses:
- 400: Invalid file format
- 401: Unauthorized
- 413: File too large
- 422: Processing failed
- 500: Internal server error
Process Invoice OCR V2
POST /v2/invoices/ocr
Extract invoice details from documents using OCR technology with automatic recipient search, draft upload creation, and draft transfer prefilling.
Request Body:
{
"base64_file": "JVBERi0xLjcKCjEgMCBvYmogICUgZW50...",
"customer_id": "550e8400-e29b-41d4-a716-446655440000"
}Success Response (202):
{
"job_id": "123e4567-e89b-12d3-a456-426614174000",
"status": 202,
"upload_id": "123e4567-e89b-12d3-a456-426614174002",
"message": "Job is processing"
}Poll GET /v2/invoices/ocr/{id} for completion. When status is 200, the response includes transfer_id, counterparty_match, counterparty_id, cp_account_id, and result.
Error Responses:
- 400: Invalid input or missing required fields
- 401: Unauthorized
- 403: Insufficient permissions
- 413: File too large
- 500: Internal server error
Check Invoice OCR Status
GET /v1/invoices/ocr/{id}
Check the status of an OCR processing job.
Path Parameters:
- id: Job UUID
Success Response (200):
{
"job_id": "123e4567-e89b-12d3-a456-426614174000",
"status": 200,
"result": {
"total": "112.31",
"customer_name": "Receiver GmbH",
"customer_email": "info@receiver.ch",
"currency_code": "CHF",
"currency_symbol": "CHF",
"due_date": "2024-04-01",
"subtotal": "100.00",
"sales_tax_percentage": "7.7",
"sales_tax_amount": "7.70",
"invoice_number": "INV-2024-000123",
"reference": "REF123",
"bic": "BCGEVBGG",
"iban": "CH93 0076 2011 6238 5295 7"
}
}Error Responses:
- 400: Invalid job ID
- 401: Unauthorized
- 403: Forbidden - job doesn't belong to user
- 404: Job not found
- 500: Internal server error
Check Invoice OCR Status V2
GET /v2/invoices/ocr/{id}
Check the status of an OCR processing job with counterparty destination resolution.
Path Parameters:
- id: Job UUID
Success Response (200):
{
"job_id": "123e4567-e89b-12d3-a456-426614174000",
"status": 200,
"upload_id": "123e4567-e89b-12d3-a456-426614174002",
"transfer_id": "123e4567-e89b-12d3-a456-426614174003",
"counterparty_match": "found",
"counterparty_id": "123e4567-e89b-12d3-a456-426614174001",
"cp_account_id": "123e4567-e89b-12d3-a456-426614174004",
"message": "Job completed",
"result": {
"total": "112.31",
"customer_name": "Receiver GmbH",
"customer_email": "info@receiver.ch",
"currency_code": "CHF",
"currency_symbol": "CHF",
"due_date": "2024-04-01",
"subtotal": "100.00",
"sales_tax_percentage": "7.7",
"sales_tax_amount": "7.70",
"invoice_number": "INV-2024-000123",
"reference": "REF123",
"bic": "BCGEVBGG",
"iban": "CH93 0076 2011 6238 5295 7"
}
}Processing Response (202):
{
"job_id": "123e4567-e89b-12d3-a456-426614174000",
"status": 202,
"upload_id": "123e4567-e89b-12d3-a456-426614174002",
"message": "Job is processing"
}Failed Response (500):
{
"job_id": "123e4567-e89b-12d3-a456-426614174000",
"status": 500,
"message": "Job failed"
}Notes:
upload_ididentifies the draft upload created for the scanned document; present while the job is processing and when complete; omitted when the job fails and draft resources are cleaned uptransfer_ididentifies the draft transfer prefilled from OCR data (only whenstatusis200)counterparty_matchisfoundwhen an existing destination counterparty matched, orcreatedwhen a new one was created (only whenstatusis200)counterparty_idandcp_account_ididentify the resolved destination selectors used by the prefilled draft transfertransaction_idis a legacy customer-transaction draft identifier; new jobs usetransfer_idinsteadrecipientandrecipient_matchare legacy fields for older jobs; new OCR jobs expose counterparty fields instead
Error Responses:
- 400: Invalid job ID
- 401: Unauthorized
- 403: Forbidden - job doesn't belong to user
- 404: Job not found
- 500: Internal server error
Read QR Code
POST /v1/invoices/qrcode
Extract payment information from Swiss QR-bills.
Request Body:
{
"base64_file": "JVBERi0xLjcKCjEgMCBvYmogICUgZW50...",
"options": {
"page": 1,
"validate_format": true
}
}Success Response (200):
{
"qr_info": {
"iban": "CH93 0076 2011 6238 5295 7",
"creditor": {
"name": "Sender Company AG",
"address": "Bahnhofstrasse 1",
"zip": "8001",
"city": "Zürich",
"country": "CH"
},
"amount": 112.31,
"currency": "CHF",
"reference": "RF18539007547034",
"message": "Invoice INV-2024-000123"
}
}Error Responses:
- 400: Invalid file format or no QR code found
- 401: Unauthorized
- 413: File too large
- 422: Invalid QR code format
- 500: Internal server error
Get Invoice By ID
GET /v2/invoices/{id}
Retrieve complete invoice details including line items.
Path Parameters:
- id: Invoice UUID
Query Parameters:
- include_items: Include line items (default: true)
- include_metadata: Include metadata (default: false)
Success Response (200):
{
"invoice": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"invoice_number": "INV-2024-000001",
"description": "Monthly services",
"status": "draft",
"party_type": "receiver",
"due_date": "2024-04-01T00:00:00Z",
"currency": "CHF",
"iban": "CH93 0076 2011 6238 5295 7",
"customer_id": "550e8400-e29b-41d4-a716-446655440000",
"name_from": "Sender Company AG",
"address_from": "Bahnhofstrasse 1",
"zip_from": "8001",
"city_from": "Zürich",
"country_from": "Switzerland",
"name_to": "Receiver GmbH",
"address_to": "Hauptstrasse 10",
"zip_to": "3000",
"city_to": "Bern",
"country_to": "Switzerland",
"subtotal": 100.00,
"shipping": 10.00,
"discount": 5.00,
"vat": 7.70,
"total": 112.31,
"created_at": "2024-03-21T10:00:00Z",
"metadata": {
"department": "IT",
"project_code": "P123"
}
},
"items": [
{
"id": "987fcdeb-51a2-43d7-9012-345678901234",
"invoice_id": "123e4567-e89b-12d3-a456-426614174000",
"title": "Service A",
"description": "Monthly subscription",
"quantity": 1,
"unit_price": 100.00,
"total": 100.00
}
]
}Error Responses:
- 400: Invalid invoice ID format
- 401: Unauthorized
- 403: Insufficient permissions
- 404: Invoice not found
- 500: Internal server error
Get All Invoices
GET /v2/invoices
List all invoices with support for filtering, sorting, and stacking.
Query Parameters:
- status: Filter by invoice status (draft/pending/paid/sent/overdue)
- date_from: Start date (format: 2024-03-21T00:00:00Z)
- date_to: End date (format: 2024-03-21T23:59:59Z)
- currency: 3-letter currency code (e.g., CHF)
- customer_id: Customer UUID
- limit: Records per page (default: 10, max: 50)
- offset: Pagination offset (default: 0)
- sort: Sort fields with optional - prefix (e.g., -created_at,status)
- stack: Stack by field with optional format (e.g., created_at[DD-MM-YYYY])
Query Parameters Documentation
Search Parameters
Use search.field.operator=value format for filtering:
search.status.eq=draft
search.amount.gt=1000
search.currency.in=CHF,EUR
search.active=trueAvailable operators:
eq: Equal tone: Not equal togt: Greater thangte: Greater than or equal tolt: Less thanlte: Less than or equal toin: In array (comma-separated values)nin: Not in array (comma-separated values)like: Contains string (case-insensitive)ilike: Contains string (case-sensitive)
Sort Parameters
Use sort=field for ascending or sort=-field for descending order:
sort=created_at # ascending
sort=-amount # descending
sort=status,-date # multiple fieldsStack Parameters
Group results by field(s):
stack=status # group by status
stack=currency,status # group by currency then statusPagination
Control the number of results:
limit=25 # items per page (default: 10, max: 100)
offset=50 # skip first 50 itemsExample
/v1/invoices?search.status.in=draft,pending&search.amount.gt=1000&sort=-created_at&stack=status&limit=25This will:
- Find invoices with status 'draft' or 'pending'
- Filter for amounts greater than 1000
- Sort by creation date (newest first)
- Group results by status
- Return up to 25 results per page
Sorting Examples:
sort=created_at # Sort by created_at ascending
sort=-created_at # Sort by created_at descending
sort=-due_date,status # Sort by due_date descending, then status ascendingStacking Examples:
stack=created_at[DD-MM-YYYY] # Group by created_at, format as DD-MM-YYYY
stack=total[#,##0.00] # Group by total, format with thousand separators
stack=status # Group by status as-is
stack=-currency # Group by currency in reverse orderRegular Response (200):
{
"data": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"invoice_number": "INV-2024-000001",
"status": "draft",
"total": 112.31,
"created_at": "2024-03-21T10:00:00Z"
}
],
"total": 100,
"has_more": true
}Stacked Response (200):
{
"data": {
"24-03-2024": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"invoice_number": "INV-2024-000001",
"status": "draft",
"total": 112.31,
"created_at": "2024-03-24T10:00:00Z"
},
{
"id": "123e4567-e89b-12d3-a456-426614174001",
"invoice_number": "INV-2024-000002",
"status": "paid",
"total": 245.00,
"created_at": "2024-03-24T14:30:00Z"
}
],
"23-03-2024": [
{
"id": "123e4567-e89b-12d3-a456-426614174002",
"invoice_number": "INV-2024-000003",
"status": "pending",
"total": 89.99,
"created_at": "2024-03-23T09:15:00Z"
}
]
},
"total": 100,
"has_more": true
}Error Responses:
- 400: Invalid query parameters
- 401: Unauthorized
- 403: Insufficient permissions
- 500: Internal server error
Update Invoice
PUT /v2/invoices/{id}
Update existing invoice details and items. Supports partial updates.
Path Parameters:
- id: Invoice UUID
Request Body:
{
"status": "sent",
"due_date": "2024-04-15T00:00:00Z",
"items": [
{
"id": "987fcdeb-51a2-43d7-9012-345678901234",
"quantity": 2,
"unit_price": 95.00
}
]
}Success Response (200):
{
"invoice": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"status": "sent",
"due_date": "2024-04-15T00:00:00Z",
"total": 209.62,
"updated_at": "2024-03-21T11:00:00Z"
}
}Error Responses:
- 400: Invalid invoice ID or request body
- 401: Unauthorized
- 403: Insufficient permissions
- 404: Invoice not found
- 422: Invalid status transition
- 500: Internal server error
Delete Invoice
DELETE /v1/invoices/{id}
Remove invoice and associated items. Only draft invoices can be deleted.
Path Parameters:
- id: Invoice UUID
Success Response (200):
{
"message": "Invoice successfully deleted",
"id": "123e4567-e89b-12d3-a456-426614174000"
}Error Responses:
- 400: Invalid invoice ID
- 401: Unauthorized
- 403: Insufficient permissions
- 404: Invoice not found
- 422: Cannot delete non-draft invoice
- 500: Internal server error
Get Customer Invoices
GET /v1/invoices/customers/{id}
List all invoices for a specific customer with filtering options.
Path Parameters:
- id: Customer UUID
Query Parameters:
- status: Filter by invoice status (draft/pending/paid/sent/overdue)
- date_from: Start date (format: 2024-03-21T00:00:00Z)
- date_to: End date (format: 2024-03-21T23:59:59Z)
- currency: 3-letter currency code (e.g., CHF)
Success Response (200):
{
"customer_id": "550e8400-e29b-41d4-a716-446655440000",
"total_invoices": 50,
"total_amount": 5615.50,
"currency_breakdown": {
"CHF": 4500.00,
"EUR": 1115.50
},
"invoices": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"invoice_number": "INV-2024-000001",
"status": "paid",
"currency": "CHF",
"total": 112.31,
"created_at": "2024-03-21T10:00:00Z"
}
]
}Error Responses:
- 400: Invalid customer ID or query parameters
- 401: Unauthorized
- 403: Insufficient permissions
- 404: Customer not found
- 500: Internal server error
Get Invoice PDF
GET /v1/invoices/{id}/pdf
Generate or retrieve PDF version of an invoice with embedded QR code.
Path Parameters:
- id: Invoice UUID
Query Parameters:
- template: PDF template name (optional, default: "default")
- language: Language code for PDF content (optional, default: "en")
- include_qr: Include QR code in PDF (optional, default: true)
Success Response (200):
{
"content": "JVBERi0xLjcKCjEgMCBvYmogICUgZW50...",
"filename": "INV-2024-000001.pdf",
"content_type": "application/pdf",
"size": 123456
}Error Responses:
- 400: Invalid invoice ID
- 401: Unauthorized
- 403: Insufficient permissions
- 404: Invoice not found
- 422: PDF generation failed
- 500: Internal server error
Get Next Invoice Number
GET /v1/invoices/customers/{id}/next-number
Get the next available invoice number for a customer. The number is reserved for a short period.
Path Parameters:
- id: Customer UUID
Success Response (200):
{
"invoice_number": "INV-20240321-000001",
"expires_at": "2024-03-21T10:05:00Z"
}Error Responses:
- 400: Invalid customer ID
- 401: Unauthorized
- 403: Insufficient permissions
- 500: Internal server error