# Uniorder: jedno API pro každou zásilku

Uniorder je jediná sada endpointů, přes kterou integrace oceňuje, vytváří, tiskne, sleduje a ruší každou zásilku účtu bez ohledu na způsob jejího vyřízení. Jedna nabídka vrátí doručení samotnou firmou a na požádání také každou službu štítků dopravce na účtu, každou s `rate_id`. Objednávka se vytvoří odesláním zvoleného `rate_id`; službu nevybírá nic jiného v požadavku.

## 1. Co můžete vytvořit

- **Pokladnu, která nabídne všechny možnosti dopravy najednou.** Zákazník zadá adresu, pokladna zavolá jeden endpoint a stránka zobrazí místní doručení vedle UPS, Canada Post a každého dalšího dopravce, kterého účet používá, každé s cenou.
- **Konektor pro správu objednávek nebo ERP s jednou cestou v kódu.** Objednávky ze všech kanálů procházejí stejnými voláními pro vytvoření, čtení, štítek, sledování a zrušení. Konektor nepotřebuje samostatnou logiku pro místní doručení a pro štítky dopravce.
- **Noční hromadné zpracování.** Až 500 zásilek se ocení nebo vytvoří v jedné úloze ve frontě a výsledky se načtou podle id úlohy.
- **Obrazovku zákaznického servisu.** Pracovník vyhledá objednávku, znovu vytiskne její štítek, načte historii sledování a zruší ji, a to stejnými čtyřmi voláními pro každou objednávku.

## 2. Co za vás Uniorder řeší

| Bez Uniorder | S Uniorder |
|---|---|
| Jedno API pro objednávky místního doručení a další pro štítky dopravce, každé s vlastními poli a odpověďmi | Jeden tvar požadavku (`from_*`, `to_*`, `packages`) a jeden tvar odpovědi pro každou službu |
| Integrace rozhoduje, které API dopravce zavolá | Nabídka uvádí každou službu; rozhoduje `rate_id` zvolené sazby |
| Samostatné endpointy pro štítek, sledování a zrušení pro každou službu | `GET /label`, `GET /tracking` a `POST /cancel` fungují pro každou objednávku |
| Dávkové vytvoření je dostupné pouze pro místní doručení | Dávková nabídka a dávkové vytvoření pro každou službu, synchronně nebo ve frontě |

Uniorder nenahrazuje stávající endpointy; zůstávají dostupné a nezměněné. Je to doporučený vstupní bod pro novou integraci.

## 3. Přehled endpointů v pořadí, v jakém je integrace používá

| Krok | Účel | REST | GraphQL |
|---|---|---|---|
| 1 | Získání přístupového tokenu | `POST /api/v1/user/login` | `userLogin` |
| 2 | Nabídka pro každou službu | `POST /api/v1/uniorder/rate` | `uniorderRate` |
| 3 | Vytvoření objednávky za zvolenou sazbu | `POST /api/v1/uniorder` | `uniorderCreate` |
| 4 | Tisk štítku | `GET /api/v1/uniorder/{orderId}/label` | `uniorderLabel` |
| 5 | Čtení objednávky | `GET /api/v1/uniorder/{orderId}` | `uniorder` |
| 6 | Sledování objednávky | `GET /api/v1/uniorder/{orderId}/tracking` | `uniorderTracking` |
| 7 | Zrušení objednávky | `POST /api/v1/uniorder/{orderId}/cancel` | `uniorderCancel` |
| — | Nákup štítku, který se při vytvoření nepodařilo koupit | `POST /api/v1/uniorder/{orderId}/label` | `uniorderPurchaseLabel` |
| — | Nabídka nebo vytvoření až 20 řádků najednou | `POST /api/v1/uniorder/rate/batch`, `POST /api/v1/uniorder/batch` | `uniorderRateBatch`, `uniorderCreateBatch` |
| — | Zařazení až 500 řádků do fronty | `POST /api/v1/uniorder/rate/batch-async`, `POST /api/v1/uniorder/batch-async`, `GET /api/v1/uniorder/jobs/{jobId}` | `uniorderRateBatchAsync`, `uniorderCreateBatchAsync`, `uniorderJob` |

