Documentation for 4.0 (pre-release). Using 3.x? See the README on main.
Skip to content

Reminders (Mahnungen) ​

API wrapper for payment reminders under /reminders and their two sub-resources (/reminder-items, /reminder-tags).

Access ​

php
$billomat->reminders         // reminders
$billomat->reminders->items  // line items of a reminder (read-only)
$billomat->reminders->tags   // tags

The configurable reminder text blocks live in a separate resource: $billomat->reminderTexts (see ReminderTextsApi).

Model ​

A reminder always references an underlying invoice via invoiceId (required on create). Content and line items are generated by Billomat from the original invoice plus the selected reminder text block (reminderTextId), so the reminder-items are read-only.

The lifecycle is status-driven:

DRAFT  ── complete() ──▶  OPEN  ── invoice is paid ──▶  PAID
  │                        │
  │                        ├── due date passed ──▶  OVERDUE
  │                        │
  │                        └── cancel() ──▶  CANCELED  ── uncancel() ──▶  OPEN
  └── delete() (any status; prefer cancel() once completed)

An open reminder can be followed by further dunning levels: Billomat increments the level internally and uses the templates stored as dunning levels in reminderTexts (see Reminder levels).

Endpoint overview ​

/reminders ​

MethodHTTPPath
list($filters?)GET/reminders
listPage($filters?)GET/reminders (one page plus pagination metadata)
iterateAll($filters?, $pageSize?)GET/reminders (all pages, lazily)
get($id) / getOrFail($id)GET/reminders/{id}
create($options)POST/reminders
update($id, $options)PUT/reminders/{id}
delete($id)DELETE/reminders/{id}
complete($id, $templateId?)PUT/reminders/{id}/complete
cancel($id)PUT/reminders/{id}/cancel
uncancel($id)PUT/reminders/{id}/uncancel
email($id, $options?)POST/reminders/{id}/email
pdf($id, $type?)GET/reminders/{id}/pdf
pdfContent($id, $type?)GET/reminders/{id}/pdf?format=pdf
uploadSignature($id, $base64Pdf)PUT/reminders/{id}/upload-signature

/reminder-items ​

MethodHTTPPath
list($reminderId, $filters?)GET/reminder-items?reminder_id={id}
listPage($reminderId, $filters?) / iterateAll($reminderId, $filters?, $pageSize?)GET/reminder-items?reminder_id={id} (paginated)
get($id) / getOrFail($id)GET/reminder-items/{id}

Read-only: there is no create/update/delete and no ReminderItemCreateOptions class. Billomat generates the items from the invoice.

/reminder-tags ​

MethodHTTPPath
list($reminderId, $filters?)GET/reminder-tags?reminder_id={id}
listPage($reminderId, $filters?) / iterateAll($reminderId, $filters?, $pageSize?)GET/reminder-tags?reminder_id={id} (paginated)
cloud()GET/reminder-tags
get($id) / getOrFail($id)GET/reminder-tags/{id}
create($reminderId, $options)POST/reminder-tags
delete($id)DELETE/reminder-tags/{id}

Methods ​

Reminders ​

list(ReminderFilter|array $filters = []): list<Reminder> ​

Billomat filters by client_id, contact_id, invoice_id, invoice_number, status, from, to, tags and more.

The typed filter ReminderFilter is recommended. Its camelCase fields are clientId, contactId, invoiceNumber, status (list<ReminderStatus>), from/to (DateTimeImmutable), label, subject, intro, note, tags and articleId. Multi-value fields are lists and are sent comma-separated. On top of that there are orderBy, page, perPage and extra for further query parameters (e.g. invoice_id). A plain array still works: it is passed through to the query string as is, and array values are sent as key[]=….

php
use Justpilot\Billomat\Api\OrderBy;
use Justpilot\Billomat\Api\ReminderFilter;
use Justpilot\Billomat\Model\Enum\ReminderStatus;

