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

Delivery Notes (Lieferscheine) ​

API wrapper for delivery notes under /delivery-notes and their three sub-resources (/delivery-note-items, /delivery-note-comments, /delivery-note-tags).

Access ​

php
$billomat->deliveryNotes             // delivery notes
$billomat->deliveryNotes->items      // line items
$billomat->deliveryNotes->comments   // comments / audit trail
$billomat->deliveryNotes->tags       // tags

Model ​

A delivery note documents the physical handover of a delivery. Compared to an invoice it carries little monetary data: the read model has no total or price fields, and the document itself creates no payment obligation. The status lifecycle is a single step:

DRAFT  ──complete()──▶  CREATED

Unlike confirmations, the API offers no further status transitions: PUT /delivery-notes/{id}/cancel and /uncancel answer 400 ("cancellation not supported"), /clear, /unclear and /undo answer 404. The enum still knows OPEN, CLEARED and CANCELED, which Billomat may report for documents changed in the web app. A delivery note can be linked to a source invoice (invoiceId), confirmation (confirmationId) and/or offer (offerId).

Endpoint overview ​

/delivery-notes ​

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

/delivery-note-items ​

MethodHTTPPath
list($deliveryNoteId, $filters?)GET/delivery-note-items?delivery_note_id={id}
listPage($deliveryNoteId, $filters?) / iterateAll($deliveryNoteId, $filters?, $pageSize?)GET/delivery-note-items?delivery_note_id={id} (paginated)
get($id) / getOrFail($id)GET/delivery-note-items/{id}
create($deliveryNoteId, $options)POST/delivery-note-items
update($id, $options)PUT/delivery-note-items/{id}
delete($id)DELETE/delivery-note-items/{id}

/delivery-note-comments ​

MethodHTTPPath
list($deliveryNoteId, $actionKeys?, $filters?)GET/delivery-note-comments?delivery_note_id={id}
listPage(…) / iterateAll(…, $pageSize?)GET/delivery-note-comments?delivery_note_id={id} (paginated)
get($id) / getOrFail($id)GET/delivery-note-comments/{id}
create($deliveryNoteId, $options)POST/delivery-note-comments
delete($id)DELETE/delivery-note-comments/{id}

/delivery-note-tags ​

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

Methods ​

Delivery notes ​

list(DeliveryNoteFilter|array $filters = []): list<DeliveryNote> ​

Filters according to the Billomat docs: client_id, contact_id, status, from, to, number_pre, tags, invoice_id, confirmation_id, order_by. If Billomat returns a single match as an object, the SDK normalizes it to a list.

The typed filter DeliveryNoteFilter is recommended. Its camelCase fields are clientId, contactId, deliveryNoteNumber, status (list<DeliveryNoteStatus>), from/to (DateTimeImmutable), label, 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, confirmation_id, number_pre). A plain array still works.

php
use Justpilot\Billomat\Api\DeliveryNoteFilter;
use Justpilot\Billomat\Api\OrderBy;
use Justpilot\Billomat\Model\Enum\DeliveryNoteStatus;

