KanalKanal API
Recipes

PHP integration

A retry-safe client using Guzzle.

A minimal Guzzle-based client. Install Guzzle with composer require guzzlehttp/guzzle.

KanalClient.php
<?php

use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;

class KanalClient
{
    private Client $http;

    public function __construct(
        private string $apiKey,
        private int $storeId,
    ) {
        $this->http = new Client([
            'base_uri' => 'https://api.getkanal.com',
            'timeout'  => 10,
        ]);
    }

    private function request(string $method, string $path, array $body = []): ?array
    {
        $attempt = 0;

        do {
            try {
                $res = $this->http->request($method, "/api/v1/stores/{$this->storeId}{$path}", [
                    'headers' => [
                        'Authorization' => "Bearer {$this->apiKey}",
                        'Content-Type'  => 'application/json',
                    ],
                    'json'        => $body ?: null,
                    'http_errors' => true,
                ]);

                return $res->getStatusCode() === 204
                    ? null
                    : json_decode((string) $res->getBody(), true);
            } catch (RequestException $e) {
                $status = $e->getResponse()?->getStatusCode() ?? 0;

                // Retry 429 and 5xx — safe because writes are idempotent.
                if (($status === 429 || $status >= 500) && $attempt < 4) {
                    usleep((2 ** $attempt) * 500_000); // 0.5s, 1s, 2s, 4s
                    $attempt++;
                    continue;
                }

                throw $e; // 4xx ≠ 429: fix the payload/credentials, do not retry.
            }
        } while ($attempt <= 4);

        return null;
    }

    public function upsertOrder(array $order): ?array
    {
        return $this->request('POST', '/orders', $order);
    }

    public function updateOrder(string $externalId, array $patch): ?array
    {
        return $this->request('PATCH', '/orders/' . rawurlencode($externalId), $patch);
    }

    public function upsertCheckout(array $checkout): ?array
    {
        return $this->request('POST', '/checkouts', $checkout);
    }

    public function upsertCustomer(array $customer): ?array
    {
        return $this->request('POST', '/customers', $customer);
    }

    public function upsertShipment(array $shipment): ?array
    {
        return $this->request('POST', '/shipments', $shipment);
    }
}
usage.php
<?php

$kanal = new KanalClient(getenv('KANAL_API_KEY'), 123);

$kanal->upsertOrder([
    'external_id' => 'ORDER-1001',
    'placed_at'   => (new DateTime())->format(DateTime::ATOM),
    'total_price' => 49.90,
    'currency'    => 'EUR',
    'customer'    => ['phone' => '+33612345678', 'first_name' => 'Marie'],
]);

Load the API key from the environment or your secrets manager — never commit it to source control.