API de Integração — Atualização de Rastreio de Pedidos
Documento de contrato para integrações externas (WMS, ERP, Make, n8n, scripts).
Base URL (produção)
https://apiv3.usecorvex.com.br
Todas as URLs abaixo são relativas a essa base (sem barra final na base).
Visão geral
A Corvex oferece uma superfície dedicada para o lojista atualizar o código de rastreio dos pedidos via API Key, sem expor o JWT de sessão do painel.
| Item | Valor |
|---|---|
| Prefixo da API de integração | /integrations/v1 |
| Autenticação | Authorization: Bearer cvx_live_... |
| Escopo obrigatório | orders:write |
| Restrição de loja | storeIds na chave (obrigatório para este escopo) |
| JWT do painel | Não aceito nas rotas /integrations/v1/* |
O que a API faz
- Atualiza
trackingCode,trackingUrl,trackingStatusetrackingCarrierno pedido. - Dispara o mesmo fluxo interno do painel (timeline de rastreio, automações
tracking_code_updated, integrações Appmax/Reportana quando aplicável). - Aceita identificador do pedido como UUID interno ou
external_id(referência externa do pedido na loja).
O que a API não faz
- Não lista pedidos (use o painel ou outras rotas autenticadas por JWT).
- Não cria pedidos.
- Não aceita
x-api-keydo checkout externo (stores/external/checkout) — sistema diferente.
Fluxo recomendado
Fluxo: painel cria API Key → integração envia PATCH/POST com Bearer cvx_live_... → API retorna 200.
- No painel, com login + 2FA, crie uma API Key com escopo
orders:writee a(s) loja(s) emstoreIds. - Guarde o
plainKey— ele não é exibido novamente. - Na integração, use apenas
Authorization: Bearer cvx_live_...nas rotas/integrations/v1.
Autenticação
Header obrigatório
Authorization: Bearer cvx_live_ABCDEFGHIJKLMNOPQRSTUVWXYZ012345
Content-Type: application/json
- Formato:
cvx_live_+ 32 caracteres (base32 Crockford). - Não use
x-api-keynesta API. - Não envie JWT de sessão do painel nas rotas
/integrations/v1/*.
Criar API Key (painel / JWT apenas)
Esta rota exige token de sessão do painel. Uma API Key não pode criar outra API Key.
| Método | Path |
|---|---|
POST | /api-keys |
GET | /api-keys — listar chaves (sem secret) |
DELETE | /api-keys/:id — revogar |
POST | /api-keys/:id/rotate — rotacionar |
GET | /api-keys/_meta/scopes — listar escopos disponíveis |
Exemplo — criar chave para rastreio
curl --request POST 'https://apiv3.usecorvex.com.br/api-keys' \
--header 'Authorization: Bearer SEU_JWT_DO_PAINEL' \
--header 'Content-Type: application/json' \
--data '{
"name": "WMS Rastreio",
"scopes": ["orders:write"],
"storeIds": ["909ed99c-a3a5-4e91-ba41-f4be59df8efb"],
"neverExpires": true
}'
Alternativa com expiração:
{
"name": "WMS Rastreio",
"scopes": ["orders:write"],
"storeIds": ["909ed99c-a3a5-4e91-ba41-f4be59df8efb"],
"expiresAt": "2027-08-28T12:00:00-03:00",
"neverExpires": false
}
Resposta 201 — sucesso
{
"success": true,
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "WMS Rastreio",
"plainKey": "cvx_live_ABCDEFGHIJKLMNOPQRSTUVWXYZ012345",
"prefix": "cvx_live_ABCDEFGHIJKL",
"last4": "2345",
"display": "cvx_live_ABCDEFGHIJKL…2345",
"scopes": ["orders:write"],
"storeIds": ["909ed99c-a3a5-4e91-ba41-f4be59df8efb"],
"expiresAt": null,
"createdAt": "2026-08-28T15:00:00.000Z",
"notice": "Guarde esta chave agora. Ela NÃO será exibida novamente. Se perder, revogue e crie outra."
}
}
Escopos disponíveis (referência)
| Escopo | Uso |
|---|---|
orders:write | Atualizar rastreio de pedidos (esta API) |
stores:read | Listar lojas |
themes:read / themes:write / themes:publish | CLI de temas |
Para orders:write, storeIds é obrigatório (ao menos uma loja UUID).
Endpoints de rastreio (integração)
| Método | Path | Descrição |
|---|---|---|
PATCH | /integrations/v1/stores/:storeId/orders/:orderRef/tracking | Atualiza um pedido |
POST | /integrations/v1/stores/:storeId/orders/tracking/bulk | Atualiza até 100 pedidos |
Parâmetros de rota
| Parâmetro | Tipo | Descrição |
|---|---|---|
storeId | UUID | ID da loja na Corvex. Deve estar em storeIds da chave. |
orderRef | string (1–80) | UUID do pedido ou external_id (ex.: PED-1001, #12345) |
1. Atualizar rastreio de um pedido
Request
PATCH /integrations/v1/stores/{storeId}/orders/{orderRef}/tracking
Authorization: Bearer cvx_live_...
Content-Type: application/json
Body (JSON)
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
trackingCode | string (1–120) | Sim | Código de rastreio |
trackingUrl | string (URL, max 2048) | Não | Link de rastreamento |
trackingStatus | enum | Não | Status do ciclo de vida (ver tabela abaixo) |
trackingCarrier | string (max 120) | Não | Transportadora (ex.: Correios, Jadlog) |
Status de rastreio (trackingStatus)
| Valor | Descrição típica |
|---|---|
label_generated | Etiqueta gerada |
posted | Postado / enviado |
in_transit | Em trânsito |
out_for_delivery | Saiu para entrega |
delivered | Entregue |
failed | Falha na entrega |
returned | Devolvido |
unknown | Status desconhecido |
Exemplo — por UUID do pedido
export API_URL="https://apiv3.usecorvex.com.br"
export API_KEY="cvx_live_ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"
export STORE_ID="909ed99c-a3a5-4e91-ba41-f4be59df8efb"
export ORDER_ID="11111111-1111-4111-8111-111111111111"
curl --request PATCH "${API_URL}/integrations/v1/stores/${STORE_ID}/orders/${ORDER_ID}/tracking" \
--header "Authorization: Bearer ${API_KEY}" \
--header "Content-Type: application/json" \
--data '{
"trackingCode": "AB123456789BR",
"trackingUrl": "https://rastreamento.correios.com.br/app/index.php?objeto=AB123456789BR",
"trackingStatus": "posted",
"trackingCarrier": "Correios"
}'
Exemplo — por external_id
curl --request PATCH "${API_URL}/integrations/v1/stores/${STORE_ID}/orders/PED-1001/tracking" \
--header "Authorization: Bearer ${API_KEY}" \
--header "Content-Type: application/json" \
--data '{
"trackingCode": "AB123456789BR"
}'
Resposta 200 — sucesso
{
"success": true,
"message": "Código de rastreio atualizado com sucesso",
"data": {
"order": {
"id": "11111111-1111-4111-8111-111111111111",
"trackingCode": "AB123456789BR",
"trackingUrl": "https://rastreamento.correios.com.br/app/index.php?objeto=AB123456789BR",
"trackingStatus": "posted"
}
}
}
2. Atualizar rastreio em massa (bulk)
Processa até 100 pedidos por requisição. Cada item pode usar UUID ou external_id.
Request
POST /integrations/v1/stores/{storeId}/orders/tracking/bulk
Authorization: Bearer cvx_live_...
Content-Type: application/json
Body (JSON)
{
"items": [
{
"orderId": "PED-1001",
"trackingCode": "AB111111111BR",
"trackingStatus": "posted",
"trackingCarrier": "Correios"
},
{
"orderId": "11111111-1111-4111-8111-111111111111",
"trackingCode": "AB222222222BR",
"trackingUrl": "https://tracking.example.com/AB222222222BR"
}
]
}
| Campo (item) | Tipo | Obrigatório | Descrição |
|---|---|---|---|
orderId | string (1–80) | Sim | UUID ou external_id |
trackingCode | string (1–120) | Sim | Código de rastreio |
trackingUrl | string (URL) | Não | URL de rastreamento |
trackingStatus | enum | Não | Mesmos valores do PATCH individual |
trackingCarrier | string (max 120) | Não | Transportadora |
Exemplo curl
curl --request POST "${API_URL}/integrations/v1/stores/${STORE_ID}/orders/tracking/bulk" \
--header "Authorization: Bearer ${API_KEY}" \
--header "Content-Type: application/json" \
--data '{
"items": [
{ "orderId": "PED-1001", "trackingCode": "AB111111111BR" },
{ "orderId": "PED-1002", "trackingCode": "AB222222222BR", "trackingStatus": "in_transit" }
]
}'
Resposta 200 — todos atualizados
{
"success": true,
"message": "2 rastreio(s) atualizado(s)",
"data": {
"total": 2,
"updated": 2,
"skipped": 0,
"failed": 0,
"results": [
{
"index": 0,
"orderId": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
"orderReference": "PED-1001",
"status": "updated",
"trackingStatus": "posted"
},
{
"index": 1,
"orderId": "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
"orderReference": "PED-1002",
"status": "updated",
"trackingStatus": "in_transit"
}
]
}
}
Resposta 200 — parcial (alguns falharam)
Quando failed > 0, success no corpo é false, mas o status HTTP continua 200 (processamento parcial).
{
"success": false,
"message": "1 rastreio(s) atualizado(s)",
"data": {
"total": 2,
"updated": 1,
"skipped": 0,
"failed": 1,
"results": [
{
"index": 0,
"orderId": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
"orderReference": "PED-1001",
"status": "updated",
"trackingStatus": "posted"
},
{
"index": 1,
"orderId": "PED-9999",
"orderReference": "PED-9999",
"status": "failed",
"reason": "order_not_found"
}
]
}
}
Status por item (results[].status)
| Status | Descrição |
|---|---|
updated | Rastreio persistido ou automação notificada |
skipped | Sem alteração (reason: no_change) |
failed | Erro — ver reason |
Reasons comuns em failed
reason | Descrição |
|---|---|
order_not_found | Pedido não existe nesta loja |
invalid_tracking_code | Código inválido ou vazio após normalização |
Respostas de erro (integração)
Formato pode variar entre rotas que usam FastifyAdapter (objeto error aninhado) e controllers diretos (error como string). Exemplos reais:
400 — validação do body
{
"success": false,
"message": "Dados inválidos",
"errors": [
{
"code": "too_small",
"minimum": 1,
"type": "string",
"message": "Código de rastreio é obrigatório",
"path": ["trackingCode"]
}
]
}
401 — sem credencial ou API Key inválida
{
"success": false,
"error": {
"message": "Credencial inválida.",
"code": "AUTH_API_KEY_INVALID"
},
"meta": {
"timestamp": "2026-08-28T15:00:00.000Z",
"status": 401
}
}
401 — rota de integração sem API Key (JWT enviado por engano)
{
"success": false,
"error": {
"message": "Esta rota exige uma API Key. Use Authorization: Bearer cvx_live_...",
"code": "AUTH_API_KEY_REQUIRED"
},
"meta": {
"timestamp": "2026-08-28T15:00:00.000Z",
"status": 401
}
}
401 — chave expirada / revogada
code | Mensagem típica |
|---|---|
AUTH_API_KEY_EXPIRED | Credencial expirou |
AUTH_API_KEY_REVOKED | Credencial revogada |
403 — escopo insuficiente
{
"success": false,
"error": {
"message": "Sua API Key não tem o escopo 'orders:write' necessário para esta operação.",
"code": "AUTH_SCOPE_DENIED"
},
"meta": {
"timestamp": "2026-08-28T15:00:00.000Z",
"status": 403
}
}
403 — loja não autorizada na chave
{
"success": false,
"message": "Esta API Key não tem acesso a esta loja.",
"error": "AUTH_STORE_ACCESS_DENIED"
}
403 — permissão de pedidos insuficiente
Usuário da chave não é dono/membro com módulo PEDIDOS nível 2 (edição).
{
"message": "Permissão insuficiente para esta ação",
"code": "INSUFFICIENT_PERMISSION",
"module": "PEDIDOS",
"requiredLevel": 2,
"currentLevel": 1
}
403 — faturas vencidas
{
"success": false,
"error": "Acesso bloqueado",
"message": "Você possui faturas vencidas que precisam ser regularizadas",
"reason": "<motivo do bloqueio>",
"details": {}
}
404 — pedido não encontrado na loja
Não revela se o pedido existe em outra loja (anti-IDOR).
{
"success": false,
"message": "Pedido não encontrado nesta loja",
"error": "ORDER_NOT_FOUND"
}
429 — rate limit
{
"success": false,
"message": "Muitas requisições. Tente novamente em instantes.",
"error": "RATE_LIMITED",
"retryAfter": 45
}
Header opcional: Retry-After: 45 (segundos).
Rate limits e proteções
Falhas de autenticação (qualquer rota com API Key)
| Dimensão | Limite |
|---|---|
| Por IP | 10 falhas / minuto |
| Por prefix da chave | 30 falhas / hora |
Após excesso: 429 com RATE_LIMITED ou bloqueio temporário na auth.
Throughput de escrita (rastreio)
| Operação | Por chave / min | Por IP / min | Por loja / min |
|---|---|---|---|
| PATCH individual | 60 | 120 | 200 |
| POST bulk | 10 | 20 | 30 |
Outras proteções
- Chave restrita a
storeIdsdefinidos na criação. - Lookup de pedido sempre filtrado por
storeIdda URL. - Auditoria de uso da API Key (
SCOPE_DENIED,STORE_DENIED,FAILED_AUTH, etc.). - Limite de 20 chaves ativas por usuário (padrão).
Segurança — boas práticas
- Crie uma chave só para integração — escopo mínimo (
orders:write) estoreIdsda loja certa. - Não commite o
plainKeyem repositórios; use variáveis de ambiente ou secret manager. - Rotacione (
POST /api-keys/:id/rotate) se houver suspeita de vazamento. - Revogue (
DELETE /api-keys/:id) chaves antigas. - Prefira
/integrations/v1em vez de expor JWT do painel em automações.
Rotas alternativas (painel / JWT)
O painel Corvex também expõe rotas legadas com JWT de sessão (e API Key com escopo orders:write):
| Método | Path | Auth |
|---|---|---|
PATCH | /orders/:id/tracking | JWT ou API Key + orders:write |
POST | /orders/stores/:storeId/tracking/bulk | JWT ou API Key + orders:write |
Para integrações externas, prefira /integrations/v1 — contrato estável e auth exclusiva por API Key.
Exemplo completo — script bash
#!/usr/bin/env bash
set -euo pipefail
API_URL="${CORVEX_API_URL:-https://apiv3.usecorvex.com.br}"
API_KEY="${CORVEX_API_KEY:?defina CORVEX_API_KEY}"
STORE_ID="${CORVEX_STORE_ID:?defina CORVEX_STORE_ID}"
ORDER_REF="${1:?usage: $0 <orderRef> <trackingCode>}"
TRACKING_CODE="${2:?usage: $0 <orderRef> <trackingCode>}"
curl --silent --show-error --fail-with-body \
--request PATCH "${API_URL}/integrations/v1/stores/${STORE_ID}/orders/${ORDER_REF}/tracking" \
--header "Authorization: Bearer ${API_KEY}" \
--header "Content-Type: application/json" \
--data "$(jq -n \
--arg code "$TRACKING_CODE" \
'{ trackingCode: $code, trackingStatus: "posted" }')"
Exemplo — Make / n8n
HTTP Request node:
- Method:
PATCH - URL:
https://apiv3.usecorvex.com.br/integrations/v1/stores/{{storeId}}/orders/{{orderRef}}/tracking - Authentication: Header
Authorization=Bearer {{apiKey}} - Body (JSON):
{
"trackingCode": "{{trackingCode}}",
"trackingUrl": "{{trackingUrl}}",
"trackingStatus": "posted",
"trackingCarrier": "Correios"
}
Para bulk, use POST em /orders/tracking/bulk com body { "items": [...] }.
Referência rápida de códigos de erro
| HTTP | Código | Causa comum |
|---|---|---|
| 400 | VALIDATION_ERROR | Body inválido (Zod) |
| 401 | AUTH_API_KEY_INVALID | Chave incorreta |
| 401 | AUTH_API_KEY_REQUIRED | JWT em rota /integrations/v1 |
| 401 | AUTH_API_KEY_EXPIRED | Chave expirada |
| 401 | AUTH_API_KEY_REVOKED | Chave revogada |
| 403 | AUTH_SCOPE_DENIED | Falta orders:write |
| 403 | AUTH_STORE_ACCESS_DENIED | Loja fora de storeIds |
| 403 | INSUFFICIENT_PERMISSION | Sem PEDIDOS nível 2 |
| 404 | ORDER_NOT_FOUND | Pedido inexistente na loja |
| 429 | RATE_LIMITED | Muitas requisições |
| 409 | API_KEY_LIMIT_REACHED | Limite de chaves ativas (criação) |
Changelog
| Data | Versão | Notas |
|---|---|---|
| 2026-08-28 | integrations/v1 | Primeira versão pública: escopo orders:write, PATCH + bulk, rate limits |