# Árajánlat és rendelés egy folyamatban

Ez az útmutató kérésről kérésre mutatja be az Uniorder API-t (`/api/v1/uniorder/...`), abban a sorrendben, ahogyan egy integráció felépül: hitelesítés, árajánlat, létrehozás a kiválasztott `rate_id` értékkel, címkenyomtatás, a rendelés lekérdezése, követése és lemondása, valamint a küldemények kötegelt feldolgozása. Egy árajánlat felsorolja a fiók összes lehetőségét egy csomag feladására: a cég saját kiszállítását, és kérésre a fuvarozók összes címkeszolgáltatását. A `rate_id` értékkel leadott rendelés az adott szolgáltatáshoz jön létre: kézbesítési rendelés, vagy címkerendelés, amelynek címkéje az ajánlatban szereplő fuvarozói szolgáltatásnál kerül megvásárlásra. Az útmutató olyan webáruházak, rendeléskezelő rendszerek és ERP-rendszerek fejlesztőinek szól, amelyek céges fiókon keresztül szállítanak.

## 1. Mit építhet

Az alábbi példák egyetlen vállalkozást követnek: a **Fleurs du Plateau** virágüzletet (4500 Rue Saint-Denis, Montreal, H2J 2L3), amely online árusít csokrokat. Egy jellemző küldemény egy 1,2 kg-os, 40 × 25 × 25 cm-es doboz, amely Jane Recipient címére (6841 Rue Saint-Denis, Montreal, H2S 2S3) megy a `WEB-10045` webes rendelés alapján.

- **Pénztár, amely minden szállítási lehetőséget felkínál.** Az áruház egyszer kér árajánlatot a csomagra, és a fiók minden fuvarozói címkeszolgáltatása mellett megjeleníti az aznapi helyi kiszállítást, mindegyiket az árával, majd a vevő által választott lehetőséggel hozza létre a rendelést.
- **Automatikus címkenyomtatás.** A rendelés létrehozásakor az áruház letölti a címke PDF-jét, és elküldi a csomagolóállomás nyomtatójára, akár a vállalkozás, akár egy fuvarozó kézbesíti a csomagot.
- **Rendelési oldal élő követéssel.** A vevő rendelési oldala megjeleníti a küldemény állapotát és eseményeinek idővonalát, a csokor kézbesítése után pedig a kézbesítési igazolást is.
- **Éjszakai köteg az ERP-ből.** A nap nagykereskedelmi rendeléseinek árajánlata és létrehozása egyetlen, legfeljebb 500 soros, sorba állított feladatban történik, és minden eredmény a `reference` alapján rendelhető vissza a saját rendelési tételéhez.

## 2. Mit tartalmaz ez az útmutató

Ez az Uniorder API lépésenkénti útmutatója. Az Uniorder által kínált lehetőségek és azok indokainak áttekintése az **Uniorder: egy API minden küldeményhez** útmutatóban található; ez az útmutató az egyes hívások kéréseit, válaszait és ellenőrzéseit adja meg.

Az Uniorder az ajánlott egyetlen belépési pont azoknak az új integrációknak, amelyek helyi kiszállítással vagy fuvarozói címkével adnak fel csomagokat: a helyi kiszállítási API és a fuvarozói címke API külön hívásait egyetlen kérésformával váltja fel. A **Felvétel és kézbesítés (saját flotta)** és a **Fuvarozói címkék** útmutatóban leírt korábbi végpontok változatlanul elérhetők maradnak. Az Uniorder nem vonatkozik a vevői fiók által foglalt szállítási szolgáltatásokra, sem a tárolási és kiszállítási rendelésekre; ezekhez használja a **Szállítási szolgáltatások** és a **Tárolás és kiszállítás** útmutatót.

## 3. Mielőtt elkezdi

