PHP SDK
The official PHP SDK wraps the public API with built-in retries and a typed exception hierarchy. PHP 8.1+.
Install
Section titled “Install”composer require zulaiy/zutaxPulls in guzzlehttp/guzzle.
Get an API key
Section titled “Get an API key”- Sign in to your ZUTAX workspace.
- Settings → API keys → Create key.
- Copy the key — you’ll only see it once.
Use a staging key against https://staging-api.getzutax.com until you’re
ready to go live.
Your first transmit
Section titled “Your first transmit”use Zutax\ZutaxClient;
$client = new ZutaxClient( apiKey: 'zk_test_...', baseUrl: 'https://staging-api.getzutax.com',);
$result = $client->invoices->transmit( payload: [ 'external_id' => 'INV-2026-0042', 'issue_date' => '2026-05-03', 'due_date' => '2026-06-03', 'customer' => [ 'external_id' => 'C-100', 'legal_name' => 'Acme Industries Limited', 'tin' => '12345678-0001', 'address' => [ 'city_name' => 'Lagos', 'country_code' => 'NG', ], ], 'lines' => [ [ 'name' => 'Consulting services — May 2026', 'quantity' => '1', 'unit_price_naira' => '250000.00', 'vat_rate' => '7.5', ], ], ], idempotencyKey: 'INV-2026-0042',);
echo $result['invoice_id'] . PHP_EOL;Errors
Section titled “Errors”Every HTTP error surfaces as a typed exception:
use Zutax\Exception\AuthException;use Zutax\Exception\ConflictException;use Zutax\Exception\NotFoundException;use Zutax\Exception\RateLimitException;use Zutax\Exception\ServerException;use Zutax\Exception\ValidationException;use Zutax\Exception\ZutaxException;
try { $client->invoices->transmit($payload);} catch (ValidationException $e) { foreach ($e->errors as $err) { echo $err['loc'] . ': ' . $err['msg'] . PHP_EOL; }} catch (RateLimitException $e) { echo "Slow down, retry in {$e->retryAfter}s" . PHP_EOL;} catch (ZutaxException $e) { echo "Failed: {$e->statusCode} {$e->getMessage()}" . PHP_EOL;}| Exception | When it fires |
|---|---|
| AuthException | 401 / 403 |
| NotFoundException | 404 |
| ValidationException | 400 / 422 |
| ConflictException | 409 (idempotency-key reuse with mismatched payload) |
| RateLimitException | 429 (SDK already retried, gave up) |
| ServerException | 5xx (SDK already retried, gave up) |
| ZutaxException | base class |
Idempotency
Section titled “Idempotency”Pass a key per call:
$client->invoices->transmit($payload, idempotencyKey: 'INV-2026-0042');…or scope a key to a callable when several calls share one logical operation:
use Zutax\IdempotencyKey;
IdempotencyKey::scoped('INV-2026-0042', function () use ($client, $payload) { return $client->invoices->transmit($payload);});Resources
Section titled “Resources”$client->invoices // transmit, get, getByExternalId, list, cancel$client->parties // create, get, getByExternalId, list$client->products // create, get, getByExternalId, list$client->creditNotes // create, get, getByExternalId, listReference connector
Section titled “Reference connector”A complete end-to-end example — read pending invoices from MySQL, transmit
each one with an idempotency key, mark transmitted on success — lives in
zutax-sdks/reference-connectors/php-mysql-source/.
Fork it as a starting point for your own custom-ERP integration.
Source
Section titled “Source”The SDK is open source: Zulaiy/zutax/zutax-sdks/php/.