PlanDocket

Invoices

Business+

Create, issue, send, download and cancel invoices. Every rule of the admin applies (GoBD): drafts get their number only when they are issued, issued invoices are locked and are corrected only by cancelling them with a credit note.

Required scopes: invoices
Access level: GET invoices:read POST / PUT / PATCH / DELETE invoices:write About access levels
Feature flag: invoices

Endpoints

GET /api/v1/invoices

List all invoices (open_amount already subtracts payments, credit notes and write-offs)

GET /api/v1/invoices/{id}

Retrieve a single invoice with its lines (include=payments,credit_notes,contact for more)

POST /api/v1/invoices

Create a draft for a participation (event_participant_id) or a contact (contact_id). Lines come from "items" (description, quantity, unit_price net, tax_rate from your invoice settings) and/or the participation's open billable items (booth, service orders, documents; default when no items are given; "billable_item_ids" picks single ones). The due date defaults to the payment terms. "issue": true issues it right away (optional "invoice_date"), "send": true also e-mails it. Returns 201 with the invoice; problems with issuing or sending are listed in "warnings". Fires invoice.created

PUT/PATCH /api/v1/invoices/{id}

Update an invoice: notes and due_date (also on issued invoices); status "sent" on a draft issues it (like POST /issue), status "cancelled" cancels it (like POST /cancel, with "cancellation_reason"). paid, partially_paid, overdue and refunded follow from payments, credit notes and the dunning run and are rejected with 422

POST /api/v1/invoices/{id}/issue

Issue a draft: assigns the next invoice number and the invoice date (today or "invoice_date", at most back to the start of the previous month and never before the last issued invoice) and locks it. 422 for an invoice without lines or one that is already issued

POST /api/v1/invoices/{id}/send

E-mail the invoice PDF (plus the XRechnung XML) to the customer's billing address or to "to" (cc, bcc, subject and a personal "message" are optional). A draft is issued first, so the attachment always carries the final number. The text uses the customer's language. Fires invoice.sent

GET /api/v1/invoices/{id}/pdf

Download the invoice PDF (application/pdf). Issued e-invoices are served from the archive; drafts carry a draft watermark

GET /api/v1/invoices/{id}/e-invoice

Download the e-invoice: format=xrechnung (default output: XML) or zugferd (default output: hybrid PDF); output=xml|pdf overrides it. Only the format set on the invoice is available; issued invoices come from the archive. 422 when e-invoicing is not enabled or master data is missing

POST /api/v1/invoices/{id}/cancel

Cancel an invoice (Storno). An issued invoice is never edited: the open remainder is reversed by a credit note (one line per tax rate); "reason" is required and documented. A draft is simply discarded. Optional "send_credit_note": true e-mails the credit note. Returns invoice and credit_note. Fires invoice.cancelled and credit_note.created. 409 if already cancelled, 422 for credit notes and refunded invoices

Query Parameters

Parameter Description
status Filter by invoice status
customer_number Filter by customer number
event_key Filter by event key
type Filter by invoice type (invoice, credit_note)
sort Sort field (invoice_number, invoice_date = issue date, empty for drafts and sorted last, total, status, due_date, created_at)
order Sort direction (ASC or DESC, default: DESC)
include Include related data (items, payments, contact, credit_notes)
format e-invoice only: xrechnung or zugferd (default: the format set on the invoice)
output e-invoice only: xml or pdf (default: xml for XRechnung, pdf for ZUGFeRD)

Request Schema

Parameter Type Required Description
event_participant_id integer No Create: participation to invoice (one of event_participant_id or contact_id)
contact_id integer No Create: contact to invoice without an event
items array No Create: lines [{"description", "quantity" (default 1), "unit_price" (net), "tax_rate" (one of your invoice tax rates, default the highest)}]
include_billable_items boolean No Create: add the participation's open billable items (booth, service orders, documents). Default: true when no items are given
billable_item_ids array No Create: only these open billable items
due_date string No Due date (YYYY-MM-DD or ISO 8601). Default on create: invoice date + payment terms
service_date string No Create: service date (YYYY-MM-DD; default the event start)
is_reverse_charge boolean No Create: reverse charge (0 % VAT; only for EU customers with a VAT ID abroad)
e_invoice_format string No Create: none, xrechnung or zugferd
leitweg_id string No Create: Leitweg-ID for public-sector XRechnung recipients
buyer_reference string No Create: buyer reference (BT-10) when there is no Leitweg-ID
issue boolean No Create: issue the invoice right away (number + invoice date)
invoice_date string No Create with issue / POST issue: invoice date (YYYY-MM-DD, default today)
send boolean No Create: issue and e-mail the invoice right away (to = billing e-mail or "send_to")
status string No PATCH only: "sent" issues a draft, "cancelled" cancels the invoice. Payment states (paid, partially_paid, overdue, refunded) cannot be set (422)
notes string No Internal notes for the invoice
reason string No POST cancel: cancellation reason (required for issued invoices)
to string|array No POST send: recipient address(es); default the billing e-mail of the customer. Also cc, bcc, subject, attach_xml
message string No POST send: personal text inserted after the greeting