- **Fiók.** Használjon API-jogosultsággal rendelkező céges (ügyfél-) fiókot vagy a cég alkalmazotti fiókját. A cég vevői fiókja is hívhatja az Uniordert; az árajánlat és a számlázás ilyenkor mindig a saját nevére szól. Kézbesítési rendelés létrehozásához rendelésleadási jogosultság szükséges.
- **Vevők.** Ügyfél- vagy alkalmazotti fiók a `customer_id` vagy a `customer_code` megadásával kérhet árajánlatot és adhat le rendelést valamelyik vevője számára; a `rate_id` ekkor ezt a vevőt hordozza, és az ár a vevő díjcsomagját követi.
- **Címkeszolgáltatások.** A `label_service` díjak fogadásához a fióknak (vagy a megnevezett vevőnek) legalább egy beállított fuvarozói címkefiókkal kell rendelkeznie.
- **Tesztadatok.** A `self_delivery` díjakhoz használjon a cég kézbesítési területén belüli címet, valamint olyan teszthivatkozásokat, például `WEB-10045`, amelyek utólag lemondhatók.
- **Tokenek.** A hozzáférési tokent a szerveréről kérje le, és ott is tárolja. Soha ne küldje el böngészőnek vagy mobilalkalmazásnak.
- **Helyőrzők.** Cserélje a `YOUR_HOST` értéket a környezete API-hosztjára, az `ACCESS_TOKEN` értéket pedig a 4. lépésben kapott tokenre.

## 4. Hitelesítés

Minden Uniorder-hívás egy fiók nevében történik. Jelentkezzen be egyszer a szerveréről, tárolja a kapott tokent, és küldje el minden kérésben.

**REST:** `POST /api/v1/user/login` — [REST kézikönyv](/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`: helyezze el minden későbbi kérés fejlécében:

```
Authorization: Bearer ACCESS_TOKEN
```

A GraphQL ugyanazt a fejlécet használja a `POST /api/graphql` híváson.

**GraphQL:** `userLogin` ([GraphQL kézikönyv](/api/graphql/documentation#/user/userLogin))

**Ellenőrzés:** a belépés `access_token`-t ad. Az e token nélküli későbbi kérések `401`-et adnak.

## 5. Árajánlat minden szolgáltatásra

Az árajánlat felsorolja a csomag feladásának összes módját, mindegyikhez árral és `rate_id` értékkel. A pénztár a díjakat lehetőségekként jeleníti meg; semmi nem jön létre és semmi nem kerül lefoglalásra.

**REST:** `POST /api/v1/uniorder/rate` — [REST kézikönyv](/api/documentation#/paths/v1-uniorder-rate/post)

A feladó és a címzett teljes cím; csak a `from_address_2` és a `to_address_2` opcionális. Minden csomaghoz meg kell adni a `weight`, `length`, `width` és `height` értéket. A fuvarozói címkeszolgáltatások hozzáadásához állítsa a `quote_labels` értékét `true`-ra; ekkor mindkét fél neve és telefonszáma kötelező. Ügyfél- vagy alkalmazotti fiók a `customer_id` vagy a `customer_code` megadásával kérhet árajánlatot valamelyik vevője számára. A kézbesítési időablakot (`time_window_start`, `time_window_end`, formátum: `YYYY-MM-DD HH:MM:SS`) a rendszer figyelembe veszi, ha az ár függ tőle.

```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`: kiszállítás a vállalkozás által. Árajánlatonként legfeljebb egy.
- `type` `label_service`: címkefiókonként szolgáltatásonként egy. Jelenítse meg a vevőnek a `service_name`, `shipping_price` és `transit_days` értéket.
- Az `errors` felsorolja, mire nem sikerült árajánlatot adni, a `type` értékével. A kézbesítési területen kívüli cím `self_delivery` típusú hiba `OUT_OF_DELIVERY_AREA` kóddal; ilyenkor csak a címkeszolgáltatásokat jelenítse meg.
- A `rate_id` 30 percig érvényes, és csak az árajánlatot kérő fiók számára. Tárolja a pénztári munkamenettel együtt.
- A `result` értéke `true`, ha legalább egy díj található.

**GraphQL:** `uniorderRate` ([GraphQL kézikönyv](/api/graphql/documentation#/orders/uniorderRate)). A válasz JSON skalár, ezért a műveletnek nincs selection setje.

```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
  )
}
```

Változók:

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

**Ellenőrzés:** a `rates` területen belüli címre tartalmaz egy `self_delivery` díjat, a `quote_labels` megadásával pedig fuvarozói szolgáltatásonként egy `label_service` díjat. Semmi nem jön létre.

## 6. Rendelés létrehozása a kiválasztott díjjal

Amikor a vevő fizet, az áruház a választott lehetőség `rate_id` értékével és ugyanazzal a küldeménnyel hozza létre a rendelést. A szolgáltatást a `rate_id` határozza meg; a kérésben semmi más nem választja ki.

**REST:** `POST /api/v1/uniorder` — [REST kézikönyv](/api/documentation#/paths/v1-uniorder/post)

Minden létrehozáskor küldjön rendelésenként egyedi `Idempotency-Key` fejlécet. Az azonos kulccsal és azonos törzzsel megismételt kérés az első választ adja vissza `replayed` `true` értékkel, és nem hoz létre második rendelést.

```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
    }]
  }'
