Version 3 targets version 2 of the Postbode API. It is a rewrite: the old Postbode\PostbodeClient that
shipped in 1.x and 2.x is gone and no method names carry over. This document maps everything you were using
onto its replacement.
| 1.x / 2.x | 3.0 | |
|---|---|---|
| API | https://app.postbode.nu/api (v1) |
https://postbode.app/api/v2 |
| Authentication | X-Authorization: <key> |
Authorization: Bearer <key> |
| Identifiers | numeric letter IDs | UUIDs |
| HTTP client | Guzzle, hard-wired | any PSR-18 client |
| Return values | array, or an int status code on failure |
typed readonly objects, exceptions on failure |
| PHP | 8.0 | 8.2 |
The change that will touch the most code is the last one. Before, a failed call returned an integer, which was easy to miss and impossible to tell apart from a real result. In 3.0 every failure throws.
guzzlehttp/guzzle is no longer a dependency of this package. If your project does not already have a PSR-18
client, add one:
composer require postbode/postbode-api guzzlehttp/guzzle// 1.x / 2.x
$postbode = new \Postbode\PostbodeClient(API_KEY);
// 3.0
$postbode = new \Postbode\PostbodeApiClient(API_KEY);| 1.x / 2.x | 3.0 |
|---|---|
getMailboxes() |
$postbode->mailboxes->list() |
getLetters($mailboxId) |
$postbode->postals->list($customerCode) |
getLetter($mailboxId, $letterId) |
$postbode->postals->get($postalUuid) |
sendLetter($mailboxId, $filename, …) |
$postbode->postals->create(PostalRequest::make(…)) |
addLetterToQueue(…) + sendLetterQueue($mailboxId) |
see Batches below |
The mailbox ID of v1 is the customer code of v2 — the short code such as PSBD, not a numeric ID.
The old client collected letters in memory and posted them together to /letterbatch. The v2 API has no batch
endpoint; create the items in a loop instead. Build the shared settings once and reuse them, since a request
builder is immutable:
$template = PostalRequest::make($customerCode, $envelopeUuid)->shipping(ShippingType::NL_SLOW)->send();
foreach ($files as $file) {
$postbode->postals->create($template->addDocumentFromFile($file));
}If the point of the batch was the discounted bulk rate rather than the single call, use
ShippingType::NL_MAILING and let the mailbox's shipping threshold gather the items instead.
The old signature took a long positional argument list. In 3.0 the same call is a builder, and the flags that used to be strings are enums.
// 1.x / 2.x
$postbode->sendLetter(
$mailboxId,
'/path/to/invoice.pdf',
$envelopeId,
'NL',
false, // registered
true, // send
'FC', // color
'simplex',
'inkjet',
);
// 3.0
use Postbode\Enum\PostalPlex;
use Postbode\Enum\PostalPrinting;
use Postbode\Enum\ShippingType;
use Postbode\Request\PostalRequest;
$postbode->postals->create(
PostalRequest::make($customerCode, $envelopeUuid)
->addDocumentFromFile('/path/to/invoice.pdf')
->shipping(ShippingType::NL_FAST)
->printing(PostalPrinting::COLOR)
->plex(PostalPlex::SIMPLEX)
->send(),
);Notes on the individual arguments:
$registeredbecame a shipping method:ShippingType::NL_REGISTERED.$countryis no longer passed separately; pick the shipping method for the destination (NL_*,EU_*orINT_*).$color'FC'/'ZW'becamePostalPrinting::COLOR/PostalPrinting::BLACK.$printeris gone; Postbode picks the production method.$sendbecame->send(true|false). Leave it off entirely to follow the mailbox default.
Everything is typed now, so array keys become properties and snake_case becomes camelCase.
// 1.x / 2.x
$letter = $postbode->getLetter($mailboxId, $letterId);
echo $letter['status'];
echo $letter['customer_reference'];
// 3.0
$postal = $postbode->postals->get($postalUuid);
echo $postal->status->name; // 'Delivered'
echo $postal->status->code->value; // 150
echo $postal->customerReference;// 1.x / 2.x — a failure came back as an int
$mailboxes = $postbode->getMailboxes();
if (is_int($mailboxes)) {
// something went wrong, but what?
}
// 3.0
use Postbode\Exception\PostbodeException;
use Postbode\Exception\ValidationException;
try {
$mailboxes = $postbode->mailboxes->list();
} catch (ValidationException $e) {
print_r($e->getErrors()); // per field, as the API reported them
} catch (PostbodeException $e) {
echo $e->getMessage();
}PostbodeException is the base class of everything this library throws, including transport failures, so a
single catch is enough if you do not want to distinguish cases.
If your database holds v1 letter IDs, you do not have to re-create anything. Translate them once:
$postal = $postbode->postals->findByV1Id($customerCode, $letterId);
$db->update('letters', ['uuid' => $postal->uuid], ['id' => $letterId]);The returned PostalSummary also carries the current reference, type, status and tags, so you can backfill
those in the same pass.
Functionality that had no v1 equivalent:
- Price calculation —
$postbode->postals->calculate()quotes an item before you create it. - Address validation —
$postbode->address->validate()resolves a postal code and house number. - Window preview —
$postbode->envelopes->windowPreview()renders your PDF behind the envelope window so you can check the address lines up before printing thousands of them. - Tags —
$postbode->tagsgroups items in the interface. - Products and fulfillment —
$postbode->productsand$postbode->fulfillmentship goods held in stock. - Public tracking —
$postbode->tracking->track()gives a recipient a status without exposing your account. - Webhooks —
PostalRequest::webhook()pushes status changes to your application.