$overdue = $billomat->reminders->list(new ReminderFilter(
    status: [ReminderStatus::OVERDUE],
    orderBy: OrderBy::asc('due_date'),
));

listPage() takes the same filters and returns a Page with pagination metadata; iterateAll() walks through all pages lazily. See Pagination and filtering.

get(int $id): ?Reminder ​

Returns null on 404. Embedded reminder-items are hydrated automatically. getOrFail() throws a NotFoundException instead of returning null.

create(ReminderCreateOptions $options): Reminder ​

Only invoiceId is required. Billomat takes the address, reminder text, due date etc. from the invoice or the client configuration unless you override them.

php
use Justpilot\Billomat\Api\ReminderCreateOptions;

$opts = new ReminderCreateOptions(
    invoiceId: 9876,
    reminderTextId: 42,
    dueDays: 7,
    subject: 'Payment reminder for invoice 2026-0042',
);

$reminder = $billomat->reminders->create($opts);

update(int $id, ReminderUpdateOptions $options): Reminder ​

Only advisable in status DRAFT. invoiceId can no longer be changed here; the link to the invoice is fixed.

complete(int $id, ?int $templateId = null): void ​

Status DRAFT → OPEN. An optional templateId forces a specific layout template.

cancel(int $id): void / uncancel(int $id): void ​

cancel() sets the status to CANCELED, uncancel() reactivates a canceled reminder (CANCELED → OPEN). Reminders have no clear()/unclear() (Billomat answers 404).

email(int $id, ?EmailOptions $options = null): void ​

Without options, Billomat uses all defaults from the configured email template.

php
use Justpilot\Billomat\Api\EmailOptions;

$mail = new EmailOptions(to: ['client@example.com'], subject: 'Reminder: open invoice 2026-0042');

$billomat->reminders->email($reminder->id, $mail);

pdf(int $id, ?PdfType $type = null): ReminderPdf / pdfContent(int $id, ?PdfType $type = null): string ​

pdf() returns a ReminderPdf model (metadata plus base64 body). pdfContent() appends ?format=pdf and returns the binary PDF content directly; it throws an UnexpectedResponseException if the body is empty or doesn't start with %PDF-.

php
$pdf = $billomat->reminders->pdf($reminder->id);                 // model
$raw = $billomat->reminders->pdfContent($reminder->id);        // string (PDF binary)

uploadSignature(int $id, string $base64Pdf): void ​

Attaches a PDF signed by the client to the reminder.

delete(int $id): void ​

Only works on reminders in status DRAFT.

Reminder items (read-only) ​

php
$items = $billomat->reminders->items->list($reminder->id);
$item = $billomat->reminders->items->get($itemId);

There is no ReminderItemCreateOptions and no write endpoint. Items show the original invoice amount and late fees, generated from the configured reminder text block.

Reminder tags ​

php
use Justpilot\Billomat\Api\ReminderTagCreateOptions;

$billomat->reminders->tags->create(
    $reminder->id,
    new ReminderTagCreateOptions(name: 'dunning-level-2'),
);

$tags = $billomat->reminders->tags->list($reminder->id);
$cloud = $billomat->reminders->tags->cloud(); // aggregated, with count

There is no update. To rename a tag, delete it and create it again.

Write model: ReminderCreateOptions ​

Constructor: new ReminderCreateOptions(int $invoiceId, …). invoiceId is required and the first parameter. Every field is a constructor parameter with a default and is passed as a named argument. The object is immutable (final readonly); each field has a with*() method that returns a modified copy (e.g. $opts->withSubject('New')).

PropertyBillomat fieldTypeNotes
invoiceIdinvoice_idint (required)source invoice; can't be changed after creation
contactIdcontact_id?intoverrides the client contact
addressaddress?stringmulti-line address
numberPrenumber_pre?string
numbernumber?intmanual numbering
numberLengthnumber_length?int
datedate?\DateTimeImmutableformatted as Y-m-d
dueDaysdue_days?intdue in days from date
dueDatedue_date?\DateTimeImmutableabsolute due date (overrides dueDays)
subjectsubject?stringletterhead title
labellabel?string
introintro?string
notenote?string
reminderTextIdreminder_text_id?intID from /reminder-texts (reminder text block)
templateIdtemplate_id?intlayout template ID