```

Egy `self_delivery` díj kézbesítési rendelést hoz létre. `D` `type` esetén a címzett a megálló; állítsa a `need_pick_up` értékét `1`-re, ha a csomagot a feladónál kell felvenni. `P` `type` esetén a feladó a megálló.

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

Egy `label_service` díj címkerendelést hoz létre, és megvásárolja a címkét az ajánlatban szereplő fuvarozói szolgáltatásnál. A `type` értéke csak `D` lehet, és a `from_name`, `from_telephone`, `to_name` és `to_telephone` kötelező. Ha a vevő az UPS STANDARD szolgáltatást választotta volna, a válasz a következő lenne:

```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`: tárolja a webes rendeléssel együtt; minden későbbi hívás ezt használja.
- `tracking_numbers`: a küldemény saját követési számai, csomagonként egy.
- `shipping_price`: a felszámított ár. A rendelés ára a létrehozáskor kerül kiszámításra; a `quoted_price` az árajánlatban szereplő ár. A kettő eltérhet.
- `label.main_tracking_number` és `label.shipping_label` (csak címkerendelésnél): a fuvarozó követési száma és a címke PDF-je base64 kódolásban.
- `result` `false` `LABEL_PURCHASE_FAILED` kóddal (csak címkerendelésnél): a rendelés létezik, de nincs címkéje. Őrizze meg az `id` értéket, és folytassa a 11. lépéssel.

**GraphQL:** `uniorderCreate` ([GraphQL kézikönyv](/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
  )
}
```

Változók:

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

**Ellenőrzés:** a `result` értéke `true`, és az `id` ki van töltve. A lejárt vagy más fiókhoz tartozó `rate_id` `400`-at ad `RATE_ID_INVALID` kóddal, és semmi nem jön létre.

## 7. A címke nyomtatása

A csomagolóállomás azonnal kinyomtatja a címkét, amint a rendelés létrejött. Ugyanaz a hívás adja vissza kézbesítési rendelésnél a vállalkozás saját címkéjét, címkerendelésnél pedig a megvásárolt fuvarozói címkét.

