# Cenová ponuka a objednávka v jednom toku

Táto príručka prechádza API Uniorder (`/api/v1/uniorder/...`) požiadavku po požiadavke v poradí, v akom sa integrácia vytvára: prihlásenie, cenová ponuka, vytvorenie so zvoleným `rate_id`, tlač štítku, čítanie, sledovanie a zrušenie objednávky a spracovanie zásielok v dávkach. Jedna cenová ponuka uvádza každý spôsob, akým môže účet odoslať balík: doručenie samotnou firmou a na požiadanie každú službu dopravcov štítkov. Objednanie s `rate_id` vytvorí objednávku pre danú službu: objednávku doručenia alebo objednávku štítku so štítkom kúpeným pri ocenenej službe dopravcu. Je určená vývojárom internetových obchodov, systémov na správu objednávok a ERP, ktoré odosielajú cez firemný účet.

## 1. Čo môžete vytvoriť

Nasledujúce príklady sledujú jednu firmu: **Fleurs du Plateau**, kvetinárstvo na adrese 4500 Rue Saint-Denis, Montreal (H2J 2L3), ktoré predáva kytice online. Typickým balíkom je jedna krabica s hmotnosťou 1,2 kg a rozmermi 40 × 25 × 25 cm pre Jane Recipient na adrese 6841 Rue Saint-Denis, Montreal (H2S 2S3), pod webovou objednávkou `WEB-10045`.

- **Pokladňa, ktorá ponúka všetky možnosti dopravy.** Obchod ocení balík raz a zobrazí miestne doručenie v ten istý deň vedľa každej služby štítkov dopravcu na účte, každú s cenou, a potom vytvorí objednávku pre možnosť, ktorú zákazník zvolil.
- **Automatická tlač štítkov.** Po vytvorení objednávky obchod stiahne PDF štítku a pošle ho do tlačiarne baliaceho pracoviska bez ohľadu na to, či balík doručuje firma alebo dopravca.
- **Stránka objednávky s aktuálnym sledovaním.** Stránka objednávky zákazníka zobrazuje stav a časovú os udalostí zásielky a po doručení kytice aj doklad o doručení.
- **Nočná dávka z ERP.** Veľkoobchodné objednávky dňa sa ocenia a vytvoria v jednej úlohe vo fronte s najviac 500 riadkami a každý výsledok sa priradí k svojmu riadku objednávky podľa `reference`.

## 2. Čo táto príručka pokrýva

Toto je podrobná príručka API Uniorder krok za krokom. Prehľad toho, čo Uniorder ponúka a prečo, nájdete v príručke **Uniorder: jedno API pre každú zásielku**; táto príručka uvádza požiadavky, odpovede a kontroly pre každé volanie.

Uniorder je odporúčaným jediným vstupným bodom pre nové integrácie, ktoré odosielajú balíky miestnym doručením alebo so štítkom dopravcu: nahrádza samostatné volania API miestneho doručenia a API štítkov dopravcu jedným tvarom požiadavky. Staršie endpointy opísané v príručkách **Vyzdvihnutie a doručenie (vlastná flotila)** a **Štítky dopravcu** zostávajú dostupné a nezmenené. Uniorder sa nevzťahuje na prepravné služby rezervované zákazníckym účtom ani na objednávky skladovania a výdaja; pre tie použite príručky **Prepravné služby** a **Skladovanie a výdaj**.

## 3. Skôr než začnete

