# SDK PHP

**AlsendoOne SDK** to oficjalny klient PHP dla Apaczka API v2 i **zalecany
sposób integracji** — obsługuje podpisywanie żądań, znaczniki `expires` i
mapowanie błędów, a każdą metodę API udostępnia przez typowane obiekty
żądań i odpowiedzi.

- Źródła: [github.com/Alsendo/AlsendoOneSDK](https://github.com/Alsendo/AlsendoOneSDK) (MIT)
- Pakiet: [`alsendo/alsendo-one-sdk`](https://packagist.org/packages/alsendo/alsendo-one-sdk) na Packagist
- Wymaga PHP ≥ 7.4 oraz `ext-json`

## Instalacja

```bash
composer require alsendo/alsendo-one-sdk
```

SDK zawiera domyślny adapter Guzzle — zainstaluj Guzzle obok niego (albo
[użyj własnego klienta HTTP](#własny-klient-http-retry-i-logowanie)):

```bash
composer require guzzlehttp/guzzle guzzlehttp/psr7
```

## Pierwsze kroki

Uzyskaj `app_id` i `app_secret` w [panelu Apaczka](https://panel.apaczka.pl)
w sekcji **Ustawienia → API**, a następnie:

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

use AlsendoOne\SDK\AlsendoClient;

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

// Pobierz usługi dostępne na Twoim koncie
$structure = $client->getServiceStructure();

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

Uwierzytelnianie jest w pełni automatyczne — SDK wylicza
[podpis HMAC-SHA256](/pl/legacy/hmac-signing) oraz znacznik `expires` dla
każdego żądania.

Każde żądanie niesie też nagłówek `User-Agent: AlsendoOneSDK/<wersja> PHP/<wersja>`,
dzięki któremu Apaczka wie, na jakim wydaniu SDK działa Twoja integracja —
zachowaj ten nagłówek, jeśli [podstawiasz własny klient HTTP](#własny-klient-http-retry-i-logowanie).

:::tip

W kodzie aplikacji używaj interfejsu `AlsendoOne\SDK\AlsendoClientInterface`
(a nie konkretnej klasy `AlsendoClient`) — klient pozostanie mockowalny w
testach.

:::

## Dostępne metody

| Metoda | Opis |
|---|---|
| `getServiceStructure()` | Dostępne usługi, opcje, typy paczek i odbiorów |
| `getPoints($supplier, $countryCode, $subtype)` | Punkty nadania/odbioru przewoźnika (np. Paczkomaty InPost) |
| `getValuation($orderData)` | Wycena — ceny zwracane **w groszach** (1 PLN = 100 gr) |
| `sendOrder($orderData)` | Utworzenie zamówienia przesyłki |
| `getOrder($orderId)` / `getOrders($page, $limit)` | Szczegóły zamówienia / lista z paginacją (max 25 na stronę) |
| `cancelOrder($orderId)` | Anulowanie zamówienia |
| `getPickupHours($postalCode, $service)` | Dostępne okna odbioru kurierskiego dla kodu pocztowego |
| `schedulePickup(...)` / `scheduleBatchPickup(...)` | Zamówienie odbioru kurierskiego dla jednego / wielu zamówień |
| `getTracking($waybillNumber)` | Zdarzenia śledzenia dla listu przewozowego |
| `getWaybill($orderId)` | Etykieta jako PDF zakodowany w base64 |
| `getTurnIn($orderIds)` | Zbiorcze potwierdzenie nadania (PDF) |
| `getDispatchCode($orderId)` | Kod nadania/zwrotu przewoźnika |
| `request($route, $params)` | Surowe podpisane żądanie do dowolnego endpointu |

Aplikacje partnerskie z podwyższonymi uprawnieniami mają dodatkowo
`registerCustomer()` oraz `checkData()` (walidacja NIP, limit 100 wywołań
dziennie).

Żądania można budować jako zwykłe tablice (zgodne z payloadami z
[referencji API](/pl/reference/v2-legacy)) albo typowanymi builderami —
`OrderRequest`, `Address`, `ShipmentRequest`, `PickupRequest` itd. Pełny
przykład znajdziesz w [cyklu życia zamówienia](/pl/guides/order-lifecycle).

## Obsługa błędów

Wszystkie wyjątki SDK dziedziczą po `AlsendoOne\SDK\Exception\AlsendoException`:

| Wyjątek | Znaczenie |
|---|---|
| `ApiException` | API zwróciło kopertę błędu — zobacz [semantykę błędów](/pl/legacy/error-semantics) |
| `ConnectionException` | Samo żądanie HTTP nie powiodło się (timeout, DNS, status HTTP inny niż 200) |
| `WebhookVerificationException` | Przychodzący [webhook push tracking](/pl/guides/tracking#webhooki-push-tracking) nie przeszedł weryfikacji podpisu |

```php
use AlsendoOne\SDK\Exception\ApiException;
use AlsendoOne\SDK\Exception\ConnectionException;

try {
    $order = $client->getOrder(123456);
} catch (ApiException $e) {
    // np. "Order not found." — pełna koperta przez $e->getResponseData()
    echo 'API error ' . $e->getCode() . ': ' . $e->getMessage();
} catch (ConnectionException $e) {
    echo 'Connection error: ' . $e->getMessage();
}
```

API nie rozróżnia błędów uwierzytelniania i walidacji kodem statusu (w
praktyce zawsze `400`) — gdy musisz je odróżnić, sprawdzaj treść komunikatu
wyjątku.

## Własny klient HTTP, retry i logowanie

Dowolny klient HTTP może zastąpić wbudowany adapter Guzzle — wystarczy
zaimplementować `HttpClientInterface`. Dwa opcjonalne dekoratory opakowują
dowolną implementację:

```php
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` ponawia **wyłącznie błędy sieciowe**, nigdy koperty
błędów API — pamiętaj też, że błąd sieciowy nie gwarantuje, że żądanie nie
dotarło do serwera; ponawianie operacji nieidempotentnych, takich jak
`sendOrder()`, może utworzyć zduplikowane zamówienia. `LoggingHttpClient`
loguje URL, statusy i czas trwania przez dowolny logger PSR-3 i nigdy nie
loguje danych dostępowych ani podpisanych payloadów.

## Sandbox

Przekaż `AlsendoClient::SANDBOX_URL` jako bazowy URL, aby testować w
środowisku sandbox — zobacz [Testowanie integracji](/pl/guides/testing):

```php
$client = new AlsendoClient(
    'app_id',
    'app_secret',
    null,                        // domyślny klient Guzzle
    AlsendoClient::SANDBOX_URL
);
```

## Integrujesz z innego języka?

SDK jest tylko dla PHP. Z każdego innego języka wywołuj API bezpośrednio —
cały kontrakt to podpisany `POST` z kopertą, opisany w
[Podpisywaniu żądań (HMAC)](/pl/legacy/hmac-signing), z przykładami cURL do
skopiowania w [przykładach implementacji](/pl/legacy/implementation-examples).