Write model: ReminderUpdateOptions ​

Mirrors ReminderCreateOptions without invoiceId; the link to the invoice is fixed. Fields left at null are stripped from the payload. Clear::Field instead sends the field as JSON null, and Billomat empties it, e.g. new ReminderUpdateOptions(note: Clear::Field).

Write model: ReminderTagCreateOptions ​

The reminder ID isn't part of the options: pass it as the first argument of create(), which adds reminder_id to the payload.

PropertyBillomat fieldTypeNotes
namenamestring (required)

Write model: EmailOptions ​

Shared class for sending every document type by email (invoices, offers, confirmations, credit notes, delivery notes, reminders, letters); the full description is on the Invoices page.

PropertyBillomat fieldTypeNotes
emailTemplateIdemail_template_id?int
fromfrom?string
torecipients.tolist<string>
ccrecipients.cclist<string>
bccrecipients.bcclist<string>
subjectsubject?string
bodybody?string
filenamefilename?stringname of the PDF attachment
attachmentsattachments.attachmentlist<array{filename,mimetype,base64file}>additional attachments

Empty recipient arrays are left out, so Billomat falls back to the template.

Note on reminder items ​

There is no ReminderItemCreateOptions and no ReminderItemUpdateOptions. Reminder items are generated on the server from the original invoice and the reminder text block; they are read-only.

Read model: Reminder ​

final readonly class Reminder.

