# Migracja z Ecolet — przegląd

Integrujesz się z **API Ecolet** (`panel.ecolet.ro`, v1/v2), a Twoje
przesyłki przechodzą na platformę **Apaczka**. Ta sekcja mapuje to, co już
masz, na Apaczka API v2 — tak, żebyś przepisał warstwę transportową bez
odkrywania każdej różnicy na własną rękę.

Trzy strony:

1. **Ten przegląd** — które pojęcia się zmieniają i w jakiej kolejności je ugryźć.
2. [Mapowanie endpointów](/pl/migration/ecolet-endpoint-map) — wywołanie po wywołaniu, co czym zastąpić.
3. [Braki i obejścia](/pl/migration/ecolet-gaps) — czego Apaczka nie ma i co zrobić zamiast tego.

:::note[Logika biznesowa zostaje; protokół nie]

Zamówienia, paczki, pobranie, etykiety i śledzenie istnieją po obu stronach.
Zmienia się *sposób* rozmowy z API — uwierzytelnianie, transport, kształt
adresu i to, że tworzenie zamówienia jest synchroniczne. Tam zaplanuj pracę.

:::

## Pięć różnic, które generują pracę

| # | Obszar | Ecolet | Apaczka API v2 |
| --- | --- | --- | --- |
| 1 | Uwierzytelnianie | Bearer JWT z `oauth/token` | Podpis **HMAC-SHA256** przy każdym żądaniu |
| 2 | Transport | GET / POST / DELETE, ciało JSON, HTTP 401/422/500 | **Tylko POST**, koperta form-urlencoded, **zawsze HTTP 200** |
| 3 | Tworzenie zamówienia | Asynchroniczne — `send-order` → `order_to_send_id` → odpytywanie | **Synchroniczne** — jedno wywołanie zwraca zamówienie i numer listu przewozowego |
| 4 | Pieniądze | RON, łańcuchy dziesiętne (`"16,28"`) | Liczby całkowite w **jednostkach podrzędnych** (grosze: 1 PLN = 100 gr) |
| 5 | Adresy | Ustrukturyzowane pola RO + `locality_id` | `line1` / `line2` + tekstowe `city` + `postal_code` |

Cała reszta — etykiety, przesyłki wielopaczkowe, pobranie, okna odbioru — to
mechaniczna transformacja.

## 1. Uwierzytelnianie — bez tokenów, podpisuj każde żądanie

Nie ma wywołania logowania ani sesji. Każde żądanie niesie `app_id`,
znacznik `expires` oraz podpis HMAC-SHA256 wyliczony z trasy, ładunku i czasu
wygaśnięcia, przy użyciu Twojego `app_secret`.

```text
Ecolet    POST /oauth/token  →  access_token  →  Authorization: Bearer …
Apaczka   sign(app_secret, "order_send/:{json}:{expires}")  →  każde żądanie
```

Konsekwencje praktyczne:

- **Usuń cache tokenu i logikę odświeżania.** Nie ma czego przechowywać ani
  odnawiać.
- **`expires` to krótkie okno ważności pojedynczego żądania**, a nie TTL
  sesji. Zegar serwera ma znaczenie — rozjazd oznacza masowe odrzucenia.
- `app_secret` nigdy nie opuszcza Twojego serwera. Podpisywanie w
  przeglądarce lub aplikacji mobilnej oznacza jego wyciek.

Pełny algorytm z przykładami: [Podpisywanie żądań
(HMAC)](/pl/legacy/hmac-signing). Używasz PHP? [SDK](/pl/sdk) podpisuje za
Ciebie i cała ta sekcja sprowadza się do dwóch argumentów konstruktora.

## 2. Transport — jeden czasownik, jeden kod statusu

Każdy endpoint to `POST` na ścieżkę z **ukośnikiem na końcu**, a ładunek
jedzie jako łańcuch JSON wewnątrz pola formularza:

```text
app_id=<uuid>&request=<json>&expires=<unix>&signature=<hmac>
```

Odpowiedź to **zawsze HTTP 200**. Faktyczny wynik jest w ciele:

```json
{ "status": 200, "message": "", "response": { } }
{ "status": 400, "message": "Validation error", "response": null }
```

Zatem:

- Przepisz `GET /order/{id}` na `POST order/{id}/`, a `DELETE /order/{id}` na
  `POST cancel_order/{id}/`.
- **Przestań rozgałęziać kod po statusach HTTP.** Rozgałęziaj po `status` z
  ciała odpowiedzi. Każdy kod HTTP inny niż 200 to awaria transportu, a nie
  błąd API.
- Ecolet-owe `errors[]` na poziomie pól nie mają odpowiednika — błąd
  przychodzi jako pojedynczy `message`. Jeśli Twój interfejs podświetla
  konkretne niepoprawne pola, zobacz
  [Braki i obejścia](/pl/migration/ecolet-gaps).

Szczegóły: [Semantyka błędów](/pl/legacy/error-semantics).

## 3. Tworzenie zamówienia — synchroniczne i nieidempotentne

Przepływ w Ecolet wyglądał tak: `send-order` → `order_to_send_id` →
odpytywanie `order-to-send/{id}` aż do `ordered` albo `error` → dopiero
potem odczyt zamówienia.

`order_send` w Apaczce robi to wszystko w jednym wywołaniu i zwraca id
zamówienia, numer listu przewozowego przewoźnika oraz URL śledzenia. Maszyna
stanów `order_to_send` znika — nie ma bytu pośredniego, nie ma czego
odpytywać, nie ma `order_to_send/destroy`.