Response Schema

Field Type
id integer
invoice_number string|null
display_number string
invoice_type string
related_invoice_id integer|null
status string
event_participant_id integer|null
contact_id integer|null
invoice_date string|null
issued_at string|null
total float
currency string
credited_amount float
paid_amount float
written_off_amount float
open_amount float
service_date string|null
due_date string|null
is_reverse_charge boolean
is_locked boolean
locked_at string|null
sent_at string|null
reminder_sent_at string|null
reminder_count integer
cancellation_reason string|null
e_invoice_format string
e_invoice_status string|null
leitweg_id string|null
buyer_reference string|null
po_number string|null
notes string|null
links object
created_at string
updated_at string

Code Examples

curl -X POST "https://your-tenant.plandocket.com/api/v1/invoices" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "event_participant_id": 7,
    "items": [
        {
            "description": "Standfläche Halle A, 12 m²",
            "quantity": 12,
            "unit_price": 75,
            "tax_rate": 19
        }
    ],
    "include_billable_items": false,
    "issue": true
}'
<?php
$apiKey = 'YOUR_API_KEY';
$baseUrl = 'https://your-tenant.plandocket.com';

$payload = [
    'event_participant_id' => 7,
    'items' => [
        [
            'description' => 'Standfläche Halle A, 12 m²',
            'quantity' => 12,
            'unit_price' => 75,
            'tax_rate' => 19,
        ],
    ],
    'include_billable_items' => false,
    'issue' => true,
];

$ch = curl_init();
curl_setopt_array($ch, [
    CURLOPT_URL => $baseUrl . '/api/v1/invoices',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode($payload),
]);

$response = curl_exec($ch);
curl_close($ch);

$data = json_decode($response, true);
print_r($data);
const apiKey = 'YOUR_API_KEY';
const baseUrl = 'https://your-tenant.plandocket.com';

const payload = {
    "event_participant_id": 7,
    "items": [
        {
            "description": "Standfläche Halle A, 12 m²",
            "quantity": 12,
            "unit_price": 75,
            "tax_rate": 19
        }
    ],
    "include_billable_items": false,
    "issue": true
};

const response = await fetch(`${baseUrl}/api/v1/invoices`, {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(payload),
});

const data = await response.json();
console.log(data);
import requests

api_key = 'YOUR_API_KEY'
base_url = 'https://your-tenant.plandocket.com'

headers = {
    'Authorization': f'Bearer {api_key}',
}

payload = {
    'event_participant_id': 7,
    'items': [
        {
            'description': 'Standfläche Halle A, 12 m²',
            'quantity': 12,
            'unit_price': 75,
            'tax_rate': 19,
        },
    ],
    'include_billable_items': False,
    'issue': True,
}

response = requests.request('POST', f'{base_url}/api/v1/invoices', headers=headers, json=payload)
data = response.json()
print(data)

Sample Response

200 OK
{
    "data": {
        "id": 1,
        "invoice_number": "string",
        "display_number": "string",
        "invoice_type": "string",
        "related_invoice_id": 1,
        "status": "string",
        "event_participant_id": 1,
        "contact_id": 1,
        "invoice_date": "2026-01-15T10:00:00+01:00",
        "issued_at": "2026-01-15T10:00:00+01:00",
        "total": 100,
        "currency": "string",
        "credited_amount": 100,
        "paid_amount": 100,
        "written_off_amount": 100,
        "open_amount": 100,
        "service_date": "2026-01-15T10:00:00+01:00",
        "due_date": "2026-01-15T10:00:00+01:00",
        "is_reverse_charge": true,
        "is_locked": true,
        "locked_at": "2026-01-15T10:00:00+01:00",
        "sent_at": "2026-01-15T10:00:00+01:00",
        "reminder_sent_at": "2026-01-15T10:00:00+01:00",
        "reminder_count": 1,
        "cancellation_reason": "string",
        "e_invoice_format": "string",
        "e_invoice_status": "string",
        "leitweg_id": "string",
        "buyer_reference": "string",
        "po_number": "string",
        "notes": "string",
        "links": {},
        "created_at": "2026-01-15T10:00:00+01:00",
        "updated_at": "2026-01-15T10:00:00+01:00"
    }
}