$openDeliveries = $billomat->deliveryNotes->list(new DeliveryNoteFilter(
    status: [DeliveryNoteStatus::OPEN],
    orderBy: OrderBy::desc('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): ?DeliveryNote ​

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

create(DeliveryNoteCreateOptions $options): DeliveryNote ​

Line items can be passed directly in the create() call via items: […] or withItem(); they end up as delivery-note-items.delivery-note-item in the payload. invoiceId, confirmationId and offerId link the delivery note to preceding documents.

php
use Justpilot\Billomat\Api\DeliveryNoteCreateOptions;
use Justpilot\Billomat\Api\DeliveryNoteItemCreateOptions;
use Justpilot\Billomat\Model\Money;

$opts = new DeliveryNoteCreateOptions(
    clientId: 12345,
    invoiceId: 999,
    date: new DateTimeImmutable('today'),
    title: 'Delivery note',
    items: [
        new DeliveryNoteItemCreateOptions(quantity: 3.0, unitPrice: Money::of('49.90')),
    ],
);

$note = $billomat->deliveryNotes->create($opts);

update(int $id, DeliveryNoteUpdateOptions $options): DeliveryNote ​

Fully editable only in DRAFT. Line items can't be changed here; use $billomat->deliveryNotes->items.

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

Completes the draft. Assigns the final delivery_note_number and generates the PDF.

delete(int $id): void ​

Deletes the delivery note. There is no cancel() for delivery notes; in the sandbox, Billomat also deleted completed delivery notes.

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

Sends the delivery note by email. Without options, Billomat uses the account defaults; the PDF is attached automatically.

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

Uploads a signed PDF version. Typical use case: the driver photographs the signed proof of delivery, and the PDF is uploaded base64-encoded.

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

pdf() returns a DeliveryNotePdf (base64 container), pdfContent() the raw bytes (UnexpectedResponseException if the body isn't a PDF).

php
use Justpilot\Billomat\Model\Enum\PdfType;

$pdf = $billomat->deliveryNotes->pdf($note->id, PdfType::SIGNED);
file_put_contents('delivery-note.pdf', $pdf->getBinary());

Delivery note items ​

php
$items = $billomat->deliveryNotes->items->list($note->id);

$item = $billomat->deliveryNotes->items->create(
    $note->id,
    new DeliveryNoteItemCreateOptions(quantity: 2.0, unitPrice: Money::of('49.90')),
);

$billomat->deliveryNotes->items->update($item->id, new DeliveryNoteItemUpdateOptions(title: 'Packed separately'));
$billomat->deliveryNotes->items->delete($item->id);

create() adds delivery_note_id automatically; the options class itself has no such field. update() takes DeliveryNoteItemUpdateOptions and only sends the fields you set.

Delivery note comments ​

php
use Justpilot\Billomat\Api\DeliveryNoteCommentCreateOptions;
use Justpilot\Billomat\Model\Enum\DeliveryNoteCommentActionKey;

$comments = $billomat->deliveryNotes->comments->list(
    $note->id,
    actionKeys: [DeliveryNoteCommentActionKey::COMPLETE, DeliveryNoteCommentActionKey::EMAIL],
);

$billomat->deliveryNotes->comments->create(
    $note->id,
    new DeliveryNoteCommentCreateOptions(
        comment: 'Handed over to warehouse South.',
    ),
);

Delivery note tags ​

php
use Justpilot\Billomat\Api\DeliveryNoteTagCreateOptions;

$tag = $billomat->deliveryNotes->tags->create(
    $note->id,
    new DeliveryNoteTagCreateOptions(name: 'freight-shipping'),
);

$tags  = $billomat->deliveryNotes->tags->list($note->id);
$cloud = $billomat->deliveryNotes->tags->cloud();

Write model: DeliveryNoteCreateOptions ​

Constructor: new DeliveryNoteCreateOptions(int $clientId, …). clientId 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->withTitle('New')).

PropertyBillomat fieldTypeNotes
clientIdclient_idintrequired (constructor)
contactIdcontact_id?int
addressaddress?string
numberPre, number, numberLengthsnake_case equivalent?string/?int/?int
datedate?\DateTimeImmutableserialized as Y-m-d
title, label, intro, note, reductionsnake_case equivalent?string
currencyCodecurrency_code?string
netGrossnet_gross?NetGross
quotequote?float
invoiceIdinvoice_id?intsource invoice
confirmationIdconfirmation_id?intsource confirmation
freeTextIdfree_text_id?int
templateIdtemplate_id?int
offerIdoffer_id?intsource offer

Unlike OfferCreateOptions/ConfirmationCreateOptions, there is no discountRate/discountDays/discountDate/validityDays: a delivery note has no payment or validity context of its own.

Line items ​

Line items are passed as a list via the constructor parameter items (items: [new DeliveryNoteItemCreateOptions(…), …]) and are then available in the $items property. withItem() returns a copy with one additional item. toArray() renders them as delivery-note-items.delivery-note-item.

Write model: DeliveryNoteUpdateOptions ​

Mirrors DeliveryNoteCreateOptions, but clientId is optional and there is no items. null means "don't send", so the value stays unchanged. Clear::Field (Justpilot\Billomat\Api\Clear) sends the field as JSON null, and Billomat empties it, e.g. new DeliveryNoteUpdateOptions(note: Clear::Field).

PropertyBillomat fieldType
clientIdclient_id?int
contactId, numberPre, number, numberLength, invoiceId, confirmationId, offerId, freeTextId, templateIdsnake_case equivalent?int/?string
address, title, label, intro, note, reduction, currencyCodesnake_case equivalent?string
datedate?\DateTimeImmutable
netGrossnet_gross?NetGross
quotequote?float

Every field additionally accepts Clear::Field.

Write model: DeliveryNoteItemCreateOptions ​

Constructor: new DeliveryNoteItemCreateOptions(float $quantity, Money $unitPrice). Both are required and are sent even when they are 0.

PropertyBillomat fieldTypeNotes
quantityquantityfloatrequired (constructor)
unitPriceunit_priceMoneyrequired (constructor)
typetype?ItemType
articleIdarticle_id?int
title, description, unitsnake_case equivalent?string
taxName, taxRate, taxChangedManuallysnake_case equivalent?string/?float/?bool
reductionreduction?string
positionposition?int

For ItemsApi::update() there is DeliveryNoteItemUpdateOptions: every field is optional (X|Clear|null) with a with*() method, only the fields you set are sent, and Clear::Field empties a field. Billomat keeps all other fields of the item.

Write model: DeliveryNoteCommentCreateOptions ​

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

PropertyBillomat fieldTypeNotes
commentcommentstringrequired (constructor)
actionkeyactionkey?DeliveryNoteCommentActionKeyusually only for system actions

Write model: DeliveryNoteTagCreateOptions ​

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

PropertyBillomat fieldType
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. No required fields.

PropertyBillomat fieldTypeNotes
emailTemplateIdemail_template_id?int
fromfrom?string
to, cc, bccrecipients.{to,cc,bcc}list<string>empty arrays are left out
subject, body, filenamesnake_case equivalent?string
attachmentsattachments.attachment[]list<array{filename,mimetype,base64file}>

Read model: DeliveryNote ​

final readonly class DeliveryNote.

PropertyType
idint
clientIdint
contactId?int
created?\DateTimeImmutable
deliveryNoteNumber?string, only set after complete()
number, numberPre, numberLength?int/?string/?int
status?DeliveryNoteStatus
date?\DateTimeImmutable
address?string
title, label, intro, note?string
invoiceId?int
confirmationId?int
freeTextId, templateId?int
taxeslist<TaxSummary> (name, rate, amount as Money)
itemslist<DeliveryNoteItem>
updated?\DateTimeImmutable
offerId?int
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: DeliveryNoteItem ​

final readonly.

PropertyType
id, deliveryNoteId, articleId, position?int
unit?string
quantityfloat
taxChangedManually?bool
title, description?string
type?ItemType
customfield?string (free-form extra field, see Custom meta attributes)
extraarray<string, mixed>

Read model: DeliveryNoteComment ​

final readonly.

PropertyType
idint
deliveryNoteIdint
comment?string
created?\DateTimeImmutable
userId?int
actionkey?DeliveryNoteCommentActionKey
actionkeyRaw?string, raw value for an unknown actionkey
public?bool
byClient?bool
emailId?int
clientId?int
customfield?string (free-form extra field, see Custom meta attributes)
extraarray<string, mixed>

Read model: DeliveryNoteTag ​

final readonly. Fields: id (?int), deliveryNoteId (int), name (string), customfield (?string), extra (array).

Read model: DeliveryNoteTagCloudEntry ​

final readonly. Aggregate: id (?int), name (string), count (int), extra (array).

Read model: DeliveryNotePdf ​

final class DeliveryNotePdf (not readonly).

PropertyType
idint
deliveryNoteIdint
created?\DateTimeImmutable
filenamestring
mimeTypestring, default application/pdf
fileSizeint
base64filestring

getBinary(): string decodes base64file.

Enums used ​

  • DeliveryNoteStatus: DRAFT, OPEN, CREATED, CLEARED, CANCELED. After complete(), Billomat now returns CREATED. Has label() for the German display name.
  • DeliveryNoteCommentActionKey: CREATE, EDIT, OPEN, COMPLETE, CANCEL, CLEAR, CHANGE_STATUS, EMAIL, MAIL, COMMENT.
  • ItemType: PRODUCT, SERVICE, shared with invoice items.
  • PdfType: SIGNED (signed), PRINT (print); the wire values are lowercase.
  • NetGross: NET, GROSS, SETTINGS.

Pitfalls ​

  • A delivery note carries little monetary data. Billomat returns no total or price fields in the read model, and the document creates no receivable. If you expect a payment, you want $billomat->invoices or $billomat->incomings.
  • No discount/validity. Unlike OfferCreateOptions/ConfirmationCreateOptions, DeliveryNoteCreateOptions has no discountRate/discountDays/discountDate/validityDays fields. Don't look for them out of copy-paste habit.
  • update() doesn't change line items. Billomat ignores embedded delivery-note-items on PUT. Always use $billomat->deliveryNotes->items.
  • No status transitions after complete(). The SDK has no cancel(), clear() or undo() for delivery notes because Billomat's API doesn't support them (400/404). Up to 3.x the SDK had these methods; they always failed.
  • delete() isn't limited to DRAFT. Billomat's API deletes delivery notes in any status. Think twice before deleting a completed one: it is numbered, and deleting it leaves a gap in the number sequence.
  • Item updates are partial. DeliveryNoteItemUpdateOptions sends only the fields you set; Billomat keeps the rest of the item. Passing *ItemCreateOptions to update() throws an InvalidArgumentException.
  • Single results are normalized in list(). For exactly one match, Billomat returns delivery-note as an object; the SDK wraps it in a list.
  • Multiple source references are possible. invoiceId, confirmationId and offerId can all be set at the same time, but Billomat does not synchronize the status of the linked documents automatically.
  • tax_changed_manually is required for manual taxRate values. Without the flag, Billomat uses the article's or client's default.
  • DeliveryNotePdf is not readonly, a pragmatic exception for the binary data container.
  • uploadSignature() expects plain base64, without a data: prefix. Typical use case: sending a PDF signed by the driver back from a mobile workflow.

End-to-end example ​

php
<?php

declare(strict_types=1);

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

use Justpilot\Billomat\Api\DeliveryNoteCommentCreateOptions;
use Justpilot\Billomat\Api\DeliveryNoteCreateOptions;
use Justpilot\Billomat\Api\DeliveryNoteItemCreateOptions;
use Justpilot\Billomat\Api\DeliveryNoteTagCreateOptions;
use Justpilot\Billomat\Api\EmailOptions;
use Justpilot\Billomat\BillomatClient;
use Justpilot\Billomat\Model\Enum\ItemType;
use Justpilot\Billomat\Model\Enum\PdfType;
use Justpilot\Billomat\Model\Money;

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

// 1) Create a delivery note for an existing invoice
$opts = new DeliveryNoteCreateOptions(
    clientId: 12345,
    invoiceId: 999,
    date: new DateTimeImmutable('today'),
    title: 'Delivery note',
    intro: 'Please countersign on receipt.',
);

$item = new DeliveryNoteItemCreateOptions(
    quantity: 3.0,
    unitPrice: Money::of('49.90'),
    title: 'Hardware bundle',
    type: ItemType::PRODUCT,
    unit: 'piece',
);
$opts = $opts->withItem($item);

$note = $billomat->deliveryNotes->create($opts);
printf("Delivery note #%d created (DRAFT)\n", $note->id);

// 2) Add a tag
$billomat->deliveryNotes->tags->create(
    $note->id,
    new DeliveryNoteTagCreateOptions(name: 'freight-shipping'),
);

// 3) Complete: the number is assigned
$billomat->deliveryNotes->complete($note->id);

$opened = $billomat->deliveryNotes->getOrFail($note->id);
printf("Status: %s, delivery note number: %s\n",
    $opened->status?->label() ?? '?',
    $opened->deliveryNoteNumber ?? '?',
);

// 4) Email the PDF to the carrier
$email = new EmailOptions(to: ['carrier@example.com'], subject: 'Delivery note {NUMBER}');
$billomat->deliveryNotes->email($note->id, $email);

// 5) Upload the signed proof of delivery (e.g. from a mobile workflow)
$signed = file_get_contents('/var/spool/scans/' . $opened->deliveryNoteNumber . '.pdf');
if (false !== $signed) {
    $billomat->deliveryNotes->uploadSignature($note->id, base64_encode($signed));
}

// 6) Add a note
$billomat->deliveryNotes->comments->create(
    $note->id,
    new DeliveryNoteCommentCreateOptions(
        comment: 'Receipt confirmed by warehouse South on June 2.',
    ),
);

// 7) Archive the signed PDF version
$pdf = $billomat->deliveryNotes->pdf($note->id, PdfType::SIGNED);
file_put_contents("delivery-note-{$opened->deliveryNoteNumber}.pdf", $pdf->getBinary());

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