:::caution[Usuń pętlę odpytywania, dodaj dyscyplinę ponawiania]

`order_send` **nie jest idempotentne**. Tam, gdzie Ecolet pozwalał
bezpiecznie ponownie odpytać oczekujące zadanie, ponowione wywołanie Apaczki
po timeoucie może utworzyć **drugie zamówienie i drugi list przewozowy**.
Traktuj timeout jako „nie wiem" i uzgadniaj stan przez listę zamówień —
nigdy jako „nie udało się, ponawiam". Zobacz [dobre
praktyki](/pl/guides/best-practices).

:::

Pełny przepływ: [Cykl życia zamówienia](/pl/guides/order-lifecycle).

## 4. Pieniądze — liczby całkowite, jednostki podrzędne

| | Ecolet | Apaczka |
| --- | --- | --- |
| Typ | łańcuch dziesiętny z przecinkiem (`"16,28"`) | liczba całkowita |
| Jednostka | RON | jednostki podrzędne — w referencji grosze (1 PLN = 100 gr) |
| Rozbicie opłat | pozycje `fees[]` | kwoty netto / brutto |

Konwertuj na krawędziach systemu i trzymaj liczby całkowite wewnątrz. `1628`
oznacza 16,28 — pomyłka o 100 kończy się na prawdziwej fakturze.

Kwoty pobrania i `shipment_value` działają tak samo; `cod.currency` niesie
kod waluty jawnie.

:::note[Potwierdź walutę i VAT przed startem produkcyjnym]

Kwestia RON ↔ PLN (w jakiej walucie rozliczane jest konto i czy wypłaty
pobrania są przewalutowywane) to ustawienie handlowe, nie flaga API.
Potwierdź to z opiekunem po stronie Alsendo, zamiast wnioskować z testowej
odpowiedzi. VAT różni się między rynkami i dotyczy fakturowania, nie API.

:::

## 5. Adresy — dwie linie zamiast ośmiu pól

Ecolet modeluje adres rumuński jako osobne pola. Apaczka przyjmuje dwie
swobodne linie adresu plus miasto, kod pocztowy i kraj:

| Ecolet | Apaczka | Jak |
| --- | --- | --- |
| `street_name`, `street_number` | `line1` | konkatenacja |
| `block`, `entrance`, `floor`, `flat` | `line2` | konkatenacja z prefiksami |
| `locality_id` | `city` | rozwiń id do nazwy (zobacz [braki](/pl/migration/ecolet-gaps#locations-api)) |
| `locality` | `city` | bezpośrednio |
| `county` | `state_code` | bezpośrednio |
| — | `name`, `contact_person`, `email`, `phone` | wymagane pola kontaktowe |

:::caution[Sklejenie jest stratne — trzymaj własną kopię]

`line1` + `line2` nie da się wiarygodnie rozłożyć z powrotem na blok /
klatkę / piętro / mieszkanie. Rumuńscy przewoźnicy często potrzebują tych
części osobno, więc **przechowuj ustrukturyzowany adres we własnej bazie** i
traktuj postać Apaczki jako jego rendering, a nie jako źródło prawdy.

:::

Składając `line2`, użyj przyjętych rumuńskich prefiksów, żeby człowiek (i
kurier) nadal to rozczytał:

```text
line2 = "bl. 12, sc. A, et. 3, ap. 27"
        bloc      scara   etaj    apartament
```

Pilnuj limitów długości pól z [referencji API v2](/pl/reference/v2-legacy) —
długi rumuński adres potrafi je przekroczyć.

Punkty nadania/odbioru (paczkomaty, PUDO) podpina się inaczej: id punktu
trafia do `foreign_address_id` na odpowiednim adresie, a typ odbioru
pozostaje `SELF`. Zobacz [Typy odbioru (pickup)](/pl/guides/pickups).

## Sugerowana kolejność prac

Każdy krok da się przetestować niezależnie, a wcześniejsze odblokowują
późniejsze:

1. **Podpisywanie** — doprowadź jedno wywołanie `service_structure` do
   `status: 200`. Nic innego nie zadziała, dopóki to nie działa.
2. **Słownik usług** — zmapuj swoje slugi usług Ecolet na numeryczne
   `service_id` faktycznie dostępne na koncie. Nie zaszywaj listy na
   sztywno; czytaj ją z `service_structure` i cache'uj (odświeżaj raz dziennie).
3. **Renderowanie adresu** — zbuduj i pokryj testami transformację Ecolet →
   `line1`/`line2`, razem z rozwijaniem `locality_id`.
4. **Tworzenie zamówienia** na [sandboxie](/pl/guides/testing) —
   `order_send`, potem `waybill`. W tym momencie możesz już nadawać.
5. **Śledzenie** — przejdź z wsadowego wywołania statusów Ecolet na
   `tracking` per list przewozowy albo (lepiej) na [webhooki
   push](/pl/guides/tracking).
6. **Reszta** — pobranie, usługi dodatkowe, punkty, odbiory, anulowanie.
7. **Braki** — lokalizacje, książka adresowa, użycie `/me`. Przeczytaj
   [Braki i obejścia](/pl/migration/ecolet-gaps) *przed* krokiem 1, żeby
   żaden z nich nie zaskoczył Cię na końcu.

---

**Dalej:** [Mapowanie endpointów](/pl/migration/ecolet-endpoint-map) ·
[Braki i obejścia](/pl/migration/ecolet-gaps) ·
[Szybki start](/pl/quick-start)