- **Účet.** Použite firemný (klientsky) účet alebo zamestnanecký účet firmy s oprávnením na API. Uniorder môže volať aj zákaznícky účet firmy; cenová ponuka a vyúčtovanie sa mu vždy vystavujú na jeho vlastné meno. Vytvorenie objednávky doručenia vyžaduje oprávnenie na zadávanie objednávok.
- **Zákazníci.** Klientsky alebo zamestnanecký účet môže získať cenovú ponuku a objednávať pre jedného zo svojich zákazníkov pomocou `customer_id` alebo `customer_code` v cenovej ponuke; `rate_id` potom nesie tohto zákazníka a cena sa riadi plánom zákazníka.
- **Služby štítkov.** Na získanie sadzieb `label_service` potrebuje účet (alebo uvedený zákazník) aspoň jeden nastavený účet dopravcu štítkov.
- **Testovacie údaje.** Pre sadzby `self_delivery` použite adresu v oblasti doručenia firmy a testovacie referencie, napríklad `WEB-10045`, ktoré možno potom zrušiť.
- **Tokeny.** Prístupový token si vyžiadajte zo svojho servera a uchovávajte ho tam. Nikdy ho neposielajte do prehliadača ani do mobilnej aplikácie.
- **Zástupné hodnoty.** Nahraďte `YOUR_HOST` hostiteľom API vášho prostredia a `ACCESS_TOKEN` tokenom z kroku 4.

## 4. Prihlásenie

Každé volanie Uniorder sa vykonáva v mene účtu. Prihláste sa raz zo svojho servera, uložte vrátený token a posielajte ho pri každej požiadavke.

