# Uniorder: uma API para cada envio

O Uniorder é um conjunto único de endpoints através do qual uma integração cota, cria, imprime, rastreia e cancela todos os envios da conta, qualquer que seja a forma como o envio é executado. Uma única cotação devolve a entrega feita pela própria empresa e, a pedido, todos os serviços de etiqueta de transportadora da conta, cada um com um `rate_id`. O pedido é criado enviando de volta o `rate_id` escolhido; nenhum outro elemento do pedido HTTP seleciona o serviço.

## 1. O que pode construir

- **Um checkout que apresenta todas as opções de envio de uma só vez.** O cliente introduz um endereço, o checkout chama um único endpoint e a página lista a entrega local ao lado da UPS, da Canada Post e de qualquer outra transportadora que a conta utilize, cada uma com o respetivo preço.
- **Um conector de gestão de pedidos ou de ERP com um único caminho de código.** Os pedidos de todos os canais passam pelas mesmas chamadas de criação, consulta, etiqueta, rastreio e cancelamento. O conector não precisa de lógica separada para a entrega local e para as etiquetas de transportadora.
- **Processamento em lote durante a noite.** Até 500 envios são cotados ou criados num único job em fila, e os resultados são lidos pelo id do job.
- **Um ecrã de apoio ao cliente.** Um agente procura um pedido, reimprime a sua etiqueta, lê a linha temporal de rastreio e cancela-o, com as mesmas quatro chamadas para qualquer pedido.

## 2. O que o Uniorder faz por si

| Sem o Uniorder | Com o Uniorder |
|---|---|
| Uma API para os pedidos de entrega local e outra para as etiquetas de transportadora, cada uma com os seus próprios campos e respostas | Uma forma de pedido (`from_*`, `to_*`, `packages`) e uma forma de resposta para todos os serviços |
| A integração decide que API de transportadora chamar | A cotação lista todos os serviços; o `rate_id` da tarifa escolhida decide |
| Endpoints de etiqueta, rastreio e cancelamento separados por serviço | `GET /label`, `GET /tracking` e `POST /cancel` funcionam para todos os pedidos |
| Criação em lote disponível apenas para a entrega local | Cotação em lote e criação em lote para todos os serviços, síncronas ou em fila |

O Uniorder não substitui os endpoints existentes; estes continuam disponíveis e inalterados. É o ponto de entrada recomendado para uma nova integração.

## 3. Mapa de endpoints, pela ordem em que uma integração os utiliza

| Passo | Finalidade | REST | GraphQL |
|---|---|---|---|
| 1 | Obter um token de acesso | `POST /api/v1/user/login` | `userLogin` |
| 2 | Cotar todos os serviços | `POST /api/v1/uniorder/rate` | `uniorderRate` |
| 3 | Criar o pedido com a tarifa escolhida | `POST /api/v1/uniorder` | `uniorderCreate` |
| 4 | Imprimir a etiqueta | `GET /api/v1/uniorder/{orderId}/label` | `uniorderLabel` |
| 5 | Consultar o pedido | `GET /api/v1/uniorder/{orderId}` | `uniorder` |
| 6 | Rastrear o pedido | `GET /api/v1/uniorder/{orderId}/tracking` | `uniorderTracking` |
| 7 | Cancelar o pedido | `POST /api/v1/uniorder/{orderId}/cancel` | `uniorderCancel` |
| — | Comprar uma etiqueta que não pôde ser comprada na criação | `POST /api/v1/uniorder/{orderId}/label` | `uniorderPurchaseLabel` |
| — | Cotar ou criar até 20 linhas de uma só vez | `POST /api/v1/uniorder/rate/batch`, `POST /api/v1/uniorder/batch` | `uniorderRateBatch`, `uniorderCreateBatch` |
| — | Colocar até 500 linhas em fila | `POST /api/v1/uniorder/rate/batch-async`, `POST /api/v1/uniorder/batch-async`, `GET /api/v1/uniorder/jobs/{jobId}` | `uniorderRateBatchAsync`, `uniorderCreateBatchAsync`, `uniorderJob` |

