Appearance
Invoice
Allowed query parameters
Filters
| Filter | Type | Description |
|---|---|---|
search | String | Full-text search |
own | Boolean | Show only own invoices |
project | Id | Filter by Project Id |
company | String | Filter by Company Id |
contact | String | Filter by Contact Id |
product | String | Filter by Product Id |
status | String | Filter based on status:paid, pending, overdue, draft, dunned, paidOrPending, cancelled |
date_range | DateRange | Filter by issued date<start-date>,<end-date> |
total_range | NumberRange | Filter by total amount<min-amount>,<max-amount> or just <min-amount> |
net_total_range | NumberRange | Filter by net total amount<min-amount>,<max-amount> or just <min-amount> |
member | String | Filter by Member Id |
recurring | Boolean | Show only recurring invoices |
exported | Boolean | Show only exported invoices |
custom_field | Key,String | Filter by Custom Field (eg. my_internal_id,42) |
trashed | Boolean | Include soft-deleted invoices |
Sorting
issued_at, due_at, paid_at, number_sequence, created_at
Includes
project.invoices, project.unbilledExpenses, contact.company.media, company.media, elements.tag, elements.product, member.user.media, createdBy.user.media, updatedBy.user.media, activities, expenses, expensesCount, lockedTimes, lockedTimesCount, sourceOffer, bankAccount, commentsCount, comments.commentator.media, payments.bankAccount, media, latestOutgoingMail
Appends
(Available append parameters for additional computed fields)
current_dunning_level, next_dunning_level, auto_dunning_active, dunning_text, vat_detailed
vat_detailed contains the invoice's VAT amounts grouped by VAT Rate: [{ "id": <vat-rate-id|null>, "rate": 7.7, "total": 8271.35, "amount": 591.35 }], where total is the gross amount and amount the VAT share (both in document currency).
Create an invoice
post
/invoice
| Attribute (* required) | Type | Description |
|---|---|---|
name | String? | Invoice title (max 255 characters) |
project_id | String? | A Project Id (min 10 characters). For a sub-project, its parent is assigned |
contact_id * | String | A Contact Id (min 10 characters) |
include_vat | Boolean | With/without taxes |
issued_at | Date | Issue date |
due_at | Date? | Due date (must be after or equal to issued_at) |
due_within | Number? | Due in days (0-365, used when due_at is empty) |
paid_at | Date? | Deprecated — Paid date (on or after issued_at) |
description | String? | Invoice description |
reminded | Number | Dunning level (0 to max dunning levels) |
address | String? | Recipient Address |
header | String? | Header text |
footer | String? | Footer text |
has_page_break_after_header | Boolean | Add page break after header |
has_page_break_before_footer | Boolean | Add page break before footer |
recurring_type | String? | Recurrence type (weeks, months, years) |
recurring_every | Number? | Recurrence interval (1-99) |
recurring_ends_at | Date? | Recurrence end date |
revenue_account_no | String? | Revenue account number |
bank_account_id | String? | Bank account ID (min 10 characters) |
custom_fields | Object? | Custom data as Custom Fields |
Deprecated: paid_at
Setting paid_at directly still works for backwards compatibility, but is deprecated and will not mark the invoice as paid the way the app does — it fires no paid side effects (no Paid webhook, notifications, or dashboard updates). To record a payment, add an invoice payment or use Update invoice status with status: paid.
Example response
json
// HTTP 201 Created
{
// an invoice object
}Update an invoice
put
/invoice/{id}
| Attribute (* required) | Type | Description |
|---|---|---|
name | String? | Invoice title (max 255 characters) |
project_id | String? | A Project Id (min 10 characters). For a sub-project, its parent is assigned |
contact_id | String | A Contact Id (min 10 characters) |
total | Number? | Total amount (max 99999999.99) |
include_vat | Boolean | With/without taxes |
is_scheduled_for_sending | Boolean | Schedule invoice for auto-sending |
issued_at | Date | Issue date (must be before or equal to due_at) |
due_at | Date | Due date (must be after or equal to issued_at) |
paid_at | Date? | Deprecated — Paid date (on or after issued_at) |
sent_at | Date? | Sent date |
description | String? | Invoice description |
reminded | Number | Dunning level (0 to max dunning levels) |
is_dunning_paused | Boolean | Exclude from automatic dunning («Mahnstopp») |
address | String | Recipient Address |
header | String? | Header text |
footer | String? | Footer text |
has_page_break_after_header | Boolean | Add page break after header |
has_page_break_before_footer | Boolean | Add page break before footer |
recurring_type | String? | Recurrence type (weeks, months, years) |
recurring_every | Number? | Recurrence interval (1-99) |
recurring_ends_at | Date? | Recurrence end date |
revenue_account_no | String? | Revenue account number |
is_exported | Boolean | Whether invoice has been exported |
bank_account_id | String? | Bank account ID (min 10 characters) |
custom_fields | Object? | Custom data as Custom Fields |
Deprecated: paid_at
Setting paid_at directly still works for backwards compatibility, but is deprecated and will not mark the invoice as paid the way the app does — it fires no paid side effects (no Paid webhook, notifications, or dashboard updates). To record a payment, add an invoice payment or use Update invoice status with status: paid.
Example response
json
// HTTP 200 OK
{
// an invoice object
}Dunning pause («Mahnstopp»)
is_dunning_paused: true takes a single invoice out of the automatic reminder run and stamps dunning_paused_at with the current time; sending false clears it again. Re-sending true on an already paused invoice keeps the original timestamp. The pause suppresses automatic reminders only — the invoice stays overdue, keeps its dunning level, and can still be dunned manually. It is cleared automatically when the invoice is set back to draft, and is never copied to a cloned or recurring follow-up invoice.
The pause is an update-only field: sending is_dunning_paused when creating an invoice is rejected (new invoices are never paused). dunning_paused_at is read-only: it is rejected on create and silently ignored on update (so a client may echo the whole invoice back) — write the boolean instead, so the original “paused since” date is preserved.
The read-only auto_dunning_active field tells you whether this invoice will actually be dunned automatically: it is true only when the invoice is not paused and automatic reminders are effectively on — the customer’s company setting decides when it is set (it can switch reminders on even if the organization default is off), otherwise the organization default applies. Resolving it can cost an extra query per invoice, so it is only returned when you ask for it: ?append=auto_dunning_active.
Retrieve an invoice
get
/invoice/{id}
Example response
json
// HTTP 200 OK
{
"id": "D4rNdYjlGy",
"number": "RE-01234",
"name": "Jahresretainer 2023",
"description": null,
"reminded": 0,
"current_dunning_level": null,
"next_dunning_level": null,
"dunning_text": null,
"is_dunning_paused": false,
"dunning_paused_at": null,
"auto_dunning_active": true,
"total": 7680.0,
"total_with_vat": 8271.35,
"external_total": 0.0,
"total_paid": 0.0,
"total_open": 8271.35,
"include_vat": true,
"vat_detailed": [
{
"id": "eqNdV92mQ3",
"rate": 7.7,
"total": 8271.35,
"amount": 591.35
}
],
"status": "pending",
"is_paid": false,
"is_sent": false,
"is_scheduled_for_sending": false,
"is_rfd": false,
"is_locked": true,
"is_exported": false,
"is_overdue": false,
"is_overpaid": false,
"is_cancelled": false,
"issued_at": "2022-09-19",
"due_at": "2022-10-19",
"sent_at": null,
"locked_at": "2022-09-19T13:51:35.000000Z",
"paid_at": null,
"cancelled_at": null,
"days_overdue": 0,
"payable_in_days": 30,
"address": "<p><strong>StrawBlond</strong><br> Alice Cooper<br>Rütistrasse 2<br>CH-8645 Rapperswil</p>",
"header": "<p>Sehr geehrte Damen und Herren</p><p>Vielen Dank für Ihren Auftrag. Wir stellen Ihnen folgende Leistungen/Lieferungen in Rechnung:</p>",
"footer": "<p>Vielen Dank für eine fristgerechte Zahlung.</p><p>Freundliche Grüsse<br>StrawBlond GmbH</p>",
"address_personalized": "<p><strong>StrawBlond</strong><br> Alice Cooper<br>Rütistrasse 2<br>CH-8645 Rapperswil</p>",
"header_personalized": "<p>Sehr geehrte Damen und Herren</p><p>Vielen Dank für Ihren Auftrag. Wir stellen Ihnen folgende Leistungen/Lieferungen in Rechnung:</p>",
"footer_personalized": "<p>Vielen Dank für eine fristgerechte Zahlung.</p><p>Freundliche Grüsse<br>StrawBlond GmbH</p>",
"has_page_break_after_header": false,
"has_page_break_before_footer": false,
"show_qrbill": true,
"pdf_url": "https://api.blond.swiss/api/invoice/1502/pdf?expires=1666195512&signature=af336a31dc989b7755b4a1391e7134226d5697e926711080130aaa12b2689470",
"pdf_dunning_url": "https://api.blond.swiss/api/invoice/1502/pdf?expires=1666195512&options%5BwithDunningText%5D=1&signature=f476ce81ccc72230e5efdb9e7cc09af83f4b7fdf266dfd176fbd72e066400d14",
"preview_url": "https://api.blond.swiss/api/invoice/1502/view?signature=89c4deac39578b4a961a15eddb7a2c648edeb60ccd30a091c13cc8cd48435d30",
"mail_preview_url": "https://api.blond.swiss/api/document/mail-preview?type=invoice&id=D4rNdYjlGy",
"project": {
// Project object when included
},
"contact": {
// Contact object when included
},
"member": {
// Member object when included
},
"created_by": {
// Member object when included
},
"updated_by": {
// Member object when included
},
"company": {
// Company object when included
},
"elements": [
// Only present when included `elements` relation
{
// a document element object
}
],
"activities": [
// Only present when included `activities` relation
],
"expenses": [
// Only present when included `expenses` relation
],
"locked_times": [
// Only present when included `lockedTimes` relation
],
"locked_times_count": 0,
"attachments_download_url": null,
"source_offer": {
// Offer object when included
},
"revenue_account_no": "3000",
"is_recurring": false,
"recurring_invoice": {
// Invoice object when included
},
"recurring_type": null,
"recurring_every": 1,
"recurring_ends_at": null,
"next_recurring_issue_date": null,
"next_recurring_due_date": null,
"bank_account_id": "AbCdEfGhIj",
"bank_account": {
// BankAccount object when included
},
"comments": [
// Only present when included `comments` relation
],
"comments_count": 3, // Only present when included `commentsCount`
"payments": [
// Only present when included `payments` relation
],
"payment_status": "unpaid",
"attachments": [
// Only present when included `media` relation
],
"latest_outgoing_mail": {
// Only present when included `latestOutgoingMail` relation, see Delivery status
},
"custom_fields": {},
"created_at": "2022-09-19T13:50:07.000000Z",
"updated_at": "2022-09-19T13:51:35.000000Z",
"deleted_at": null
}Delivery status
Include latestOutgoingMail to see whether the last email sent for the invoice (the invoice itself or a payment reminder) reached its recipients. It is null when the invoice was never emailed, and only returned when the API user may see the outgoing mail log.
| Attribute | Type | Description |
|---|---|---|
id | String | ID of the outgoing email |
subject | String | Subject of the email |
recipients | Array | All recipients (to, cc and bcc) |
delivery_status | String? | sent, deferred, delivered or failed; null when the email went out over the organization's own SMTP server |
recipient_statuses | Object? | Per recipient (lowercase address): status, at and, for a failed delivery, the receiving server's reason |
created_at | String | When the email was sent |
failed means at least one recipient's server rejected the email or it could not be delivered; delivered means every recipient's server accepted it.
json
"latest_outgoing_mail": {
"id": "bG8mEqYmMZ",
"subject": "Rechnung: Website Relaunch",
"recipients": ["anna@example.com", "accounting@example.com"],
"delivery_status": "failed",
"recipient_statuses": {
"anna@example.com": { "status": "delivered", "at": "2026-10-23T09:24:15+00:00" },
"accounting@example.com": {
"status": "failed",
"reason": "550 5.1.1 Recipient address rejected: User unknown",
"at": "2026-10-23T09:24:16+00:00"
}
},
"created_at": "2026-10-23T09:24:10.000000Z"
}Delete an invoice
delete
/invoice/{id}
Moves a draft invoice to the trash. Deleting an invoice that is already in the trash (filter[trashed]=only) removes it permanently.
Deleting a draft releases the time entries and expenses it billed, so they can be billed again.
A locked invoice (is_locked: true) cannot be deleted and returns 422 Unprocessable Entity. To void a sent invoice, cancel it instead.
Example response
json
// HTTP 204 No ContentDelete many invoices
post
/invoice/delete-many
Deletes multiple draft invoices at once. The request body is a JSON array of invoice ids. Returns 200 OK with deleted and skipped arrays — see Bulk delete.
When the array contains a locked invoice, the request returns 422 Unprocessable Entity and deletes none of the invoices.
List invoices
get
/invoice
The list endpoint accepts the same parameters as in Retrieve an invoice and returns a paginated array of the same invoice object in the data property.
Read more about Pagination, Filtering, Sorting and Includes on the Introduction page.
Invoice line items
You may use the Document Element endpoint to create, update or delete line items on an invoice.
Line items of a locked invoice (is_locked: true) are frozen — see Locked documents.
Add products to an invoice
post
/invoice/{id}/add-products
| Attribute (* required) | Type | Description |
|---|---|---|
products * | Array | Array of Product IDs to add to the invoice |
beforeOrder | Number? | Order position to insert products before (if not provided, adds to the end) |
Fails with 422 Unprocessable Entity when the invoice is locked.
Example request
json
{
"products": ["6k2KpJY3By", "8m3LqKZ4Cx"],
"beforeOrder": 2
}Example response
json
// HTTP 200 OK
{
// an invoice object
}Update invoice status
post
/invoice/{id}/status
Updates the status of an invoice, handling appropriate transitions and side effects like payments, notifications, and activity logging.
| Attribute (* required) | Type | Description |
|---|---|---|
status * | String | Invoice status: draft, pending, or paid |
paid_at | Date? | Payment date (required when status is paid) |
notify_customer | Boolean | Send notification to customer when marking as paid (default: false) |
Status transitions
- draft: Removes all payments, unlocks invoice, clears sent/paid dates and cancels scheduled sending (
is_scheduled_for_sendingbecomesfalse) - pending: Locks invoice, marks as sent, removes latest payment if exists
- paid: Creates payment record for remaining balance, sets paid date
Example request
json
{
"status": "paid",
"paid_at": "2023-10-15",
"notify_customer": true
}Example response
json
// HTTP 200 OK
{
// an invoice object
}Send an invoice
post
/invoice/{id}/send
| Attribute (* required) | Type | Description |
|---|---|---|
recipients | String | Array | List of emails, as an array or a string separated by ";" (max. 5, Default: Contact email) |
increaseDunningLevel | Boolean | Auto increase dunning level on overdue invoice |
message | String? | Custom message to include with the invoice (max. 5000 characters, links are removed) |
ccToOwner | Boolean | Send a carbon copy to self |
adjustDates | Boolean | Adjust dates to today on draft invoice |
attachments | Array | Array of media UUIDs to attach to the invoice |
Sending limits
A document can be sent to at most 5 recipients per request. Organizations without a paid subscription are limited to 10 recipient deliveries per day across all invoices and offers; exceeding either limit returns 422 Unprocessable Entity with a descriptive message.
No recipient
When no recipients are given and the invoice's contact has no email address, there is nobody to send to: the request fails with 422 Unprocessable Entity and a descriptive message, and the invoice is left unchanged (not locked, not marked as sent).
Test mode without a subscription
Without an active paid subscription, documents are not delivered to the given recipients: the email is redirected to the sending user's own (verified) email address instead and carries a notice naming the original recipients. The response is still 200 OK and the document is marked as sent.
Example response
json
// HTTP 200 OK
{
// an invoice object
}Invoice payments
You can manage incoming customer payments for invoices using the Invoice Payment endpoints. These payments automatically handle overpayments, update invoice payment status, and integrate with customer account management for comprehensive payment tracking.
Invoice status
status sums up where an invoice stands:
| Value | Meaning |
|---|---|
draft | Not locked yet (is_locked: false) |
scheduled | Locked and scheduled for sending (is_scheduled_for_sending: true) |
pending | Locked and open, not yet due |
overdue | Locked, open and past due_at |
paid | Fully settled |
cancelled | Fully cancelled without any customer payment, see Cancelled invoices |
Cancelled invoices
A sent invoice that should not have been issued is cancelled with an invoice payment of type cancellation. A cancelled invoice keeps its number and returns:
| Attribute | Type | Description |
|---|---|---|
status | String | cancelled |
is_cancelled | Boolean | true when the invoice has a cancellation payment, no customer_payment, customer_debit or customer_credit, and is fully settled |
cancelled_at | Date? | The executed_at of the cancellation, null when is_cancelled is false |
is_paid | Boolean | false, even though nothing is left open |
Filter cancelled invoices with filter[status]=cancelled. When an invoice becomes fully cancelled, the invoice/cancelled webhook event is sent. Cancelling the remainder of a partly paid invoice settles it instead: it gets status paid and sends invoice/paid.