# Guia de Atualizações de Integração

Todas as alterações abaixo são estritamente aditivas: os endpoints existentes, os campos de resposta, os códigos de estado HTTP, os bytes dos payloads de webhooks e o cabeçalho legado `Signature` mantêm-se inalterados. As integrações que nada fizerem continuam a funcionar exatamente como antes. Adote cada funcionalidade de forma independente, por qualquer ordem.

Disponibilizado em tempo real em https://api.superlabel.ca/api/documentation/integration-updates?lang=pt (`?download=1` para guardar). Documentos complementares: OpenAPI (https://api.superlabel.ca/api/documentation?lang=pt), coleção Postman (https://api.superlabel.ca/api/documentation/postman-collection), dicionário e fluxo de estados (https://api.superlabel.ca/api/documentation/order-status-flow?lang=pt).

---

## 1. Cancelamento por número de rastreio (idempotente)

`POST https://api.superlabel.ca/api/v1/orders/cancel` — forneça exatamente um de `order_id`, `tracking_number`, `external_tracking_number`.

```json
POST /api/v1/orders/cancel
Authorization: Bearer <token>
{ "external_tracking_number": "WP1234567890" }
```

- Sucesso: `200 {"result":true,"id":123456,"already_cancelled":false,...}`
- Já cancelada (repetição segura): `200` com `"already_cancelled": true`
- O número corresponde a várias encomendas ativas: `409` com `"matched_order_ids": [...]` — repita com `order_id`.
- O endpoint legado `GET /v1/orders/{orderId}/cancel` mantém-se inalterado.

## 2. Feeds de reconciliação incremental

Percorra tudo o que mudou dentro de uma janela temporal; graças à paginação por cursor, nunca perde nem contabiliza duas vezes um registo.

- `GET https://api.superlabel.ca/api/v1/orders-reconciliation?updated_from=&updated_to=&per_page=&cursor=`
- `GET https://api.superlabel.ca/api/v1/tracking-events/reconciliation?...`

`updated_from` / `updated_to` aceitam timestamps unix ou strings `Y-m-d H:i:s` no fuso horário da plataforma. Siga `next_cursor` até `has_more` ser false; compare com os campos unix `*_timestamp`, nunca com strings de hora local. Os itens de eventos de rastreio incluem `occurred_at` / `occurred_timestamp` (hora da ocorrência do negócio; igual à hora de criação nas linhas históricas).

## 3. Códigos de erro legíveis por máquina e rastreio de pedidos

As respostas de erro de criação/cancelamento de alta frequência incluem agora um campo `code` estável ao lado da `message` inalterada:
`VALIDATION_FAILED`, `MISSING_IDENTIFIER`, `ORDER_NOT_FOUND`,
`ORDER_CANCEL_UNAUTHORIZED`, `ORDER_STATUS_NOT_CANCELLABLE`,
`ORDER_CANCEL_BLOCKED_THIRD_PARTY`, `LABEL_CANCEL_FAILED`,
`DUPLICATE_TRACKING_NUMBER`, `MULTIPLE_ORDERS_MATCHED`.
Os códigos são identificadores estáveis — podem surgir novos, mas os existentes nunca mudam de significado. Todas as respostas da API devolvem também `X-Request-ID`; cite-o ao comunicar um problema.

## 4. Melhorias na deteção de duplicados

Com `auto_deduplication=1`, as entradas `exist_package_ref` / `exist_external_tracking_number` de uma criação bloqueada incluem agora o `order_id` e o `order_ref` existentes, e o envelope inclui `"duplicate": true`. Modo estrito opcional: envie `strict_duplicate_check=1` para receber HTTP `409` em vez do legado `200` + `result:false` (omita o parâmetro para manter o comportamento legado).

## 5. Opções de criação em lote

- `per_order_transaction: 1` (no nível superior do corpo do lote): cada encomenda é confirmada de forma independente — uma falha deixa de reverter as restantes. Se o processamento for interrompido antecipadamente, continua a receber linhas para tudo o que foi concluído, mais uma linha final `{"result":false,"batch_aborted":true}`.
- Lotes com mais de 100 encomendas recebem um cabeçalho de resposta consultivo `X-Batch-Size-Warning`; para grandes volumes, prefira `POST /v1/client/batchOrderCreateAsync`.

## 6. Sincronização de ficheiros de prova de entrega

As entradas `proofs[]` das respostas de rastreio incluem agora também:

```json
{ "url": "...", "full_url": "...", "type": 2,
  "file_id": 234567, "uploaded_at": "2026-07-20 14:30:05",
  "uploaded_timestamp": 1784745005,
  "signed_url": "https://.../files/pod/234567?expires=...&signature=...",
  "signed_url_expires_at": 1784745005 }
```

Use `file_id` como chave de deduplicação / sincronização incremental. `signed_url` é uma ligação com prazo de expiração (7 dias) — volte a consultar o rastreio para obter uma nova após a expiração. As ligações permanentes `url` / `full_url` mantêm-se inalteradas.

## 7. Webhooks: cabeçalhos de assinatura v2 (todas as entregas)

Cada webhook envia agora TAMBÉM, juntamente com o cabeçalho legado `Signature` inalterado:

| Cabeçalho | Significado |
|---|---|
| `X-Webhook-Event-Id` | UUID, estável entre novas tentativas — use para deduplicação |
| `X-Webhook-Timestamp` | segundos unix no primeiro envio |
| `X-Webhook-Signature-V2` | HMAC-SHA256 de `"<timestamp>.<raw body>"` |