[Manual REST](/api/documentation#/paths/v1-uniorder-rate/post) · [Manual GraphQL](/api/graphql/documentation#/orders/uniorderRate)

Os pedidos HTTP, as respostas e as verificações passo a passo encontram-se no guia **Cotação e pedido num só fluxo**.

## 4. Exemplo: um checkout que apresenta todas as opções

Uma florista em Montreal vende online. No checkout, cota o volume uma vez, com as transportadoras de etiquetas incluídas:

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

A resposta lista uma tarifa `self_delivery` e uma tarifa `label_service` por serviço de transportadora. O checkout apresenta-as como opções; o cliente escolhe a entrega local no próprio dia. O pedido é criado com o `rate_id` dessa tarifa e com os mesmos endereços e volumes:

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

A resposta devolve o `id` do pedido e os seus números de rastreio. A loja imprime a etiqueta com `GET /api/v1/uniorder/{orderId}/label` e mostra a linha temporal de `GET /api/v1/uniorder/{orderId}/tracking` na página do pedido do cliente.

## 5. Exemplo: um ERP que expede todas as noites

Um ERP exporta os pedidos do dia às 22:00. Envia os endereços para `POST /api/v1/uniorder/rate/batch-async`, lê o job até `status` ser `done`, seleciona uma tarifa para cada linha segundo as suas próprias regras e envia as linhas escolhidas para `POST /api/v1/uniorder/batch-async`. Cada resultado traz o `reference` da linha, para que o ERP associe cada resultado à sua própria linha de pedido. Um `rate_id` é válido durante 30 minutos, pelo que o job de criação é enviado pouco depois de o job de cotação terminar.

## 6. Exemplo: um ecrã de apoio ao cliente

Durante a chamada de um cliente, o ecrã do agente chama `GET /api/v1/uniorder/{orderId}` para obter o estado e os endereços, `GET /api/v1/uniorder/{orderId}/tracking` para obter a linha temporal e o comprovativo de entrega, e `POST /api/v1/uniorder/{orderId}/cancel` quando o cliente cancela. As mesmas chamadas aplicam-se a um pedido de entrega e a um pedido de etiqueta; o campo `type` distingue-os.

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

O mesmo pedido via GraphQL ([Manual GraphQL](/api/graphql/documentation#/orders/uniorder)):

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

## 7. Regras a considerar no desenho

- **O `rate_id` determina o serviço.** É válido durante 30 minutos e apenas para a conta que pediu a cotação.
- **O preço do pedido é calculado quando é criado.** `shipping_price` é o preço cobrado; `quoted_price` é o preço da cotação. Os dois podem ser diferentes.
- **Um pedido de etiqueta nunca se perde.** Quando a etiqueta não pode ser comprada na criação, o pedido é conservado e a resposta é `LABEL_PURCHASE_FAILED` com o `id` do pedido; a etiqueta é comprada mais tarde com `POST /api/v1/uniorder/{orderId}/label`.
- **As repetições são seguras.** Envie um cabeçalho `Idempotency-Key` em cada chamada de criação; o cancelamento de um pedido já cancelado devolve `already_cancelled` `true`.
- **Os estados são uniformes.** Um pedido de entrega indica `pending`, `in_transit`, `out_for_delivery`, `delivered`, `exception` ou `cancelled`; um pedido de etiqueta indica `label_pending`, `label_purchased` ou `cancelled`, e o rastreio da sua transportadora indica onde se encontra o volume.

## 8. Lista de verificação para entrada em produção

- [ ] A conta tem permissão de API e o token está guardado no servidor, não num navegador.
- [ ] As cotações são pedidas com os endereços completos do remetente e do destinatário.
- [ ] Os pedidos são criados nos 30 minutos seguintes à cotação, com uma `Idempotency-Key`.
- [ ] `LABEL_PURCHASE_FAILED` é tratado comprando a etiqueta mais tarde, nunca criando o pedido outra vez.
- [ ] O rastreio é lido a partir de `GET /api/v1/uniorder/{orderId}/tracking` ou recebido através de webhooks.
- [ ] O cancelamento trata `ORDER_STATUS_NOT_CANCELLABLE` e `ORDER_CANCEL_REFUSED` deixando o pedido como está.
