Search by

alsendo / alsendo-one-sdk

AlsendoOne SDK — official PHP client for Apaczka API v2

Maintainers

Package info

github.com/Alsendo/AlsendoOneSDK

pkg:composer/alsendo/alsendo-one-sdk

Transparency log

Statistics

Installs: 6

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

v1.1.0 2026-08-18 14:38 UTC

This package is auto-updated.

Last update: 2026-08-18 14:39:24 UTC


README

Latest Stable Version PHP Version License

Official PHP client for Apaczka API v2. Ship parcels with 20+ couriers through a single integration.

Requirements

  • PHP 7.4 or higher
  • ext-json
  • An HTTP client implementing HttpClientInterface (Guzzle 7 adapter included)

Installation

composer require alsendo/alsendo-one-sdk

If you want to use the built-in Guzzle adapter, also install Guzzle:

composer require guzzlehttp/guzzle guzzlehttp/psr7

Quick start

<?php

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

use AlsendoOne\SDK\AlsendoClient;

$client = new AlsendoClient(
    'your_app_id',
    'your_app_secret'
);

// Fetch available services
$structure = $client->getServiceStructure();

foreach ($structure->getServices() as $service) {
    echo $service['name'] . ' (ID: ' . $service['service_id'] . ')' . PHP_EOL;
}

Authentication

Every API request is signed with HMAC-SHA256. The SDK handles this automatically -- you only need to provide your app_id and app_secret when creating the client.

The signature is computed from four components:

HMAC-SHA256(app_id:route:json_request:expires, app_secret)

Each signature is valid for 15 minutes. The SDK generates expires timestamps internally, so there is nothing to manage on your end.

For endpoints without parameters the SDK signs and sends {} (an empty JSON object), while the official API examples sign [] (an empty JSON array) — the API accepts both, but the two payloads produce different signatures, so don't mix the SDK with hand-rolled signing code for the same request.

You can obtain your API credentials in the Apaczka panel under Settings > API.

Available methods

Service structure

Method Description
getServiceStructure() Get available services, options, and package types

Access points

Method Description
getPoints(string $supplier, string $countryCode = 'PL', string $subtype = '') Get pickup/drop-off points for a courier (e.g. InPost lockers)

Notes:

  • To ship to a specific point, put its foreign_address_id (e.g. "ADA01M") into the receiver Address::$foreignAddressId. Setting it on the sender address switches the pickup to drop-off at that point instead.
  • The endpoint returns the entire point list for the country (tens of thousands of entries for some carriers) — there are no geo/city filters, so fetch once, cache, and filter locally. Consider raising the HTTP timeout (see below).

Pricing

Method Description
getValuation(array $orderData) Get a price quote for given shipment parameters. Prices are returned in groszy (1 PLN = 100 groszy)

Orders

Method Description
sendOrder(array $orderData) Create a new shipment order
getOrder(int $orderId) Get details of a single order
getOrders(int $page = 1, int $limit = 10) List orders with pagination (max 25 per page)
cancelOrder(int $orderId) Cancel an order

Pickup scheduling

Method Description
getPickupHours(string $postalCode, ?Service $service = null) Get available pickup time windows for a postal code
schedulePickup(int $orderId, string $date, string $hourFrom, string $hourTo) Schedule courier pickup for one order
scheduleBatchPickup(array $orderIds, string $date, string $hourFrom, string $hourTo) Schedule courier pickup for multiple orders

Tracking

Method Description
getTracking(string $waybillNumber) Get tracking events (normalized status, carrier status, place, timestamp) for a waybill

Documents

Method Description
getWaybill(int $orderId) Get shipping label as base64-encoded PDF
getTurnIn(array $orderIds) Get batch turn-in confirmation as base64-encoded PDF
getDispatchCode(int $orderId) Get carrier dispatch/return code for an order

Account (privileged)

These endpoints require dedicated partner privileges on the calling application.

Method Description
registerCustomer(CustomerRegisterRequest|array $customerData) Register a new customer account; returns provisioned API credentials
checkData(string $vatId) Validate a VAT id (rate-limited to 100 calls/day); throws on an invalid id

Raw request

Method Description
request(string $route, array $params = []) Send a signed request to any API endpoint. Returns a Response object

All client methods are also described by AlsendoClientInterface — type-hint the interface in your application to keep the client mockable in tests.

Tracking webhooks

When you create an order with push_tracking_url, the platform POSTs a signed JSON notification to that URL on every status change. Use PushTrackingWebhook to verify the signature (computed with your own app_secret) and parse the payload:

