For each invoice, Billomat records a stream of comments: some are system-generated (status changes, received payments, emails sent), some are written manually by users. Both kinds live in the same resource and differ only in the actionkey field:
System comments have actionkey set (COMPLETE, PAYMENT, EMAIL, …) and user_id = null.
Manual comments usually have no actionkey and a specific user_id.
Lists all comments of an invoice. You can optionally filter by InvoiceCommentActionKey values; the list is sent to Billomat comma-separated. Passing a different enum throws an InvalidArgumentException.
php
use Justpilot\Billomat\Api\OrderBy;use Justpilot\Billomat\Api\SubResourceFilter;use Justpilot\Billomat\Model\Enum\InvoiceCommentActionKey;// All comments$all = $billomat->invoices->comments->list(98765);// Only payment and dunning entries$financial = $billomat->invoices->comments->list( 98765, [InvoiceCommentActionKey::PAYMENT, InvoiceCommentActionKey::DUNNING],);// Newest first, 20 per page$latest = $billomat->invoices->comments->list( 98765, filters: new SubResourceFilter(orderBy: OrderBy::desc('created'), perPage: 20),);
SubResourceFilter (orderBy, page, perPage, extra) sorts and paginates. listPage() and iterateAll() take the same arguments (iterateAll() additionally $pageSize); see Pagination.
use Justpilot\Billomat\Api\InvoiceCommentCreateOptions;$comment = $billomat->invoices->comments->create( 98765, new InvoiceCommentCreateOptions( comment: 'Client called for clarification; call back scheduled for 2026-06-05.', ),);
actionkey is optional and should be left empty for manual comments; Billomat fills it automatically for system actions.
Constructor: new InvoiceCommentCreateOptions(string $comment, …). The object is immutable (final readonly) and has a with*() method per field. The invoice ID is the first argument of create(), which adds it to the payload as invoice_id.
Property
Billomat field
Type
Notes
comment
comment
string
Required (constructor)
actionkey
actionkey
?InvoiceCommentActionKey
Rarely set manually
public
public
?bool
Visible in the client's activity list (Billomat default: false)
Billomat doesn't document a closed list. If new values show up, the SDK parses actionkey to null and fills actionkeyRaw with the original string, so nothing is lost.
Invoice Comments (Rechnungskommentare)
API wrapper for invoice comments at
/invoice-comments.Access
The generic
Justpilot\Billomat\Api\CommentsApi, typed forInvoiceComment,InvoiceCommentCreateOptionsandInvoiceCommentActionKey.Overview
For each invoice, Billomat records a stream of comments: some are system-generated (status changes, received payments, emails sent), some are written manually by users. Both kinds live in the same resource and differ only in the
actionkeyfield:actionkeyset (COMPLETE,PAYMENT,EMAIL, …) anduser_id = null.actionkeyand a specificuser_id.Endpoints
list($invoiceId, $actionKeys?, $filters?)/invoice-comments?invoice_id={id}listPage(…)/iterateAll(…, $pageSize?)/invoice-comments?invoice_id={id}(paginated)get($id)/getOrFail($id)/invoice-comments/{id}create($invoiceId, $options)/invoice-commentsdelete($id)/invoice-comments/{id}There is intentionally no
list()withoutinvoice_id; Billomat requires the filter.Methods
list(int $invoiceId, ?array $actionKeys = null, SubResourceFilter|array $filters = []): list<InvoiceComment>Lists all comments of an invoice. You can optionally filter by
InvoiceCommentActionKeyvalues; the list is sent to Billomat comma-separated. Passing a different enum throws anInvalidArgumentException.SubResourceFilter(orderBy,page,perPage,extra) sorts and paginates.listPage()anditerateAll()take the same arguments (iterateAll()additionally$pageSize); see Pagination.get(int $id): ?InvoiceComment/getOrFail(int $id): InvoiceCommentget()returnsnullon 404;getOrFail()throws aNotFoundExceptioninstead.create(int $invoiceId, InvoiceCommentCreateOptions $options): InvoiceCommentactionkeyis optional and should be left empty for manual comments; Billomat fills it automatically for system actions.delete(int $id): voidDeletes a comment. Errors are thrown as exceptions.
Write model:
InvoiceCommentCreateOptionsConstructor:
new InvoiceCommentCreateOptions(string $comment, …). The object is immutable (final readonly) and has awith*()method per field. The invoice ID is the first argument ofcreate(), which adds it to the payload asinvoice_id.commentcommentstringactionkeyactionkey?InvoiceCommentActionKeypublicpublic?boolfalse)toArray()dropsnullvalues.Read model:
InvoiceCommentfinal readonly class InvoiceComment.idintinvoiceIdintcomment?stringcreated?\DateTimeImmutableuserId?intnullfor system commentsactionkey?InvoiceCommentActionKeynullfor an unknown or missing valueactionkeyRaw?stringpublic?boolbyClient?boolemailId?intclientId?intcustomfield?stringextraarray<string, mixed>Enum:
InvoiceCommentActionKeyInvoiceCommentActionKeycovers the action keys observed in API output:CREATECREATEEDITEDITOPENOPENCOMPLETECOMPLETECANCELCANCELUNCANCELUNCANCELCHANGE_STATUSCHANGE_STATUSPAYMENTPAYMENTEMAILEMAILMAILMAILDUNNINGDUNNINGCOMMENTCOMMENTBillomat doesn't document a closed list. If new values show up, the SDK parses
actionkeytonulland fillsactionkeyRawwith the original string, so nothing is lost.Pitfalls
invoice_idis required. Without the filter Billomat responds with 400;list()sets it automatically.actionkeyis primarily API output. Setting a value likePAYMENTmanually can distort the activity view in the Billomat UI.delete()also deletes system comments. Be careful when cleaning up: system entries are part of the audit trail.End-to-end example