Verificação (em qualquer linguagem): `expected = HMAC_SHA256(timestamp + "." + raw_body, your_secret)`; compare com o cabeçalho em tempo constante. O timestamp é fixado no primeiro envio e reutilizado nas novas tentativas (as tentativas podem prolongar-se até ~3 horas), pelo que deve combinar uma janela de tolerância generosa com deduplicação por `X-Webhook-Event-Id`, em vez de um limite de replay apertado. A sua verificação existente do `Signature` legado continua a funcionar sem alterações — adote a v2 quando quiser. Teste ambas as assinaturas contra o seu endpoint a partir da página do guia de webhooks (`/webhooks-guide`).

## 8. Webhooks: envelope de payload opcional

Defina `webhook_payload_envelope = 1` nas suas definições de webhooks para receber, dentro do corpo JSON dos eventos com forma de objeto: `event_id`, `event_time` (ISO8601 com desvio horário), `event_timestamp` (unix), e ainda — quando aplicável — `is_correction: true` (uma encomenda anteriormente entregue/transferida voltou a entrar no fluxo) e `occurred_at` / `occurred_timestamp` nos eventos de rastreio. Sem esta opção, o payload permanece byte a byte idêntico ao anterior. Os payloads em forma de lista (`order.create_async`) nunca são modificados.

## 9. Novos eventos de webhook (URLs de adesão opcional)

- `pod.files_updated` — uma fotografia/assinatura de entrega foi adicionada ou removida posteriormente. Configure `pod_files_webhook_url`. Payload:
  `{"action":"added|removed","order_id":...,"order_ref":...,
  "tracking_number":[...],"external_tracking_number":[...],
  "file":{"file_id":...,"type":1|2,"note":null}, "event_id":..., ...}`
- `order.deleted` — uma encomenda foi eliminada permanentemente. Configure `order_deleted_webhook_url`. Payload: `{"action":"deleted","order_id":...,
  "order_ref":...,"tracking_number":[...],"external_tracking_number":[...],
  "event_id":..., ...}`

Ambos os eventos incluem sempre os campos do envelope e só são enviados quando o respetivo URL está configurado.

## 10. Webhooks: opções de entrega

- **Múltiplos endpoints por evento**: cada definição de URL de webhook aceita um único URL (como antes), uma lista separada por vírgulas ou um array JSON. Cada endpoint tem o seu próprio ciclo de entrega e de novas tentativas.
- **Verificação TLS**: defina `webhook_verify_ssl = 1` para que as chamadas de saída verifiquem o seu certificado. O predefinido continua desativado (comportamento histórico).
- **order.created para todos os tipos de encomenda**: defina `order_created_webhook_all_types = 1` para alargar o evento de criação de encomenda para além das encomendas de entrega local. O predefinido mantém o âmbito histórico.
- **Segredos de assinatura**: as configurações iniciais recebem um segredo aleatório forte; os segredos existentes nunca são rodados automaticamente.

## 11. Âmbitos de tokens de API e listas de IPs permitidos (opcional)

Os tokens individuais podem ser limitados a `orders:read`, `orders:write` e/ou `webhooks:manage`, e a uma lista de IPs permitidos. Os tokens sem restrições (o predefinido, e todos os tokens pré-existentes) comportam-se exatamente como antes. Um token restrito que chame fora dos seus âmbitos/IPs recebe `403`. Contacte o suporte para restringir um token.

## 12. Envio de pacotes da transportadora (Smart Locker)

Transportadoras externas enviam pacotes para a área de preparação de um armazém numa única chamada em lote. Opcionalmente, é possível anexar telefone/e-mail do destinatário para notificá-lo com um código de retirada assim que o pacote for colocado num cacifo inteligente. Os campos do destinatário são opcionais — o endpoint permanece retrocompatível.

```json
POST https://api.superlabel.ca/api/v1/inventories/carrier-staging-stockin
Authorization: Bearer <token>
{ "carrier_id": 1, "warehouse_id": 10, "data": [
  { "carrier_reference_number": "TRK1", "ref": "REF1",
    "recipient_phone": "+14165550123", "recipient_email": "r@example.com" }
] }
```

```graphql
mutation($carrierId: Int!, $warehouseId: Int, $packages: Json) {
  submitCarrierPackages(carrierId: $carrierId, warehouseId: $warehouseId, packages: $packages)
}
```

- Autenticação: token Bearer como de costume. As contas de cliente precisam de uma autorização de upload da transportadora (transportadora + armazém); as contas client, employee e partner usam o seu próprio âmbito de armazém.
- Por pacote: member_number e/ou carrier_reference_number conforme as definições da transportadora; opcionais carrier_order_id, batch, ref, grid_code (apenas pessoal), recipient_phone, recipient_email.
- Cada linha da resposta devolve um pickup_code; o mesmo código é entregue ao destinatário na notificação de retirada.

O contacto do destinatário é armazenado cifrado e nunca é devolvido. Quando telefone e e-mail são fornecidos, ambos os canais são notificados; telefone/e-mail têm prioridade sobre a notificação na aplicação por vínculo de membro.

## Compromisso de compatibilidade

Consulte a política de gestão de alterações: respostas apenas aditivas, novos endpoints ao lado dos antigos, corpos de webhooks congelados por predefinição, valores predefinidos nunca alterados, descontinuações anunciadas com pelo menos 30 dias de antecedência com os cabeçalhos `Deprecation` / `Sunset`. Estas garantias são aplicadas por testes automatizados de compatibilidade ao nível do byte em cada lançamento.