use AlsendoOne\SDK\Exception\WebhookVerificationException;
use AlsendoOne\SDK\Webhook\PushTrackingWebhook;

$webhook = new PushTrackingWebhook('your_app_id', 'your_app_secret');

try {
    $notification = $webhook->parse(file_get_contents('php://input'));
} catch (WebhookVerificationException $e) {
    http_response_code(400);
    exit;
}

foreach ($notification->getStatuses() as $status) {
    // e.g. "ON_THE_WAY", "OUT_FOR_DELIVERY", "DELIVERED", "RETURNED"
    updateShipmentStatus($notification->getOrderNumber(), $status->getStatus());
}

http_response_code(200); // acknowledge the notification

Notes:

  • Respond with HTTP 200, otherwise the platform may retry the delivery.
  • Push tracking is only registered for supported couriers; statuses may be an empty array.
  • Timestamps are Y-m-d\TH:i:s without an offset, in Europe/Warsaw time.

Error handling

The SDK throws exceptions extending AlsendoOne\SDK\Exception\AlsendoException:

  • ApiException — the API returned an error. Note that the Apaczka API responds with HTTP 200 even on failures; errors are signalled by a non-200 status field in the response envelope (in practice always 400), with the reason in the message field.
  • ConnectionException — the HTTP request itself failed (timeout, DNS failure, non-200 HTTP status, etc.).
use AlsendoOne\SDK\Exception\ApiException;
use AlsendoOne\SDK\Exception\ConnectionException;

try {
    $order = $client->getOrder(123456);
} catch (ApiException $e) {
    // API returned an error envelope, e.g. "Order not found."
    echo 'API error ' . $e->getCode() . ': ' . $e->getMessage();

    // Access the full response
    $response = $e->getResponse();
    $data = $e->getResponseData();
} catch (ConnectionException $e) {
    // Network error (timeout, DNS failure, etc.)
    echo 'Connection error: ' . $e->getMessage();
}

The API does not distinguish authentication or validation failures by status code (everything is 400) — inspect the exception message if you need to tell them apart.

Custom HTTP client

The SDK uses Guzzle by default. You can replace it with any HTTP client by implementing HttpClientInterface:

use AlsendoOne\SDK\Http\HttpClientInterface;
use AlsendoOne\SDK\Http\Response;

class MyHttpClient implements HttpClientInterface
{
    public function post(string $url, array $formParams): Response
    {
        // Your implementation using cURL, Symfony HttpClient, etc.
        $httpStatus = 200;
        $body = '{"status": 200, "response": {}}';

        return new Response($httpStatus, $body);
    }

    public function get(string $url, array $queryParams): Response
    {
        // ...
    }
}

$client = new AlsendoClient('app_id', 'app_secret', new MyHttpClient());

The bundled adapter accepts any Guzzle config options — for example to raise the timeouts (defaults: 30 s request, 10 s connect):

use AlsendoOne\SDK\Http\GuzzleHttpClient;

$client = new AlsendoClient(
    'app_id',
    'app_secret',
    new GuzzleHttpClient(['timeout' => 120])
);

Retry and logging decorators

Two optional decorators wrap any HttpClientInterface implementation:

use AlsendoOne\SDK\Http\GuzzleHttpClient;
use AlsendoOne\SDK\Http\LoggingHttpClient;
use AlsendoOne\SDK\Http\RetryingHttpClient;

$httpClient = new LoggingHttpClient(
    new RetryingHttpClient(new GuzzleHttpClient(), maxRetries: 2, delayMs: 500),
    $psrLogger
);

$client = new AlsendoClient('app_id', 'app_secret', $httpClient);

RetryingHttpClient retries only network failures (ConnectionException), never API error envelopes. Beware: a network failure does not guarantee the request did not reach the server — retrying non-idempotent operations such as sendOrder() may create duplicate orders.

LoggingHttpClient logs the URL, statuses and duration through any PSR-3 logger; request parameters (credentials, signed payload) are never logged.

Sandbox

To test against the sandbox environment, pass AlsendoClient::SANDBOX_URL as the base URL (sandbox credentials are separate from production ones):

$client = new AlsendoClient(
    'app_id',
    'app_secret',
    null,                           // use default Guzzle client
    AlsendoClient::SANDBOX_URL
);

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/my-feature)
  3. Make your changes
  4. Run the test suite and static analysis:
    composer test          # PHPUnit
    composer phpstan       # PHPStan
    composer cs-check      # PHP-CS-Fixer (dry run)
  5. Commit and push your branch
  6. Open a pull request against main

Please follow PSR-12 coding standards.

License

This package is open-source software licensed under the MIT License.