**REST:** `GET /api/v1/uniorder/{orderId}/label` — [REST kézikönyv](/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`: a címke PDF-je base64 kódolásban. Dekódolja, és küldje el a fájlt a nyomtatóra.
- `hide_sender_address`, `hide_receiver_address` (`1` az elrejtéshez): a kézbesítési rendelés saját céges címkéjére vonatkoznak.
- `label_status` (címkerendelés): `ready`, ha a fájl visszaadásra kerül. Ha a fuvarozó még nem állította elő a fájlt, a válasz `200`, `result` `false` és `label_status` `pending` értékkel; kérje le később újra a címkét.
- Ez a hívás soha nem vásárol címkét: a meg nem vásárolt címke `409`-et ad `LABEL_PURCHASE_FAILED` kóddal. Vásárolja meg a 11. lépéssel.

**GraphQL:** `uniorderLabel` ([GraphQL kézikönyv](/api/graphql/documentation#/orders/uniorderLabel))

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

**Ellenőrzés:** a `result` értéke `true`, és a dekódolt `pdf_data` PDF-ként megnyílik, rajta a rendelés követési számával.

## 8. A rendelés lekérdezése

Az áruház lekérdezi a rendelést, hogy a rendelési oldalon vagy egy ügyfélszolgálati képernyőn megjelenítse annak állapotát, címeit és csomagjait.

**REST:** `GET /api/v1/uniorder/{orderId}` — [REST kézikönyv](/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` vagy `label_service`; a többi mező mindkettőnél ugyanazt a szerkezetet követi.
- `status`: kézbesítési rendelésnél `pending`, `in_transit`, `out_for_pickup`, `out_for_delivery`, `ready_for_self_pickup`, `delivered`, `exception` vagy `cancelled`, címkerendelésnél `label_pending`, `label_purchased` vagy `cancelled`.
- `label` (csak címkerendelésnél): a fuvarozó, a szolgáltatás, a `carrier_tracking_numbers` és a `label_status` (`not_purchased`, `pending`, `ready` vagy `failed`).

**GraphQL:** `uniorder` ([GraphQL kézikönyv](/api/graphql/documentation#/orders/uniorder))

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

**Ellenőrzés:** a rendelés visszaadja a `status` és `packages` értékeit, és a `ref` megegyezik a webes rendeléssel.

## 9. A rendelés követése

A rendelési oldal megjeleníti a küldemény idővonalát. Kérdezze le, amikor a vevő megnyitja az oldalt, vagy tartsa naprakészen webhookok segítségével.

**REST:** `GET /api/v1/uniorder/{orderId}/tracking` — [REST kézikönyv](/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`: az idővonal, a legújabbal kezdve, mindegyik `code`, `description`, `location` értékkel és időponttal.
- `proofs`: a kézbesítési igazolás fájljai. Jelenítse meg őket, amint a `status` értéke `delivered`.
- `carrier` (csak címkerendelésnél): a fuvarozó neve, követési száma és követési hivatkozása (`tracking_url`).

**GraphQL:** `uniorderTracking` ([GraphQL kézikönyv](/api/graphql/documentation#/orders/uniorderTracking))

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

**Ellenőrzés:** a követési hívás `result` `true` értéket, a rendelés `status` értékét és `events` értékeit adja vissza.

## 10. A rendelés lemondása

Amikor a vevő lemondja a webes rendelést, az áruház ugyanazzal a hívással mondja le a küldeményt kézbesítési rendelésnél és címkerendelésnél is. A címkét a rendszer előbb a fuvarozójánál érvényteleníti.

**REST:** `POST /api/v1/uniorder/{orderId}/cancel` — [REST kézikönyv](/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`, ha a rendelést már e hívás előtt lemondták. Kezelje sikeres eredményként.
- Ha a rendelés nem mondható le, a válasz `409`, és a rendelés változatlan marad: `ORDER_STATUS_NOT_CANCELLABLE` (a lemondáshoz már túl késő), `ORDER_CANCEL_REFUSED` (most nem mondható le) vagy `LABEL_CANCEL_FAILED` (a fuvarozó nem érvénytelenítette a címkét). Hagyja nyitva a webes rendelést, és kezelje a küldeményt kézzel.

**GraphQL:** `uniorderCancel` ([GraphQL kézikönyv](/api/graphql/documentation#/orders/uniorderCancel))

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

**Ellenőrzés:** a `result` értéke `true`. Ugyanannak a rendelésnek az ismételt lemondása `already_cancelled` `true` értéket ad.

## 11. Címke későbbi megvásárlása (csak LABEL_PURCHASE_FAILED után)

Ez a lépés csak olyan címkerendelésre vonatkozik, amelynek létrehozása `LABEL_PURCHASE_FAILED` választ adott. A válasz `200` volt, `result` `false` értékkel, `LABEL_PURCHASE_FAILED` kóddal és a rendelés `id` értékével: a rendelés címke nélkül megmaradt. Ne küldje be újra a rendelést; vásárolja meg a címkét ehhez a rendeléshez.

**REST:** `POST /api/v1/uniorder/{orderId}/label` — [REST kézikönyv](/api/documentation#/paths/v1-uniorder-orderId--label/post)

A létrehozás, amely nem tudta megvásárolni a címkét, a következő választ adta:

```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."
}
```

Vásárolja meg a címkét a `123458` rendeléshez:

```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 '{}'
```

A címke a rendelés létrehozásakor választott szolgáltatásnál kerül megvásárlásra. Ha ugyanazon fiók másik szolgáltatásánál szeretné megvásárolni, küldjön a törzsben egy új `label_service` `rate_id` értéket az 5. lépésből (`{"rate_id": "eyJpdiI6IlpxR0..."}`). A már megvásárolt címkét a rendszer visszaadja, és nem vásárolja meg újra.

```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`: a címke PDF-je base64 kódolásban; nyomtassa ki a 7. lépés szerint.
- `result` `false` ismét `LABEL_PURCHASE_FAILED` kóddal: a fuvarozó továbbra is elutasította. Próbálja újra később, vagy vásárolja meg egy másik szolgáltatásnál új `rate_id` értékkel.

**GraphQL:** `uniorderPurchaseLabel` ([GraphQL kézikönyv](/api/graphql/documentation#/orders/uniorderPurchaseLabel))

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

**Ellenőrzés:** a `result` értéke `true`, és a `label.shipping_label` tartalmazza a PDF-et, vagy a `label.label_status` értéke `pending`, amíg a fuvarozó előállítja a fájlt.

## 12. Kötegek

A kötegek egyetlen hívásban adnak árajánlatot sok küldeményre vagy hoznak létre sok küldeményt, például az ERP nagykereskedelmi rendeléseit. Minden sor az egyedi hívás szerint kerül feldolgozásra, és azt adja vissza, amit az egyedi hívás adna; egy hibás sor nem állítja le a többi sort.

**REST:** `POST /api/v1/uniorder/rate/batch` — [REST kézikönyv](/api/documentation#/paths/v1-uniorder-rate-batch/post) · `POST /api/v1/uniorder/batch` — [REST kézikönyv](/api/documentation#/paths/v1-uniorder-batch/post)

Hívásonként legfeljebb 20 sor, amelyekre ugyanaz a válasz felel: árajánlat-kötegnél `shipments`, létrehozási kötegnél `orders`. Minden sor ugyanazokat a mezőket tartalmazza, mint az egyedi hívás, továbbá egy opcionális `reference` értéket, amelyet a rendszer az eredménnyel együtt visszaad.

```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`: soronként egy, a sor `index` és `reference` értékével, valamint azzal a `status` és `body` értékkel, amelyet az egyedi hívás adna. Minden eredményt a `reference` alapján rendeljen a saját rendelési tételéhez.

**REST:** `POST /api/v1/uniorder/rate/batch-async` — [REST kézikönyv](/api/documentation#/paths/v1-uniorder-rate-batch-async/post) · `POST /api/v1/uniorder/batch-async` — [REST kézikönyv](/api/documentation#/paths/v1-uniorder-batch-async/post) · `GET /api/v1/uniorder/jobs/{jobId}` — [REST kézikönyv](/api/documentation#/paths/v1-uniorder-jobs-jobId/get)

Legfeljebb 500 sor, egyetlen feladatként sorba állítva. A hívás egy `job_id` értéket ad vissza; kérdezze le a feladatot, amíg a `status` értéke `done` nem lesz, majd olvassa ki a `results` értékét. Ha ugyanazt a köteget újra elküldi, amíg az első még a sorban van, a rendszer az első feladatot adja vissza `duplicate` `true` értékkel.

```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`, vagy `failed` egy `message` értékkel, ha a feladatot nem sikerült feldolgozni.
- Egy feladat egyszer fut le, és nem kerül újrapróbálásra. Az a `rate_id`, amely a sora feldolgozása előtt lejár, az adott sorra `RATE_ID_INVALID` értéket ad; a létrehozási feladatot röviddel az árajánlat-feladat befejeződése után küldje el.

**GraphQL:** `uniorderRateBatch` ([GraphQL kézikönyv](/api/graphql/documentation#/orders/uniorderRateBatch)) · `uniorderCreateBatch` ([GraphQL kézikönyv](/api/graphql/documentation#/orders/uniorderCreateBatch)) · `uniorderRateBatchAsync` ([GraphQL kézikönyv](/api/graphql/documentation#/orders/uniorderRateBatchAsync)) · `uniorderCreateBatchAsync` ([GraphQL kézikönyv](/api/graphql/documentation#/orders/uniorderCreateBatchAsync)) · `uniorderJob` ([GraphQL kézikönyv](/api/graphql/documentation#/orders/uniorderJob))

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

**Ellenőrzés:** a köteg soronként egy eredményt ad; az aszinkron feladat eléri a `status` `done` értéket.

## 13. Hibakezelés

| Helyzet | HTTP-állapot | Kód | Az integráció teendője |
|---|---|---|---|
| Egy kötelező mező hiányzik vagy hibás formátumú | 400 | `VALIDATION_FAILED` | Javítsa a `message` értékében megnevezett mezőt, és küldje el újra a kérést. |
| A címzett a kézbesítési területen kívül esik (árajánlat) | 200 | `OUT_OF_DELIVERY_AREA` az `errors` értékben | Csak a `label_service` díjakat kínálja fel. |
| A `rate_id` lejárt, hibás formátumú vagy más fiókhoz tartozik | 400 | `RATE_ID_INVALID` | Kérjen új árajánlatot, és annak `rate_id` értékével hozza létre a rendelést. Semmi nem jött létre. |
| A címkerendelés létrejött, de a címkéje nem került megvásárlásra | 200 (`result` `false`) | `LABEL_PURCHASE_FAILED` | Őrizze meg az `id` értéket; vásárolja meg a címkét a `POST /api/v1/uniorder/{orderId}/label` hívással. Soha ne hozza létre újra a rendelést. |
| A címkét a megvásárlása előtt kérik le | 409 | `LABEL_PURCHASE_FAILED` | Vásárolja meg a címkét a `POST /api/v1/uniorder/{orderId}/label` hívással. |
| A rendelés feldolgozása túl előrehaladott a lemondáshoz | 409 | `ORDER_STATUS_NOT_CANCELLABLE` | Hagyja a rendelést változatlanul; a visszaküldést külön kezelje. |
| A rendelés most nem mondható le | 409 | `ORDER_CANCEL_REFUSED` | Hagyja a rendelést változatlanul; próbálja újra később, vagy lépjen kapcsolatba a vállalkozással. |
| A fuvarozó nem érvénytelenítette a címkét | 409 | `LABEL_CANCEL_FAILED` | A rendelés változatlan; próbálja újra később a lemondást. |
| A rendelés vagy a feladat nem létezik, vagy más fiókhoz tartozik | 404 | `ORDER_NOT_FOUND` | Ellenőrizze a webes rendeléssel tárolt `id` értéket. |
| Egy `Idempotency-Key` eltérő törzzsel kerül újrafelhasználásra | 409 | `IDEMPOTENCY_CONFLICT` | Eltérő kéréshez használjon új kulcsot. |
| A token hiányzik vagy lejárt, vagy a fiók nem adhat le rendelést | 401 | — | Jelentkezzen be újra; ellenőrizze a fiók jogosultságait. |

## Tesztlista

Használjon teszt `ref` értéket, pl. `WEB-10045`:

- [ ] Az árajánlat `self_delivery` díjat ad területen belüli címre.
- [ ] A `quote_labels` megadásával az árajánlat `label_service` díjakat ad, mindegyiket `rate_id` értékkel.
- [ ] A `self_delivery` `rate_id` értékkel leadott rendelés `id` és `tracking_numbers` értéket ad.
- [ ] A `label_service` `rate_id` értékkel leadott rendelés az ajánlatban szereplő szolgáltatás címkéjét adja.
- [ ] Ugyanaz az `Idempotency-Key` nem hoz létre második rendelést.
- [ ] A 30 percnél régebbi `rate_id` `RATE_ID_INVALID` értéket ad.
- [ ] Minden rendelés címkéje nyomtatható PDF-fé dekódolható.
- [ ] A rendelés, a címkéje és a követése lekérdezhető a létrehozáskor kapott `id` értékkel.
- [ ] Egy tesztrendelés lemondása `result: true` értéket ad; az ismételt lemondása `already_cancelled: true` értéket ad.
- [ ] `LABEL_PURCHASE_FAILED` után a `POST /api/v1/uniorder/{orderId}/label` ugyanahhoz a rendeléshez vásárolja meg a címkét.
- [ ] Egy kétsoros köteg két eredményt ad a `reference` értékükkel.