[Příručka REST](/api/documentation#/paths/v1-uniorder-rate/post) · [Příručka GraphQL](/api/graphql/documentation#/orders/uniorderRate)

Požadavky, odpovědi a kontroly krok za krokem jsou v příručce **Nabídka a objednávka v jednom toku**.

## 4. Příklad: pokladna, která nabízí všechny možnosti

Květinářství v Montrealu prodává online. U pokladny ocení balík jednou, včetně dopravců štítků:

```bash
curl -X POST https://YOUR_HOST/api/v1/uniorder/rate \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "from_name": "Fleurs du Plateau", "from_telephone": "5145550100",
    "from_address": "4500 Rue Saint-Denis", "from_city": "Montreal", "from_province": "QC", "from_country": "CA", "from_postcode": "H2J2L3",
    "to_name": "Jane Recipient", "to_telephone": "5145550199",
    "to_address": "6841 Rue Saint-Denis", "to_city": "Montreal", "to_province": "QC", "to_country": "CA", "to_postcode": "H2S2S3",
    "quote_labels": true,
    "packages": [{ "weight": 1.2, "weight_unit": 2, "length": 40, "width": 25, "height": 25, "dimension_unit": 2 }]
  }'
```

Odpověď uvádí jednu sazbu `self_delivery` a jednu sazbu `label_service` pro každou službu dopravce. Pokladna je zobrazí jako možnosti; zákazník zvolí místní doručení v tentýž den. Objednávka se vytvoří s `rate_id` této sazby a se stejnými adresami a balíky:

```bash
curl -X POST https://YOUR_HOST/api/v1/uniorder \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: checkout-10045" \
  -d '{
    "rate_id": "eyJpdiI6Ik1rT2Z...",
    "ref": "WEB-10045",
    "from_name": "Fleurs du Plateau", "from_telephone": "5145550100",
    "from_address": "4500 Rue Saint-Denis", "from_city": "Montreal", "from_province": "QC", "from_country": "CA", "from_postcode": "H2J2L3",
    "to_name": "Jane Recipient", "to_telephone": "5145550199",
    "to_address": "6841 Rue Saint-Denis", "to_city": "Montreal", "to_province": "QC", "to_country": "CA", "to_postcode": "H2S2S3",
    "packages": [{ "weight": 1.2, "weight_unit": 2, "length": 40, "width": 25, "height": 25, "dimension_unit": 2 }]
  }'
```

Odpověď vrátí `id` objednávky a její sledovací čísla. Obchod vytiskne štítek pomocí `GET /api/v1/uniorder/{orderId}/label` a na stránce objednávky zákazníka zobrazí historii z `GET /api/v1/uniorder/{orderId}/tracking`.

## 5. Příklad: ERP, které odesílá každou noc

ERP exportuje objednávky dne ve 22:00. Adresy odešle na `POST /api/v1/uniorder/rate/batch-async`, čte úlohu, dokud `status` není `done`, pro každý řádek vybere sazbu podle vlastních pravidel a zvolené řádky odešle na `POST /api/v1/uniorder/batch-async`. Každý výsledek nese `reference` řádku, takže ERP přiřadí každý výsledek k vlastnímu řádku objednávky. `rate_id` platí 30 minut, proto se úloha vytvoření odesílá brzy po dokončení úlohy nabídky.

## 6. Příklad: obrazovka zákaznického servisu

Při hovoru zákazníka obrazovka pracovníka volá `GET /api/v1/uniorder/{orderId}` pro stav a adresy, `GET /api/v1/uniorder/{orderId}/tracking` pro historii a doklad o doručení a `POST /api/v1/uniorder/{orderId}/cancel`, když zákazník objednávku zruší. Stejná volání platí pro objednávku doručení i pro objednávku štítku; rozlišuje je pole `type`.

```bash
curl https://YOUR_HOST/api/v1/uniorder/123456/tracking \
  -H "Authorization: Bearer ACCESS_TOKEN"
```

Tatáž objednávka přes GraphQL ([Příručka GraphQL](/api/graphql/documentation#/orders/uniorder)):

```graphql
query {
  uniorder(order_id: 123456)
}
```

## 7. Pravidla, se kterými je třeba při návrhu počítat

- **Službu určuje `rate_id`.** Platí 30 minut a pouze pro účet, který nabídku vyžádal.
- **Objednávka se ocení při vytvoření.** `shipping_price` je účtovaná cena; `quoted_price` je cena z nabídky. Tyto dvě ceny se mohou lišit.
- **Objednávka štítku se nikdy neztratí.** Pokud štítek nelze koupit při vytvoření, objednávka se zachová a odpověď je `LABEL_PURCHASE_FAILED` s `id` objednávky; štítek se koupí později pomocí `POST /api/v1/uniorder/{orderId}/label`.
- **Opakování požadavků je bezpečné.** Při každém volání vytvoření pošlete hlavičku `Idempotency-Key`; zrušení již zrušené objednávky vrátí `already_cancelled` `true`.
- **Stavy jsou jednotné.** Objednávka doručení hlásí `pending`, `in_transit`, `out_for_delivery`, `delivered`, `exception` nebo `cancelled`; objednávka štítku hlásí `label_pending`, `label_purchased` nebo `cancelled` a polohu balíku hlásí sledování jejího dopravce.

## 8. Kontrolní seznam před spuštěním

- [ ] Účet má oprávnění k API a token je uložen na serveru, ne v prohlížeči.
- [ ] Nabídky se vyžadují s úplnými adresami odesílatele a příjemce.
- [ ] Objednávky se vytvářejí do 30 minut od nabídky a s `Idempotency-Key`.
- [ ] `LABEL_PURCHASE_FAILED` se řeší pozdějším nákupem štítku, nikdy opětovným vytvořením objednávky.
- [ ] Sledování se čte z `GET /api/v1/uniorder/{orderId}/tracking` nebo přijímá přes webhooky.
- [ ] Zrušení řeší `ORDER_STATUS_NOT_CANCELLABLE` a `ORDER_CANCEL_REFUSED` tak, že objednávku ponechá beze změny.