PropertyType
idint
clientIdint
contactId?int
invoiceId?int
created?\DateTimeImmutable
status?ReminderStatus
date?\DateTimeImmutable
dueDays?int
dueDate?\DateTimeImmutable
address, subject, label, intro, note?string
totalGross?Money
currencyCode?string
reminderTextId, templateId?int
itemslist<ReminderItem>
updated?\DateTimeImmutable
paidAmount?Money (amount already paid)
openAmount?Money (outstanding amount)
reminderLevel?int (dunning level, see ReminderTextsApi)
reminderLevelName?string (name of the dunning level)
isOld?bool
customfield?string (free-form extra field, see Custom meta attributes)
extraarray<string, mixed> (raw fields the SDK doesn't map yet, see Models)

Read model: ReminderItem ​

final readonly. Leaner than InvoiceItem, with no tax detail fields, since reminder items are display values taken from the original invoice.

PropertyType
idint
reminderId?int
articleId?int
position?int
unit?string
quantity, unitPricefloat, Money
title, description?string
total?Money
isCharge?bool (the item is a dunning fee)
customfield?string (free-form extra field, see Custom meta attributes)
extraarray<string, mixed>

Read model: ReminderTag ​

PropertyType
idint
reminderIdint
namestring
customfield?string (free-form extra field, see Custom meta attributes)
extraarray<string, mixed>

Read model: ReminderTagCloudEntry ​

PropertyType
id?int
namestring
countint
extraarray<string, mixed>

Read model: ReminderPdf ​

final class ReminderPdf.

PropertyType
id, reminderIdint
created?\DateTimeImmutable
filename, mimeTypestring
fileSizeint
base64filestring

getBinary(): string decodes base64file back into raw bytes.

Enums used ​

  • ReminderStatus: DRAFT, OPEN, OVERDUE, PAID, CANCELED. Note: Billomat sets OVERDUE automatically once dueDate has passed; never send it yourself.
  • PdfType: shared PDF variants for pdf().

There is no comment action key enum for reminders: reminders simply have no /reminder-comments resource. Activity is tracked in the comments of the underlying invoice.

Pitfalls ​

  • delete() isn't limited to DRAFT. Billomat's API deletes reminders in any status. Once completed, prefer cancel(): the document is numbered, and deleting it leaves a gap in the number sequence (GoBD).
  • invoiceId is required and immutable. A reminder without an invoice doesn't exist; after create() the link is fixed and not part of ReminderUpdateOptions.
  • Items are read-only. To add line items, adjust the reminder text block (/reminder-texts) or set a different reminderTextId before calling complete().
  • No /reminder-comments endpoint. The activity log and free-form notes belong to the parent invoice workflow, not to the reminder itself.
  • dueDate beats dueDays. If both are set, the absolute due_date wins. It is cleaner to maintain only one of the two fields.
  • A reminderTextId without a matching entry in /reminder-texts leads to 422. Before create(), make sure the reminder text block exists (via $billomat->reminderTexts->list()).
  • Status OVERDUE is read-only. It is set on the server; the write models have no status field at all.
  • Multiple dunning levels for the same invoice are possible. A second reminder for the same invoice automatically gets the next dunning level according to the levels configured in reminderTexts (ReminderTextsApi).
  • Tag cloud and list share the same endpoint. GET /reminder-tags without reminder_id returns the aggregated cloud (tag wrapper); with reminder_id it returns the actual tags (reminder-tag wrapper). The SDK splits this into cloud() and list().

End-to-end example ​

php
<?php

declare(strict_types=1);

require __DIR__ . '/vendor/autoload.php';

use Justpilot\Billomat\Api\EmailOptions;
use Justpilot\Billomat\Api\InvoiceFilter;
use Justpilot\Billomat\Api\OrderBy;
use Justpilot\Billomat\Api\ReminderCreateOptions;
use Justpilot\Billomat\Api\ReminderTagCreateOptions;
use Justpilot\Billomat\BillomatClient;
use Justpilot\Billomat\Model\Enum\InvoiceStatus;

$billomat = BillomatClient::create(
    billomatId: 'mycompany',
    apiKey: getenv('BILLOMAT_API_KEY'),
);

// 1) Pick an open invoice
$openInvoices = $billomat->invoices->list(new InvoiceFilter(
    clientId: 12345,
    status: [InvoiceStatus::OPEN],
    orderBy: OrderBy::asc('due_date'),
));

if ([] === $openInvoices) {
    exit('No open invoice to remind.');
}

$invoice = $openInvoices[0];

// 2) Choose a reminder text block (e.g. the first level)
$reminderTexts = $billomat->reminderTexts->list();
$firstStage = $reminderTexts[0] ?? null;

// 3) Create the reminder as a draft
$opts = new ReminderCreateOptions(
    invoiceId: $invoice->id,
    reminderTextId: $firstStage?->id,
    dueDays: 7,
    subject: 'Payment reminder for invoice ' . ($invoice->invoiceNumber ?? ''),
);

$reminder = $billomat->reminders->create($opts);
printf("Reminder #%d created (status: %s)\n",
    $reminder->id,
    $reminder->status?->label() ?? 'unknown',
);

// 4) Add a tag (e.g. the dunning level) before completing
$billomat->reminders->tags->create(
    $reminder->id,
    new ReminderTagCreateOptions(name: 'dunning-level-1'),
);

// 5) Complete: DRAFT → OPEN
$billomat->reminders->complete($reminder->id);

// 6) Send by email
$mail = new EmailOptions(
    to: ['client@example.com'],
    subject: 'Reminder: invoice still open',
    body: "Hello,\n\nplease settle our open invoice.\n\nBest regards",
);
$billomat->reminders->email($reminder->id, $mail);

// 7) Save the PDF locally
$pdfBinary = $billomat->reminders->pdfContent($reminder->id);
file_put_contents("reminder-{$reminder->id}.pdf", $pdfBinary);

// 8) Inspect the generated reminder items (read-only)
foreach ($billomat->reminders->items->list($reminder->id) as $item) {
    printf("- %s: %s\n", $item->title ?? 'Item', $item->total?->format(2) ?? '-');
}

Unofficial SDK, not affiliated with Billomat GmbH. Released under the Apache License 2.0.