Search by

zippendo / zippendo-php

Zippendo

Public API documentation for Zippendo. Authenticate using your API token (Bearer token prefixed with zipp_). **Brands (sub-accounts).** An organization can be split into brands, each keeping its own orders, shipments and configuration separate. There are two ways to scope requests to one brand, and

Package info

github.com/zippendo/zippendo-php

Homepage

pkg:composer/zippendo/zippendo-php

Statistics

Installs: 26

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.3.10 2026-10-07 10:02 UTC

README

Official PHP client for the Zippendo shipping & logistics API. Requires PHP 7.4+ and Composer.

Install

composer require zippendo/zippendo-php

Authentication

Create an API token in your Zippendo dashboard (Settings → API tokens) — a Bearer token prefixed with zipp_. Set it on the configuration:

<?php
require_once __DIR__ . "/vendor/autoload.php";

$config = Zippendo\Sdk\Configuration::getDefaultConfiguration()
    ->setAccessToken(getenv("ZIPPENDO_API_TOKEN"));

The base URL defaults to https://api.zippendo.com.

Resources & clients

The API is split into resource clients — ShipmentsApi, OrdersApi, CarriersApi, AddressesApi, RulesApi, WebhooksApi, TokensApi, and more. Each takes an HTTP client and your config:

$shipments = new Zippendo\Sdk\Api\ShipmentsApi(new GuzzleHttp\Client(), $config);
$orders = new Zippendo\Sdk\Api\OrdersApi(new GuzzleHttp\Client(), $config);

The org_id parameter

Every call takes an org_id (your organization ID, found in the dashboard). It is explicit on each call by design: one API token can be granted access to multiple organizations, and org_id selects which one the request acts on.

Brands

A brand is a sub-account inside an organization: one company running several consumer-facing labels (say Acme and Globex) keeps each label's orders and shipments separate, with its own company name, address and logo on the documents its shipments produce. Scope a request to one brand with the X-Zippendo-Brand header, whose value is the brand's ID or slug.

The header is not a method argument — it applies uniformly to every operation, so put it on the Guzzle client you hand to the resource clients, and every call they make carries it:

$acme = new GuzzleHttp\Client([
    'headers' => ['X-Zippendo-Brand' => 'acme'], // brand ID or slug
]);

$shipments = new Zippendo\Sdk\Api\ShipmentsApi($acme, $config);
$shipments->listShipments('org_8f3kd92ld0', 1, 50); // Acme's shipments only

To address two brands from one process, build a Guzzle client per brand and pass each to its own resource clients. Omit the header and the request covers the whole organization — the behaviour of every existing token. A header naming a brand that does not exist in the organization is rejected with 404 BRAND_NOT_FOUND.

An API token created with a brand_id is permanently confined to that brand and needs no header. Sending X-Zippendo-Brand naming a different brand on such a token is refused with 403 BRAND_ACCESS_DENIED — the binding is never widened.

List operations also take a brandScope query parameter ("own" / "shared" / "both") to narrow further within whichever brand context already applies: "own" returns only that brand's rows and needs a brand context (otherwise 400); "shared" returns only the unassigned rows (equivalent to brandId=none). Set X-Zippendo-Brand-Scope as a default header the same way to cover every call:

$acme = new GuzzleHttp\Client([
    'headers' => ['X-Zippendo-Brand' => 'acme', 'X-Zippendo-Brand-Scope' => 'own'],
]);

An explicit brandScope parameter passed to a call still wins over the header.

Managing brands

Brands are managed with BrandsApi. Build it from a plain Guzzle client without the brand header — you are administering brands, not acting inside one:

$brands = new Zippendo\Sdk\Api\BrandsApi(new GuzzleHttp\Client(), $config);

$created = $brands->createOrgBrand('org_8f3kd92ld0', new Zippendo\Sdk\Model\CreateOrgBrandRequest([
    'name' => 'Acme',
    'company_name' => 'Acme ApS',
]));

$page = $brands->listOrgBrands('org_8f3kd92ld0');
$brands->updateOrgBrand('org_8f3kd92ld0', $created->getId(), new Zippendo\Sdk\Model\UpdateOrgBrandRequest([
    'vat_number' => 'DK12345678',
]));
$brands->archiveOrgBrand('org_8f3kd92ld0', $created->getId());

Retire a brand with archiveOrgBrand — archived brands keep their slug and can be restored with unarchiveOrgBrand. Permanent deletion is dashboard-only: it is refused while any order, shipment, member or token still references the brand. Brands require a plan that includes them; creating one past your plan's limit returns 403.

Listing & pagination

List endpoints accept page (1-based) and limit, and return a page with getData() plus getTotal(), getPage(), getLimit(), and getTotalPages():

$result = $shipments->listShipments("org_8f3kd92ld0", 1, 50);
foreach ($result->getData() as $shipment) {
    echo $shipment->getId(), PHP_EOL;
}
echo $result->getTotal(), " / ", $result->getTotalPages(), PHP_EOL;

Creating resources

$order = $orders->createOrder("org_8f3kd92ld0", new \Zippendo\Sdk\Model\CreateOrderRequest([
    "order_number" => "1001",
    "order_channel_id" => "chan_7d2k1",
    "order_lines" => [
        new \Zippendo\Sdk\Model\CreateOrderRequestOrderLinesInner(["name" => "T-shirt", "quantity" => 2]),
    ],
]));
echo $order->getId(), PHP_EOL;

See ./docs/Api for the full request/response shape of every operation.

Error handling

Non-2xx responses throw ApiException. The response body is Zippendo's canonical { code, error, message } — branch on the machine-readable code:

try {
    $shipments->getShipment("org_8f3kd92ld0", "shp_missing");
} catch (\Zippendo\Sdk\ApiException $e) {
    echo $e->getCode(), PHP_EOL;           // HTTP status
    echo $e->getResponseBody(), PHP_EOL;   // JSON, e.g. {"code":"SHIPMENT_NOT_FOUND", ...}
}

Configuration

Point the client at a different environment by overriding the host:

$config = Zippendo\Sdk\Configuration::getDefaultConfiguration()
    ->setAccessToken(getenv("ZIPPENDO_API_TOKEN"))
    ->setHost("https://staging.api.zippendo.com");

Reference

Full per-endpoint and per-model documentation is in ./docs. Hosted reference: https://www.zippendo.com/docs/api-reference/overview.

License

MIT