**REST:** `POST /api/v1/user/login` — [Príručka REST](/api/documentation#/paths/v1-user-login/post)

```bash
curl -X POST https://YOUR_HOST/api/v1/user/login \
  -H "Content-Type: application/json" \
  -d '{"email":"orders@fleursduplateau.example","password":"your_password"}'
```

```json
{
  "result": true,
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9..."
}
```

- `access_token`: vložte ho do hlavičky každej ďalšej požiadavky:

```
Authorization: Bearer ACCESS_TOKEN
```

GraphQL používa rovnakú hlavičku na `POST /api/graphql`.

**GraphQL:** `userLogin` ([Príručka GraphQL](/api/graphql/documentation#/user/userLogin))

**Overenie:** prihlásenie vráti `access_token`. Následujúce požiadavky bez tohto tokenu vrátia `401`.

## 5. Cenová ponuka pre každú službu

Cenová ponuka uvádza každý spôsob, akým možno balík odoslať, s cenou a `rate_id` pre každý z nich. Pokladňa zobrazí sadzby ako možnosti; nič sa nevytvorí ani nerezervuje.

**REST:** `POST /api/v1/uniorder/rate` — [Príručka REST](/api/documentation#/paths/v1-uniorder-rate/post)

Odosielateľ a príjemca sú úplné adresy; voliteľné sú iba `from_address_2` a `to_address_2`. Každý balík potrebuje `weight`, `length`, `width` a `height`. Nastavte `quote_labels` na `true`, ak chcete pridať služby dopravcov štítkov; mená a telefóny oboch strán sú potom povinné. Klientsky alebo zamestnanecký účet môže získať cenovú ponuku pre jedného zo svojich zákazníkov pomocou `customer_id` alebo `customer_code`. Časové okno doručenia (`time_window_start`, `time_window_end`, formát `YYYY-MM-DD HH:MM:SS`) sa zohľadní, ak od neho závisí cena.

```bash
curl -X POST https://YOUR_HOST/api/v1/uniorder/rate \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "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_address_2": "Apt 2",
    "to_city": "Montreal",
    "to_province": "QC",
    "to_country": "CA",
    "to_postcode": "H2S2S3",
    "time_window_start": "2026-10-02 13:00:00",
    "time_window_end": "2026-10-02 17:00:00",
    "quote_labels": true,
    "packages": [{
      "weight": 1.2,
      "weight_unit": 2,
      "length": 40,
      "width": 25,
      "height": 25,
      "dimension_unit": 2
    }]
  }'
```

`weight_unit`: `1` g, `2` kg, `3` oz, `4` lb. `dimension_unit`: `1` mm, `2` cm, `3` m, `4` in.

```json
{
  "result": true,
  "rates": [
    {
      "rate_id": "eyJpdiI6Ik1rT2Z...",
      "type": "self_delivery",
      "channel_id": null,
      "shipping_price": "14.60",
      "currency": "CAD",
      "price_details": { "shipping_fee": 12.92, "sub_total": "12.92" },
      "warning": null
    },
    {
      "rate_id": "eyJpdiI6IlpxR0...",
      "type": "label_service",
      "shipping_price": "18.40",
      "currency": "CAD",
      "shipping_method_id": 72,
      "shipping_method_name": "UPS",
      "carrier_name": "ups",
      "service_code": "ups_standard",
      "service_name": "UPS STANDARD",
      "transit_days": 3
    }
  ],
  "errors": []
}
```

- `type` `self_delivery`: doručenie firmou. Najviac jedna na cenovú ponuku.
- `type` `label_service`: jedna pre každú službu každého účtu štítkov. Zákazníkovi zobrazte `service_name`, `shipping_price` a `transit_days`.
- `errors` uvádza, čo sa nepodarilo oceniť, s jeho `type`. Adresa mimo oblasti doručenia je chyba typu `self_delivery` s kódom `OUT_OF_DELIVERY_AREA`; zobrazte iba služby štítkov.
- `rate_id` platí 30 minút a iba pre účet, ktorý si cenovú ponuku vyžiadal. Uchovávajte ho spolu s reláciou pokladne.
- `result` je `true`, ak sa našla aspoň jedna sadzba.

**GraphQL:** `uniorderRate` ([Príručka GraphQL](/api/graphql/documentation#/orders/uniorderRate)). Odpoveďou je JSON skalár, takže operácia nemá selection set.

```graphql
mutation QuoteBouquet($packages: [Json]!) {
  uniorderRate(
    type: "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: $packages
  )
}
```

Premenné:

```json
{ "packages": [{ "weight": 1.2, "weight_unit": 2, "length": 40, "width": 25, "height": 25, "dimension_unit": 2 }] }
```

**Overenie:** `rates` obsahuje sadzbu `self_delivery` pre adresu v oblasti a pri `quote_labels` jednu sadzbu `label_service` pre každú službu dopravcu. Nič sa nevytvorí.

## 6. Vytvorenie objednávky za zvolenú sadzbu

Keď zákazník zaplatí, obchod vytvorí objednávku s `rate_id` zvolenej možnosti a s rovnakou zásielkou. Službu určuje `rate_id`; nič iné v požiadavke ju nevyberá.

**REST:** `POST /api/v1/uniorder` — [Príručka REST](/api/documentation#/paths/v1-uniorder/post)

Pri každom vytvorení pošlite hlavičku `Idempotency-Key`, jedinečnú pre každú objednávku. Opakovanie s rovnakým kľúčom a rovnakým telom vráti prvú odpoveď s `replayed` `true` a nevytvorí druhú objednávku.

```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",
    "type": "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_email": "jane@example.com",
    "to_address": "6841 Rue Saint-Denis",
    "to_address_2": "Apt 2",
    "to_city": "Montreal",
    "to_province": "QC",
    "to_country": "CA",
    "to_postcode": "H2S2S3",
    "time_window_start": "2026-10-02 13:00:00",
    "time_window_end": "2026-10-02 17:00:00",
    "delivery_instruction": "Ring the bell at the side door.",
    "packages": [{
      "ref": "WEB-10045-1",
      "weight": 1.2,
      "weight_unit": 2,
      "length": 40,
      "width": 25,
      "height": 25,
      "dimension_unit": 2
    }]
  }'
```

Sadzba `self_delivery` vytvorí objednávku doručenia. Pri `type` `D` je zastávkou príjemca; nastavte `need_pick_up` na `1`, ak sa má balík vyzdvihnúť u odosielateľa. Pri `type` `P` je zastávkou odosielateľ.

```json
{
  "result": true,
  "type": "self_delivery",
  "id": 123456,
  "ref": "WEB-10045",
  "tracking_numbers": ["SR26092800001"],
  "shipping_price": "14.60",
  "quoted_price": "14.60",
  "currency": "CAD"
}
```

Sadzba `label_service` vytvorí objednávku štítku a kúpi štítok pri ocenenej službe dopravcu. `type` musí byť `D` a `from_name`, `from_telephone`, `to_name` a `to_telephone` sú povinné. Ak by si zákazník zvolil UPS STANDARD, odpoveď by bola:

```json
{
  "result": true,
  "type": "label_service",
  "id": 123457,
  "ref": "WEB-10045",
  "tracking_numbers": ["SR26092800002"],
  "shipping_price": "18.40",
  "quoted_price": "18.40",
  "currency": "CAD",
  "label": {
    "carrier_name": "ups",
    "service_code": "ups_standard",
    "main_tracking_number": "1Z999AA10123456784",
    "label_status": "ready",
    "shipping_label": "JVBERi0xLjQK..."
  }
}
```

- `id`: uložte ho k webovej objednávke; používa ho každé ďalšie volanie.
- `tracking_numbers`: vlastné sledovacie čísla zásielky, jedno na balík.
- `shipping_price`: účtovaná cena. Objednávka sa ocení pri vytvorení; `quoted_price` je cena z cenovej ponuky. Tieto dve ceny sa môžu líšiť.
- `label.main_tracking_number` a `label.shipping_label` (iba objednávka štítku): sledovacie číslo dopravcu a PDF štítku v base64.
- `result` `false` s kódom `LABEL_PURCHASE_FAILED` (iba objednávka štítku): objednávka existuje, ale nemá štítok. Uchovajte `id` a pokračujte krokom 11.

**GraphQL:** `uniorderCreate` ([Príručka GraphQL](/api/graphql/documentation#/orders/uniorderCreate))

```graphql
mutation CreateBouquetOrder($packages: [Json]!) {
  uniorderCreate(
    rate_id: "eyJpdiI6Ik1rT2Z..."
    ref: "WEB-10045"
    type: "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"
    packages: $packages
  )
}
```

Premenné:

```json
{ "packages": [{ "ref": "WEB-10045-1", "weight": 1.2, "weight_unit": 2, "length": 40, "width": 25, "height": 25, "dimension_unit": 2 }] }
```

**Overenie:** `result` je `true` a `id` je nastavené. `rate_id`, ktorého platnosť vypršala alebo patrí inému účtu, vráti `400` s kódom `RATE_ID_INVALID` a nič sa nevytvorí.

## 7. Tlač štítku

Baliace pracovisko vytlačí štítok hneď, ako objednávka existuje. Rovnaké volanie vráti vlastný štítok firmy pre objednávku doručenia a kúpený štítok dopravcu pre objednávku štítku.

**REST:** `GET /api/v1/uniorder/{orderId}/label` — [Príručka REST](/api/documentation#/paths/v1-uniorder-orderId--label/get)

```bash
curl "https://YOUR_HOST/api/v1/uniorder/123456/label?hide_sender_address=0" \
  -H "Authorization: Bearer ACCESS_TOKEN"
```

```json
{
  "result": true,
  "type": "self_delivery",
  "id": 123456,
  "format": "pdf",
  "tracking_numbers": ["SR26092800001"],
  "pdf_data": "JVBERi0xLjQK..."
}
```

- `pdf_data`: PDF štítku v base64. Dekódujte ho a súbor pošlite do tlačiarne.
- `hide_sender_address`, `hide_receiver_address` (`1` na skrytie): platia pre vlastný štítok firmy pri objednávke doručenia.
- `label_status` (objednávka štítku): `ready`, keď sa súbor vráti. Ak dopravca súbor ešte nevytvoril, odpoveďou je `200` s `result` `false` a `label_status` `pending`; štítok si vyžiadajte znova neskôr.
- Toto volanie nikdy nekupuje štítok: štítok, ktorý nebol kúpený, vráti `409` s kódom `LABEL_PURCHASE_FAILED`. Kúpte ho v kroku 11.

**GraphQL:** `uniorderLabel` ([Príručka GraphQL](/api/graphql/documentation#/orders/uniorderLabel))

```graphql
query {
  uniorderLabel(order_id: 123456, hide_sender_address: 0)
}
```

**Overenie:** `result` je `true` a dekódované `pdf_data` sa otvorí ako PDF so sledovacím číslom objednávky.

## 8. Čítanie objednávky

Obchod načíta objednávku, aby zobrazil jej stav, adresy a balíky na stránke objednávky alebo na obrazovke zákazníckeho servisu.

**REST:** `GET /api/v1/uniorder/{orderId}` — [Príručka REST](/api/documentation#/paths/v1-uniorder-orderId/get)

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

```json
{
  "result": true,
  "type": "self_delivery",
  "id": 123456,
  "ref": "WEB-10045",
  "order_type": "D",
  "status": "pending",
  "created_at": "2026-10-02 09:14:05",
  "time_window_start": "2026-10-02 13:00:00",
  "time_window_end": "2026-10-02 17:00:00",
  "from": { "name": "Fleurs du Plateau", "address": "4500 Rue Saint-Denis", "city": "Montreal", "postcode": "H2J2L3" },
  "to": { "name": "Jane Recipient", "address": "6841 Rue Saint-Denis", "address_2": "Apt 2", "city": "Montreal", "postcode": "H2S2S3" },
  "packages": [
    { "id": 998877, "ref": "WEB-10045-1", "tracking_number": "SR26092800001", "weight": 1.2 }
  ],
  "shipping_price": "14.60",
  "currency": "CAD"
}
```

- `type`: `self_delivery` alebo `label_service`; ostatné polia majú pre oba rovnaký tvar.
- `status`: `pending`, `in_transit`, `out_for_pickup`, `out_for_delivery`, `ready_for_self_pickup`, `delivered`, `exception` alebo `cancelled` pre objednávku doručenia a `label_pending`, `label_purchased` alebo `cancelled` pre objednávku štítku.
- `label` (iba objednávka štítku): dopravca, služba, `carrier_tracking_numbers` a `label_status` (`not_purchased`, `pending`, `ready` alebo `failed`).

**GraphQL:** `uniorder` ([Príručka GraphQL](/api/graphql/documentation#/orders/uniorder))

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

**Overenie:** objednávka vráti svoj `status` a `packages` a `ref` zodpovedá webovej objednávke.

## 9. Sledovanie objednávky

Stránka objednávky zobrazuje časovú os zásielky. Načítajte ju, keď zákazník otvorí stránku, alebo ju udržiavajte aktuálnu pomocou webhookov.

**REST:** `GET /api/v1/uniorder/{orderId}/tracking` — [Príručka REST](/api/documentation#/paths/v1-uniorder-orderId--tracking/get)

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

```json
{
  "result": true,
  "type": "self_delivery",
  "id": 123456,
  "status": "delivered",
  "tracking_numbers": ["SR26092800001"],
  "events": [
    { "code": "delivered", "description": "Delivered", "location": "Montreal", "time": "2026-10-02 15:42:10", "time_zone": "America/Toronto", "source": "shipper" }
  ],
  "proofs": [
    { "type": "photo", "url": "https://YOUR_HOST/storage/pod/123456.jpg", "uploaded_at": "2026-10-02 15:42:08" }
  ]
}
```

- `events`: časová os od najnovšej udalosti, každá s `code`, `description`, `location` a časom.
- `proofs`: súbory dokladu o doručení. Zobrazte ich, keď je `status` `delivered`.
- `carrier` (iba objednávka štítku): názov dopravcu, sledovacie číslo a odkaz na sledovanie (`tracking_url`).

**GraphQL:** `uniorderTracking` ([Príručka GraphQL](/api/graphql/documentation#/orders/uniorderTracking))

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

**Overenie:** volanie sledovania vráti `result` `true`, `status` objednávky a jej `events`.

## 10. Zrušenie objednávky

Keď zákazník zruší webovú objednávku, obchod zruší zásielku rovnakým volaním pre objednávku doručenia aj pre objednávku štítku. Štítok sa najprv zneplatní u jeho dopravcu.

**REST:** `POST /api/v1/uniorder/{orderId}/cancel` — [Príručka REST](/api/documentation#/paths/v1-uniorder-orderId--cancel/post)

```bash
curl -X POST https://YOUR_HOST/api/v1/uniorder/123456/cancel \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: cancel-10045" \
  -d '{}'
```

```json
{
  "result": true,
  "type": "self_delivery",
  "id": 123456,
  "already_cancelled": false,
  "message": "The order has been cancelled."
}
```

- `already_cancelled`: `true`, keď bola objednávka zrušená pred týmto volaním. Považujte to za úspech.
- Ak objednávka nie je zrušená, odpoveďou je `409` a objednávka zostáva nezmenená: `ORDER_STATUS_NOT_CANCELLABLE` (na zrušenie je neskoro), `ORDER_CANCEL_REFUSED` (momentálne ju nemožno zrušiť) alebo `LABEL_CANCEL_FAILED` (dopravca štítok nezneplatnil). Webovú objednávku ponechajte otvorenú a zásielku riešte ručne.

**GraphQL:** `uniorderCancel` ([Príručka GraphQL](/api/graphql/documentation#/orders/uniorderCancel))

```graphql
mutation {
  uniorderCancel(order_id: 123456)
}
```

**Overenie:** `result` je `true`. Opätovné zrušenie tej istej objednávky vráti `already_cancelled` `true`.

## 11. Neskorší nákup štítku (iba po LABEL_PURCHASE_FAILED)

Tento krok platí iba pre objednávku štítku, ktorej vytvorenie odpovedalo `LABEL_PURCHASE_FAILED`. Odpoveďou bolo `200` s `result` `false`, kódom `LABEL_PURCHASE_FAILED` a `id` objednávky: objednávka sa zachovala bez štítku. Objednávku neodosielajte znova; kúpte štítok pre túto objednávku.

**REST:** `POST /api/v1/uniorder/{orderId}/label` — [Príručka REST](/api/documentation#/paths/v1-uniorder-orderId--label/post)

Vytvorenie, pri ktorom sa nepodarilo kúpiť štítok, odpovedalo:

```json
{
  "result": false,
  "code": "LABEL_PURCHASE_FAILED",
  "type": "label_service",
  "id": 123458,
  "ref": "WEB-10046",
  "tracking_numbers": ["SR26092800003"],
  "quoted_price": "18.40",
  "message": "The quoted service is not offered for this shipment."
}
```

Kúpte štítok pre objednávku `123458`:

```bash
curl -X POST https://YOUR_HOST/api/v1/uniorder/123458/label \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: label-10046" \
  -d '{}'
```

Štítok sa kúpi pri službe zvolenej pri vytvorení objednávky. Ak ho chcete kúpiť pri inej službe toho istého účtu, pošlite v tele nové `rate_id` typu `label_service` z kroku 5 (`{"rate_id": "eyJpdiI6IlpxR0..."}`). Štítok, ktorý je už kúpený, sa vráti a znova sa nekupuje.

```json
{
  "result": true,
  "type": "label_service",
  "id": 123458,
  "ref": "WEB-10046",
  "shipping_price": "18.40",
  "label": {
    "carrier_name": "ups",
    "service_code": "ups_standard",
    "main_tracking_number": "1Z999AA10123456791",
    "label_status": "ready",
    "shipping_label": "JVBERi0xLjQK..."
  }
}
```

- `label.shipping_label`: PDF štítku v base64; vytlačte ho ako v kroku 7.
- `result` `false` opäť s `LABEL_PURCHASE_FAILED`: dopravca stále odmieta. Zopakujte neskôr alebo kúpte pri inej službe s novým `rate_id`.

**GraphQL:** `uniorderPurchaseLabel` ([Príručka GraphQL](/api/graphql/documentation#/orders/uniorderPurchaseLabel))

```graphql
mutation {
  uniorderPurchaseLabel(order_id: 123458)
}
```

**Overenie:** `result` je `true` a `label.shipping_label` obsahuje PDF, alebo `label.label_status` je `pending`, kým dopravca súbor vytvára.

## 12. Dávky

Dávky ocenia alebo vytvoria mnoho zásielok jedným volaním, napríklad veľkoobchodné objednávky z ERP. Každý riadok prejde jednotlivým volaním a vráti to, čo by vrátilo toto volanie; neúspešný riadok nezastaví ostatné riadky.

**REST:** `POST /api/v1/uniorder/rate/batch` — [Príručka REST](/api/documentation#/paths/v1-uniorder-rate-batch/post) · `POST /api/v1/uniorder/batch` — [Príručka REST](/api/documentation#/paths/v1-uniorder-batch/post)

Najviac 20 riadkov na volanie, zodpovedaných v tej istej odpovedi: `shipments` pre dávku cenových ponúk, `orders` pre dávku vytvorenia. Každý riadok má rovnaké polia ako jednotlivé volanie a navyše voliteľnú `reference`, ktorá sa vráti s jeho výsledkom.

```bash
curl -X POST https://YOUR_HOST/api/v1/uniorder/batch \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: erp-2026-10-01" \
  -d '{
    "orders": [
      {
        "reference": "ERP-7781",
        "rate_id": "eyJpdiI6Ik1rT2Z...",
        "ref": "ERP-7781",
        "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 }]
      }
    ]
  }'
```

```json
{
  "result": true,
  "count": 1,
  "results": [
    { "index": 0, "reference": "ERP-7781", "status": 200, "body": { "result": true, "type": "self_delivery", "id": 123460 } }
  ]
}
```

- `results`: jeden na riadok, s `index` riadku, jeho `reference` a so `status` a `body`, ktoré by vrátilo jednotlivé volanie. Každý výsledok priraďte k jeho riadku objednávky podľa `reference`.

**REST:** `POST /api/v1/uniorder/rate/batch-async` — [Príručka REST](/api/documentation#/paths/v1-uniorder-rate-batch-async/post) · `POST /api/v1/uniorder/batch-async` — [Príručka REST](/api/documentation#/paths/v1-uniorder-batch-async/post) · `GET /api/v1/uniorder/jobs/{jobId}` — [Príručka REST](/api/documentation#/paths/v1-uniorder-jobs-jobId/get)

Najviac 500 riadkov zaradených do frontu ako jedna úloha. Volanie vráti `job_id`; čítajte úlohu, kým `status` nie je `done`, a potom načítajte `results`. Rovnaká dávka odoslaná znova, kým prvá ešte čaká vo fronte, vráti prvú úlohu s `duplicate` `true`.

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

```json
{
  "result": true,
  "job_id": 8813,
  "kind": "create",
  "status": "done",
  "count": 1,
  "results": [
    { "index": 0, "reference": "ERP-7781", "status": 200, "body": { "result": true, "type": "self_delivery", "id": 123460 } }
  ]
}
```

- `status`: `queued`, `done` alebo `failed` s `message`, keď úlohu nebolo možné spracovať.
- Úloha sa spustí raz a neopakuje sa. `rate_id`, ktorého platnosť vyprší pred spracovaním jeho riadku, vráti pre tento riadok `RATE_ID_INVALID`; úlohu vytvorenia odošlite čoskoro po dokončení úlohy cenovej ponuky.

**GraphQL:** `uniorderRateBatch` ([Príručka GraphQL](/api/graphql/documentation#/orders/uniorderRateBatch)) · `uniorderCreateBatch` ([Príručka GraphQL](/api/graphql/documentation#/orders/uniorderCreateBatch)) · `uniorderRateBatchAsync` ([Príručka GraphQL](/api/graphql/documentation#/orders/uniorderRateBatchAsync)) · `uniorderCreateBatchAsync` ([Príručka GraphQL](/api/graphql/documentation#/orders/uniorderCreateBatchAsync)) · `uniorderJob` ([Príručka GraphQL](/api/graphql/documentation#/orders/uniorderJob))

```graphql
query {
  uniorderJob(job_id: 8813)
}
```

**Overenie:** dávka vráti jeden výsledok na riadok; asynchrónna úloha dosiahne `status` `done`.

## 13. Spracovanie chýb

| Situácia | Stav HTTP | Kód | Čo integrácia urobí |
|---|---|---|---|
| Povinné pole chýba alebo má nesprávny formát | 400 | `VALIDATION_FAILED` | Opravte pole uvedené v `message` a požiadavku odošlite znova. |
| Príjemca je mimo oblasti doručenia (cenová ponuka) | 200 | `OUT_OF_DELIVERY_AREA` v `errors` | Ponúknite iba sadzby `label_service`. |
| Platnosť `rate_id` vypršala, má nesprávny formát alebo patrí inému účtu | 400 | `RATE_ID_INVALID` | Vyžiadajte novú cenovú ponuku a vytvorte objednávku s jej `rate_id`. Nič sa nevytvorilo. |
| Objednávka štítku bola vytvorená, ale jej štítok nebol kúpený | 200 (`result` `false`) | `LABEL_PURCHASE_FAILED` | Uchovajte `id`; kúpte štítok pomocou `POST /api/v1/uniorder/{orderId}/label`. Objednávku nikdy nevytvárajte znova. |
| Štítok sa vyžaduje skôr, ako bol kúpený | 409 | `LABEL_PURCHASE_FAILED` | Kúpte štítok pomocou `POST /api/v1/uniorder/{orderId}/label`. |
| Objednávka je príliš ďaleko na zrušenie | 409 | `ORDER_STATUS_NOT_CANCELLABLE` | Objednávku ponechajte bez zmeny; vrátenie riešte samostatne. |
| Objednávku momentálne nemožno zrušiť | 409 | `ORDER_CANCEL_REFUSED` | Objednávku ponechajte bez zmeny; zopakujte neskôr alebo kontaktujte firmu. |
| Dopravca štítok nezneplatnil | 409 | `LABEL_CANCEL_FAILED` | Objednávka je nezmenená; zrušenie zopakujte neskôr. |
| Objednávka alebo úloha neexistuje alebo patrí inému účtu | 404 | `ORDER_NOT_FOUND` | Skontrolujte `id` uložené k webovej objednávke. |
| `Idempotency-Key` je použitý znova s iným telom | 409 | `IDEMPOTENCY_CONFLICT` | Pre inú požiadavku použite nový kľúč. |
| Token chýba alebo vypršal, alebo účet nesmie zadávať objednávky | 401 | — | Prihláste sa znova; skontrolujte oprávnenia účtu. |

## Zoznam testov

Použite testovací `ref`, napríklad `WEB-10045`:

- [ ] Cenová ponuka vráti sadzbu `self_delivery` pre adresu v oblasti.
- [ ] S `quote_labels` cenová ponuka vráti sadzby `label_service`, každú s `rate_id`.
- [ ] Objednanie s `rate_id` typu `self_delivery` vráti `id` a `tracking_numbers`.
- [ ] Objednanie s `rate_id` typu `label_service` vráti štítok ocenenej služby.
- [ ] Rovnaký `Idempotency-Key` nevytvorí druhú objednávku.
- [ ] `rate_id` staršie ako 30 minút vráti `RATE_ID_INVALID`.
- [ ] Štítok každej objednávky sa dekóduje na PDF vhodné na tlač.
- [ ] Objednávku, jej štítok a sledovanie možno načítať pomocou `id` z vytvorenia.
- [ ] Zrušenie testovacej objednávky vráti `result: true`; jej opätovné zrušenie vráti `already_cancelled: true`.
- [ ] Po `LABEL_PURCHASE_FAILED` kúpi `POST /api/v1/uniorder/{orderId}/label` štítok pre tú istú objednávku.
- [ ] Dávka s dvoma riadkami vráti dva výsledky s ich `reference`.
