Invoice API
REST endpoint for creating and issuing invoices from external systems, authenticated with rotatable API tokens.
The invoice API creates and issues invoices through a single REST endpoint. The sender is bound to the token in use and is not passed in the request. Issued invoices receive a sequential, gapless number and a PDF; the operation cannot be undone.
Behavior overview:
- Every successful request issues the invoice immediately and permanently.
- Clients are referenced by an existing id, or created when a name is provided. Bookings cannot be referenced through the API; such fields are rejected.
- Amounts are accepted as strings in German number format (
"1.234,50") or as numbers.
Plan-dependent: the invoice API is a separate plan feature. If it is not enabled, the endpoint responds with
403 FEATURE_LOCKED.
Endpoint
POST https://app.kreativmind.at/api/public/invoices
Content-Type: application/json
Authorization: Bearer <token>
Authentication
Requests authenticate with a bearer token in the Authorization header. Tokens are managed under Settings → Billing and are bound to exactly one sender.
- The token is output in plaintext exactly once, at creation and rotation, and stored server-side only as a SHA-256 hash.
- Rotation invalidates the previous token immediately; the sender binding is preserved.
- Revoked tokens are rejected with
403 TOKEN_REVOKED.
Example
curl -X POST https://app.kreativmind.at/api/public/invoices \
-H "Authorization: Bearer $INVOICE_API_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-2026-0042" \
-d '{
"client": {
"name": "Musterfirma GmbH",
"email": "office@musterfirma.at",
"addressStreet": "Hauptstraße 1",
"addressZip": "1010",
"addressCity": "Wien"
},
"serviceDate": "2026-06-30",
"items": [
{
"name": "Photo shoot",
"unit": "h",
"unitPrice": "120,00",
"quantity": "3",
"taxRate": "20"
}
]
}'
Request
The request body is JSON. Required: a client reference, a service date and at least one line item. Unset optional fields fall back to the sender's defaults.
Client
Either pass an existing client id, or — without an id — at least client.name. In the latter case the client is created; the generated id is returned in the response and can be reused for subsequent invoices.
| Field | Type | Description |
|---|---|---|
client.id | string | Id of an existing client. Must belong to the account, otherwise 422. |
client.name | string | Required when client.id is absent. Creates a new client. |
client.email | string | Optional; only used on creation. |
client.addressStreet / addressZip / addressCity / addressCountry | string | Optional; only used on creation. |
Client creation counts against the plan's client limit (403 LIMIT_REACHED when exceeded).
Service date
At least one of the following fields is required (422 VALIDATION_ERROR otherwise):
| Field | Type | Description |
|---|---|---|
serviceDate | date | Service date, ISO 8601 (2026-06-30). |
serviceFrom / serviceTo | date | Service period. serviceTo is optional. |
servicePeriodText | string | Free text, e.g. "June 2026". |
Line items (items[])
At least one item is required.
| Field | Type | Description |
|---|---|---|
name * | string | Item description. |
unitPrice * | string | number | Net unit price. |
quantity * | string | number | Quantity. |
unit | string | Unit. Default: "Stk". |
taxRate | string | number | VAT rate in percent. Defaults to the sender's standard rate. |
discountPercent | string | number | Line-item discount in percent. |
Additional fields
| Field | Type | Description |
|---|---|---|
title / introText / footerText | string | Invoice title, intro and footer text. Sender defaults apply when unset. |
dueDate | date | Due date. The sender's payment terms apply when unset. |
currency | string | ISO currency code. Default: EUR. |
discountType / discountValue | enum / string | number | Total discount: NONE, PERCENT or AMOUNT with the corresponding value. |
skontoPercent / skontoDays | string | number / number | Early-payment discount in percent and days. |
Response
201 Created with the references of the issued invoice:
{
"invoiceId": "cmck3…",
"number": "2026-014",
"clientId": "cmck1…",
"clientCreated": true,
"pdfUrl": "https://app.kreativmind.at/api/public/billing/…/pdf",
"viewUrl": "https://app.kreativmind.at/inv/…"
}
| Field | Type | Description |
|---|---|---|
invoiceId | string | Id of the created invoice. |
number | string | Assigned gapless invoice number. |
clientId | string | Id of the linked client. |
clientCreated | boolean | true if the client was created by this request. |
pdfUrl | string | Public PDF download of the invoice. |
viewUrl | string | Public invoice view page. |
Errors
Error responses are JSON with a machine-readable code. Validation errors additionally carry field codes in the fields object.
| Status | Code | Meaning |
|---|---|---|
| 401 | NOT_AUTHENTICATED | Authorization header missing, token unknown or rotated. |
| 403 | TOKEN_REVOKED | The token has been revoked. |
| 403 | SENDER_ARCHIVED | The bound sender is archived. |
| 403 | TENANT_LOCKED | The account is locked. |
| 403 | FEATURE_LOCKED / LIMIT_REACHED / NO_PACKAGE | Feature not in the plan or plan limit reached. |
| 422 | VALIDATION_ERROR | Invalid request. fields names the affected fields, e.g. { "client.name": "REQUIRED" }. |
| 500 | SERVER_ERROR | Unexpected error. Retry the request with the same idempotency key. |
If the body contains bookingId or orderId, the request is rejected with 422 and { "bookingId": "NOT_ALLOWED" }.
Idempotency
The optional Idempotency-Key header prevents duplicate invoices on retries (timeouts, automatic retry logic). A repeated request with the same key returns the originally created invoice with 200 instead of assigning another number.
Idempotency-Key: order-2026-0042
Use a stable, business-level key per transaction, such as the calling system's internal order id.