# Implementation examples

:::info

The examples below are written in **PHP**. For live testing of
individual methods (including generated snippets in other languages), use the
*Try it* panel in the [API Reference](/reference/v2-legacy).

:::

## The easy way: official SDK

If you integrate from PHP, skip the manual signing entirely — the official
[SDK](/sdk) handles signatures, expiry timestamps and error mapping for
you, and returns typed response objects:

```bash
composer require alsendo/alsendo-one-sdk guzzlehttp/guzzle guzzlehttp/psr7
```

```php
<?php
require __DIR__ . '/vendor/autoload.php';

use AlsendoOne\SDK\AlsendoClient;
use AlsendoOne\SDK\Exception\AlsendoException;

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

try {
    // 1. Pick a service
    $structure = $client->getServiceStructure();

    // 2. Price the shipment (prices are returned in groszy!)
    $valuation = $client->getValuation($order);

    // 3. Create the order
    $created = $client->sendOrder($order);
    $orderId = $created->getId();

    // 4. Download the shipping label (base64-encoded PDF)
    $waybill = $client->getWaybill($orderId);
    file_put_contents('label.pdf', base64_decode($waybill->getWaybill()));
} catch (AlsendoException $e) {
    echo 'Apaczka API error: ' . $e->getMessage();
}
```

The rest of this page shows the same flows in plain PHP + cURL — useful when
you can't use Composer or integrate from another language.

## Shared helper: signed envelope request

Every API v2 call is the same `POST` envelope — wrap it once
(see [Request signing](/legacy/hmac-signing) for the algorithm details):

```php
<?php
/**
 * Sends a signed request to the Apaczka API v2.
 * $route must include path params and the trailing slash, e.g. "order_send/".
 */
function apaczka_request(string $route, array $payload = []): array
{
    $appId     = getenv('APACZKA_APP_ID');
    $appSecret = getenv('APACZKA_APP_SECRET');

    $request = json_encode($payload);
    $expires = time() + 900; // max +15 minutes

    $stringToSign = sprintf('%s:%s:%s:%s', $appId, $route, $request, $expires);
    $signature    = hash_hmac('sha256', $stringToSign, $appSecret);

    $ch = curl_init('https://www.apaczka.pl/api/v2/' . $route);
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POSTFIELDS     => http_build_query([
            'app_id'    => $appId,
            'request'   => $request,
            'expires'   => $expires,
            'signature' => $signature,
        ]),
    ]);
    $body = curl_exec($ch);
    curl_close($ch);

    $response = json_decode($body, true);

    // HTTP status is always 200 — the real outcome is in the body.
    if (($response['status'] ?? 0) !== 200) {
        throw new RuntimeException(sprintf(
            'Apaczka API error %d: %s',
            $response['status'] ?? 0,
            $response['message'] ?? 'Unknown error'
        ));
    }

    return $response['response'];
}
```

## Get available services

```php
$structure = apaczka_request('service_structure/');

foreach ($structure['services'] as $service) {
    echo $service['id'] . ': ' . $service['name'] . PHP_EOL;
}
```

## Price an order (valuation)

```php
$order = [
    'order' => [
        'service_id' => 65,
        'address' => [
            'sender' => [
                'name'           => 'Firma Testowa Sp. z o.o.',
                'line1'          => 'ul. Marszalkowska 1',
                'postal_code'    => '05-500',
                'city'           => 'Warszawa',
                'country_code'   => 'PL',
                'is_residential' => false,
                'contact_person' => 'Jan Kowalski',
                'email'          => 'sender@example.pl',
                'phone'          => '500000000',
            ],
            'receiver' => [
                'name'           => 'Apaczka Sp. z o.o.',
                'line1'          => 'Legionow Polskich 2',
                'postal_code'    => '01-479',
                'city'           => 'Warszawa',
                'country_code'   => 'PL',
                'is_residential' => false,
                'contact_person' => 'Adam Nowak',
                'email'          => 'receiver@example.pl',
                'phone'          => '321321321',
            ],
        ],
        'pickup'   => ['type' => 'SELF'],
        'shipment' => [
            [
                'dimension1' => 10,
                'dimension2' => 10,
                'dimension3' => 10,
                'weight'     => 1,
                'is_nstd'    => 0,
            ],
        ],
        'content' => 'Elektronika',
    ],
];

$valuation = apaczka_request('order_valuation/', $order);
```

## Create the order

The payload is identical to the valuation call:

```php
$created = apaczka_request('order_send/', $order);
$orderId = $created['order']['id'];
```

## Download the shipping label (waybill)

Path parameters are part of the signed route:

```php
$waybill = apaczka_request('waybill/' . $orderId . '/');

// The document is base64-encoded PDF.
file_put_contents('label.pdf', base64_decode($waybill['waybill']));
```

## Track a shipment

```php
$tracking = apaczka_request('tracking/' . $waybillNumber . '/');

foreach ($tracking['data'] as $event) {
    echo $event['status'] . ' — ' . $event['description']
        . ' (' . $event['updated_at'] . ')' . PHP_EOL;
}
```
