MANDATORY: Tool Calls Required Before Answering
Estas chamadas são OBRIGATÓRIAS, não opcionais. Execute-as antes de gerar qualquer código ou payload. Se você está respondendo sem ter chamado a ferramenta abaixo, pare e chame agora.
1. Buscar documentação atualizada (sempre)
node skills/tray-dev/scripts/search_docs.mjs --topic=status-pedido "<termo da pergunta>"
<TOPIC_SLUG>: ver tabela emskills/tray-dev/SKILL.md.- Use os trechos retornados como fonte primária; este SKILL.md é resumo denso.
2. Revisar campos (este recurso ainda NÃO tem validate.mjs)
Nota: o recurso
status-pedidoainda não possuiscripts/validate.mjslocal. A chamada OBRIGATÓRIA asearch_docs.mjsacima continua valendo. Como não há validador automático, você é responsável por revisar manualmente cada campo obrigatório contra a doc retornada porsearch_docs.mjse contra os schemas de referência emskills/status-pedido/schemas/antes de retornar qualquer código. Confira em especial: chave de recursoOrderStatuspresente no body,namepreenchido,typedentro do enum (open/closed/cancelled) e cores em hexadecimal completo#RRGGBB.
Antes de responder
Execute estas verificações antes de gerar qualquer payload ou código:
- Confirme o método HTTP e o endpoint correto para a operação solicitada
(CRUD em
/orders/statuses). Confirme também que o pedido é sobre o CATÁLOGO de status, e não sobre mudar o status de um pedido individual (esse caso étray-pedidos,PUT /orders/:id). - Identifique os campos obrigatórios listados neste documento —
namenunca pode faltar na criação; não omita nenhum. - Verifique que
access_tokennão aparece como literal string no código gerado — use sempreTRAY_ACCESS_TOKENeTRAY_API_ADDRESSpor variável de ambiente, passado como query param. - Confirme que esta é a skill correta para o recurso (leia
when_not_to_useno frontmatter); status padrão da plataforma não podem ser editados nem excluídos.
API de Status de Pedido — Tray
Documentação oficial: https://developers.tray.com.br/#api-de-status-do-pedido
Atenção (disambiguation): este recurso gerencia o catálogo de tipos de status da loja (
/orders/statuses), com wrapperOrderStatus. Para mudar o status atribuído a um pedido específico, usetray-pedidos(PUT /orders/:id, campostatus_id) — não há endpoint aqui para isso. Confundir os dois é a causa #1 de chamada ao endpoint errado neste recurso.
Visão geral
Um status de pedido neste recurso é uma entrada do catálogo de status da
loja: um tipo/configuração reutilizável (nome, descrição, cores e tipo de
fluxo) que pode ser atribuído a pedidos. A API expõe cinco endpoints de CRUD
(GET /orders/statuses, GET /orders/statuses/:id, POST /orders/statuses,
PUT /orders/statuses/:id, DELETE /orders/statuses/:id) e permite ao
desenvolvedor montar um pipeline próprio (ex.: Aguardando Pagamento → Pago →
Em Separação → Despachado → Entregue), definindo name, description,
background_color, font_color e type. A Tray pré-configura status padrão
imutáveis; a personalização é feita criando novos status, nunca editando ou
excluindo os padrão.
O recurso se conecta diretamente a tray-pedidos: cada pedido carrega um campo
status_id que aponta para o id de um status deste catálogo, e é em
PUT /orders/:id (não aqui) que se muda o status de um pedido individual. O
fluxo típico é descobrir os IDs via GET /orders/statuses, criar status
personalizados quando necessário e então atribuí-los aos pedidos via
tray-pedidos. A mudança de status de um pedido dispara o webhook de escopo
order (ação update, ver tray-webhooks) — não existe webhook próprio
para o catálogo de status: criar/editar/excluir um tipo de status não gera
notificação. Os IDs e o type deste catálogo também alimentam relatórios e
filtros de listagem de pedidos.
Invariantes da plataforma que valem para toda chamada deste recurso:
(1) o access_token é passado sempre como query parameter
(?access_token={token}), nunca em header Authorization — token em header
retorna HTTP 401; (2) a URL base é https://{api_address}/, e o
api_address varia por loja (retornado no callback OAuth) — usar o
endereço errado retorna HTTP 404; (3) todo body de POST/PUT deve estar
envolto na chave de recurso OrderStatus — esquecer o wrapper é a causa #1 de
HTTP 400; (4) listagens paginam com limit (padrão 30, máximo 50) e
page, lendo paging.total para iterar; (5) datas usam YYYY-MM-DD e
timestamps YYYY-MM-DD HH:MM:SS (horário de Brasília); (6) o rate limit é 180
req/min e 10.000 req/dia — HTTP 429 exige backoff exponencial (1s, 2s, 4s,
8s). Como o recurso ainda não tem validate.mjs, valide manualmente name
(obrigatório), type (open/closed/cancelled) e as cores em hexadecimal
#RRGGBB antes de enviar.
GET /orders/statuses
Quando usar: para descobrir os IDs e os tipos (
open/closed/cancelled) dos status já existentes na loja antes de criar um status novo, vincular um status a um pedido (viatray-pedidosPUT /orders/:id) ou auditar o pipeline de pedido da loja. É o ponto de partida para qualquer operação neste recurso — oidretornado aqui alimenta as chamadasGET/PUT/DELETE /orders/statuses/:id.Pré-requisitos:
access_tokenválido como query param (?access_token={token}).TRAY_API_ADDRESSda loja (varia por loja, retornado no callback OAuth).
Schema do request: sem body — apenas query params de paginação:
limit(padrão 30, máximo 50) epage; leiapaging.totalpara iterar.Schema da response: resposta JSON padrão da API Tray (ver exemplo abaixo).
Paginação:
limit(padrão 30, máximo 50),page.Campos da resposta:
Campo Tipo Descrição paging.totalinteger Total de status disponíveis paging.pageinteger Página atual paging.limitinteger Itens por página solicitados paging.maxLimitinteger Teto de itens por página (50) OrderStatuses[].OrderStatus.idstring ID do status (read-only) OrderStatuses[].OrderStatus.namestring Nome do status exibido no painel/acompanhamento OrderStatuses[].OrderStatus.descriptionstring Descrição detalhada do status OrderStatuses[].OrderStatus.background_colorstring Cor de fundo ( #RRGGBB)OrderStatuses[].OrderStatus.font_colorstring Cor da fonte ( #RRGGBB)OrderStatuses[].OrderStatus.typestring open/closed/cancelledExemplo (curl):
# NÃO-VERIFICADO contra sandbox — validar antes do merge. curl -X GET \ "https://${TRAY_API_ADDRESS}/orders/statuses?access_token=${TRAY_ACCESS_TOKEN}&limit=30&page=1"Exemplo (Node):
// NÃO-VERIFICADO contra sandbox — validar antes do merge. const res = await fetch( `https://${process.env.TRAY_API_ADDRESS}/orders/statuses` + `?access_token=${process.env.TRAY_ACCESS_TOKEN}&limit=30&page=1`, ); if (res.status === 429) { /* backoff exponencial: 1s, 2s, 4s, 8s */ } const data = await res.json(); // data.paging.total para paginar; data.OrderStatuses[].OrderStatusErros comuns:
Código Causa Como resolver 401 access_tokenexpirado (3h) ou enviado como headerAuthorizationem vez de query paramRenovar via GET /auth?refresh_token={token}; sempre passar?access_token={token}na query string404 api_addressincorreto (varia por loja)Usar o api_addressretornado no callback OAuth da loja429 Rate limit (180 req/min ou 10k/dia) Backoff exponencial (1s, 2s, 4s, 8s)
GET /orders/statuses/:id
Quando usar: para obter a configuração completa (nome, descrição, cores, tipo) de um único status antes de editá-lo ou para diagnosticar como ele aparece no painel/acompanhamento do pedido.
Pré-requisitos:
access_tokenválido.iddo status (obtido viaGET /orders/statuses).
Schema do request: sem body — apenas parâmetro de path
:id.Schema da response: resposta JSON padrão da API Tray (ver exemplo abaixo).
Campos da resposta:
Campo Tipo Descrição OrderStatus.idstring ID do status OrderStatus.namestring Nome do status OrderStatus.descriptionstring Descrição detalhada OrderStatus.background_colorstring Cor de fundo ( #RRGGBB)OrderStatus.font_colorstring Cor da fonte ( #RRGGBB)OrderStatus.typestring open/closed/cancelledExemplo (curl):
# NÃO-VERIFICADO contra sandbox — validar antes do merge. curl -X GET \ "https://${TRAY_API_ADDRESS}/orders/statuses/15?access_token=${TRAY_ACCESS_TOKEN}"Exemplo (Node):
// NÃO-VERIFICADO contra sandbox — validar antes do merge. const statusId = 15; const res = await fetch( `https://${process.env.TRAY_API_ADDRESS}/orders/statuses/${statusId}` + `?access_token=${process.env.TRAY_ACCESS_TOKEN}`, ); if (res.status === 404) { /* id inexistente ou api_address errado */ } const data = await res.json(); // data.OrderStatusErros comuns:
Código Causa Como resolver 401 Token expirado ou enviado em header Renovar token; usar query param 404 ID de status inexistente ou api_addresserradoConfirmar o idviaGET /orders/statusese oapi_addressda loja429 Rate limit (180 req/min ou 10k/dia) Backoff exponencial (1s, 2s, 4s, 8s)
POST /orders/statuses
Quando usar: ao montar um pipeline de pedido próprio da loja (ex.: "Em Separação", "Aguardando Retirada", "Despachado"), definindo nome, descrição, cores hexadecimais e o
typeque classifica o comportamento no fluxo do pedido.Pré-requisitos:
access_tokenválido.namedefinido (campo obrigatório).- body envolto na chave de recurso
OrderStatus. typecoerente com o comportamento desejado (open/closed/cancelled).
Schema do request:
schemas/order_status.update.jsonSchema da response: resposta JSON padrão da API Tray (ver exemplo abaixo).
Content-Type:
application/jsoncom a chave de recurso"OrderStatus".Campos:
Campo Tipo Obrigatório Descrição namestring Sim Nome do status, exibido no painel e no acompanhamento do pedido pelo cliente (ex.: "Em Separação") descriptionstring Não Descrição detalhada do significado do status background_colorstring Não Cor de fundo no painel — hexadecimal completo #RRGGBB(ex.:#3498DB)font_colorstring Não Cor da fonte no painel — hexadecimal #RRGGBB; deve contrastar combackground_colortypestring Não Comportamento no fluxo: open(em andamento) /closed(finalizado) /cancelled(cancelado)Exemplo (curl):
# NÃO-VERIFICADO contra sandbox — validar antes do merge. curl -X POST \ "https://${TRAY_API_ADDRESS}/orders/statuses?access_token=${TRAY_ACCESS_TOKEN}" \ -H 'Content-Type: application/json' \ -d '{ "OrderStatus": { "name": "Em Separação", "description": "Pedido sendo preparado para envio", "background_color": "#3498DB", "font_color": "#FFFFFF", "type": "open" } }'Exemplo (Node):
// NÃO-VERIFICADO contra sandbox — validar antes do merge. const body = { OrderStatus: { name: 'Em Separação', description: 'Pedido sendo preparado para envio', background_color: '#3498DB', font_color: '#FFFFFF', type: 'open', }, }; const res = await fetch( `https://${process.env.TRAY_API_ADDRESS}/orders/statuses` + `?access_token=${process.env.TRAY_ACCESS_TOKEN}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }, ); if (res.status === 429) { /* backoff exponencial */ } const data = await res.json(); // { "message": "Created", "id": 15, "code": 201 }Resposta de sucesso:
{ "message": "Created", "id": 15, "code": 201 }Erros comuns:
Código Causa Como resolver 400 Faltou a chave de recurso OrderStatus,nameausente, outypecom valor inválido (fora deopen/closed/cancelled)Envolver os dados na chave OrderStatus; incluirname; usartypeválido; revisar campos contra a doc desearch_docs.mjs(semvalidate.mjslocal)401 Token expirado ou enviado em header Renovar token; usar query param 429 Rate limit (180 req/min ou 10k/dia) Backoff exponencial (1s, 2s, 4s, 8s)
PUT /orders/statuses/:id
Quando usar: para ajustar nome, descrição, cores ou
typede um status personalizado já criado. Os status padrão da plataforma não podem ser editados — tentar editá-los retorna erro; nesse caso, crie um status personalizado novo.Pré-requisitos:
access_tokenválido.idde um status personalizado (não padrão da plataforma).- body envolto na chave
OrderStatus.
Schema do request:
schemas/order_status.update.jsonSchema da response: resposta JSON padrão da API Tray (ver exemplo abaixo).
Content-Type:
application/jsoncom a chave de recurso"OrderStatus".Campos: (todos opcionais no update — envie apenas os que mudam)
Campo Tipo Obrigatório Descrição namestring Não Nome do status descriptionstring Não Descrição detalhada background_colorstring Não Cor de fundo #RRGGBBfont_colorstring Não Cor da fonte #RRGGBBtypestring Não open/closed/cancelledExemplo (curl):
# NÃO-VERIFICADO contra sandbox — validar antes do merge. curl -X PUT \ "https://${TRAY_API_ADDRESS}/orders/statuses/15?access_token=${TRAY_ACCESS_TOKEN}" \ -H 'Content-Type: application/json' \ -d '{ "OrderStatus": { "description": "Pedido em separação no centro de distribuição", "background_color": "#2980B9" } }'Exemplo (Node):
// NÃO-VERIFICADO contra sandbox — validar antes do merge. const statusId = 15; const body = { OrderStatus: { description: 'Pedido em separação no centro de distribuição', background_color: '#2980B9', }, }; const res = await fetch( `https://${process.env.TRAY_API_ADDRESS}/orders/statuses/${statusId}` + `?access_token=${process.env.TRAY_ACCESS_TOKEN}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }, ); if (res.status === 429) { /* backoff exponencial */ } const data = await res.json(); // { "message": "Saved", "id": 15, "code": 200 }Resposta de sucesso:
{ "message": "Saved", "id": 15, "code": 200 }Erros comuns:
Código Causa Como resolver 400 Falta da chave OrderStatusoutypeinválido; tentativa de editar status padrão da plataformaEnvolver na chave OrderStatus; usartypeválido; confirmar que o status não é padrão da plataforma401 Token expirado ou enviado em header Renovar token; usar query param 404 ID inexistente Confirmar idviaGET /orders/statuses429 Rate limit (180 req/min ou 10k/dia) Backoff exponencial (1s, 2s, 4s, 8s)
DELETE /orders/statuses/:id
Quando usar: ao remover definitivamente um status personalizado que não está mais em uso. Verifique antes se há pedidos vinculados ao status e os migre para outro status (via
tray-pedidosPUT /orders/:id); status padrão da plataforma não podem ser excluídos.Pré-requisitos:
access_tokenválido.iddo status personalizado.- garantir que nenhum pedido esteja vinculado ao status.
Schema do request: sem body — apenas parâmetro de path
:id.Schema da response: resposta JSON padrão da API Tray (ver exemplo abaixo).
Campos:
Campo Tipo Obrigatório Descrição idstring Sim ID do status a excluir (passado na URL) Exemplo (curl):
# NÃO-VERIFICADO contra sandbox — validar antes do merge. curl -X DELETE \ "https://${TRAY_API_ADDRESS}/orders/statuses/15?access_token=${TRAY_ACCESS_TOKEN}"Exemplo (Node):
// NÃO-VERIFICADO contra sandbox — validar antes do merge. const statusId = 15; const res = await fetch( `https://${process.env.TRAY_API_ADDRESS}/orders/statuses/${statusId}` + `?access_token=${process.env.TRAY_ACCESS_TOKEN}`, { method: 'DELETE' }, ); if (res.status === 404) { /* id inexistente ou já excluído */ } const data = await res.json(); // { "message": "Deleted", "id": 15, "code": 200 }Resposta de sucesso:
{ "message": "Deleted", "id": 15, "code": 200 }Erros comuns:
Código Causa Como resolver 400 Status em uso por pedidos existentes ou status padrão da plataforma (não excluível) Migrar os pedidos vinculados para outro status antes (via tray-pedidosPUT /orders/:id); não tentar excluir status padrão401 Token expirado ou enviado em header Renovar token; usar query param 404 ID inexistente ou já excluído Confirmar idviaGET /orders/statuses429 Rate limit (180 req/min ou 10k/dia) Backoff exponencial (1s, 2s, 4s, 8s)
Edge cases
Cenários atípicos no gerenciamento do catálogo de status de pedido (
/orders/statuses). Todos os exemplos são NÃO-VERIFICADOS contra sandbox — validar antes do merge.
Status padrão da plataforma são imutáveis. A Tray pré-configura status default (ex.: Aguardando Pagamento, Pago, Cancelado) que não podem ser editados via PUT /orders/statuses/:id nem excluídos via DELETE /orders/statuses/:id. Tentar alterar ou remover um status padrão retorna erro (HTTP 400/403). O fluxo correto é criar um status personalizado novo que reflita o ponto desejado do pipeline, nunca tentar sobrescrever o padrão.
# NÃO-VERIFICADO contra sandbox — validar antes do merge.
# ERRADO: tentar editar um status padrão da plataforma (ex.: id 1 = "Aguardando Pagamento")
curl -X PUT "https://${TRAY_API_ADDRESS}/orders/statuses/1?access_token=${TRAY_ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"OrderStatus":{"name":"Aguardando PIX"}}'
# → provável HTTP 400/403: status padrão não é editável
# CERTO: criar um status personalizado novo
curl -X POST "https://${TRAY_API_ADDRESS}/orders/statuses?access_token=${TRAY_ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"OrderStatus":{"name":"Aguardando PIX","type":"open","background_color":"#2980B9","font_color":"#FFFFFF"}}'
Excluir um status que ainda tem pedidos vinculados. Se houver pedidos apontando para o status (campo status_id em tray-pedidos), o DELETE /orders/statuses/:id pode ser bloqueado (HTTP 400) ou deixar pedidos órfãos sem status válido. Antes de remover, liste os pedidos nesse status e migre-os para outro status via PUT /orders/:id (recurso tray-pedidos), e só então execute o DELETE.
# NÃO-VERIFICADO contra sandbox — validar antes do merge.
# 1. Migrar os pedidos vinculados ao status 47 para o status 12 (recurso tray-pedidos)
curl -X PUT "https://${TRAY_API_ADDRESS}/orders/1001?access_token=${TRAY_ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"Order":{"status_id":12}}'
# 2. Só depois excluir o status agora sem vínculos
curl -X DELETE "https://${TRAY_API_ADDRESS}/orders/statuses/47?access_token=${TRAY_ACCESS_TOKEN}"
# → 200 {"message":"Deleted","id":47}
Confusão entre catálogo de status e status de um pedido específico. Este recurso (/orders/statuses) gerencia os tipos de status disponíveis na loja (o catálogo: nome, cor, tipo). Ele não muda o status de um pedido individual. Para alterar o status de um pedido específico, use PUT /orders/:id com status_id no recurso tray-pedidos. Chamar /orders/statuses esperando mover um pedido leva ao endpoint errado.
# NÃO-VERIFICADO contra sandbox — validar antes do merge.
# ERRADO: este endpoint NÃO move o pedido 1001 para "Enviado"
curl -X POST "https://${TRAY_API_ADDRESS}/orders/statuses?access_token=${TRAY_ACCESS_TOKEN}" \
-d '{"OrderStatus":{"name":"Enviado"}}' # cria um TIPO de status, não muda pedido algum
# CERTO: mudar o status do pedido específico (recurso tray-pedidos)
curl -X PUT "https://${TRAY_API_ADDRESS}/orders/1001?access_token=${TRAY_ACCESS_TOKEN}" \
-d '{"Order":{"status_id":8}}' # 8 = id do status "Enviado" obtido em GET /orders/statuses
Cores sem contraste tornam o status ilegível no painel. Definir background_color e font_color iguais ou próximas (ex.: ambas claras) faz o texto do status sumir no painel administrativo. Sempre garanta contraste adequado — fundo escuro com fonte clara, ou vice-versa.
# NÃO-VERIFICADO contra sandbox — validar antes do merge.
# ERRADO: fundo claro + fonte clara = ilegível
# {"OrderStatus":{"name":"Em Separação","background_color":"#F5F5F5","font_color":"#FFFFFF"}}
# CERTO: contraste adequado (fundo escuro, fonte branca)
curl -X POST "https://${TRAY_API_ADDRESS}/orders/statuses?access_token=${TRAY_ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"OrderStatus":{"name":"Em Separação","type":"open","background_color":"#2980B9","font_color":"#FFFFFF"}}'
Cor sem # ou em notação curta de 3 dígitos. Enviar a cor sem o prefixo # (ex.: 2980B9) ou em formato abreviado de 3 dígitos (ex.: #39C) pode não ser interpretado corretamente pela plataforma e gerar exibição inesperada ou rejeição do campo. Use sempre o hexadecimal completo de 6 dígitos com # (#RRGGBB).
# NÃO-VERIFICADO contra sandbox — validar antes do merge.
# ERRADO: sem # e em notação curta
# {"OrderStatus":{"name":"Despachado","background_color":"2980B9","font_color":"#FFF"}}
# CERTO: formato hexadecimal completo de 6 dígitos com #
curl -X POST "https://${TRAY_API_ADDRESS}/orders/statuses?access_token=${TRAY_ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"OrderStatus":{"name":"Despachado","type":"open","background_color":"#2980B9","font_color":"#FFFFFF"}}'
type omitido na criação assume comportamento default. O campo type é opcional, mas omiti-lo faz o status assumir um comportamento padrão que pode não refletir o ponto pretendido do fluxo (aberto vs. finalizado vs. cancelado). Um status que deveria encerrar o pedido (closed) mas é criado sem type pode continuar tratando o pedido como em andamento. Defina type explicitamente para garantir o comportamento correto no ciclo de vida do pedido.
# NÃO-VERIFICADO contra sandbox — validar antes do merge.
# RISCO: sem type — comportamento default pode não ser o esperado
# {"OrderStatus":{"name":"Entregue"}}
# CERTO: type explícito para um status que finaliza o pedido
curl -X POST "https://${TRAY_API_ADDRESS}/orders/statuses?access_token=${TRAY_ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"OrderStatus":{"name":"Entregue","type":"closed","background_color":"#27AE60","font_color":"#FFFFFF"}}'
Mudança de status do pedido dispara webhook; mudança no catálogo não. Ao alterar o status_id de um pedido (via PUT /orders/:id em tray-pedidos), o webhook de escopo order (ação update) é disparado automaticamente. Já criar, editar ou excluir um tipo de status neste catálogo (/orders/statuses) não dispara nenhuma notificação — não existe escopo de webhook próprio para o catálogo de status. Não espere notificação ao gerenciar o catálogo; integre via chamada direta. Consulte tray-webhooks.
Antipadrões
❌ Passar o
access_tokenem headerAuthorization. A API Tray ignoraAuthorization: Bearer ...e responde HTTP 401 em todas as rotas de status. Por que quebra: a Tray não lê o token de header — apenas da query string. Correção: envie sempre como query param em toda chamada de status (GET/POST/PUT/DELETE):https://{api_address}/orders/statuses?access_token={token}. Nunca hardcode o token; useTRAY_ACCESS_TOKENvia env.❌ Esquecer a chave de recurso
OrderStatusno body de POST/PUT. Enviar os campos no nível raiz —{"name":"Enviado","type":"open"}— em vez de{"OrderStatus":{"name":"Enviado","type":"open"}}causa HTTP 400. Por que quebra: é a causa #1 de erro de validação na plataforma; a API espera o payload envolto no wrapper PascalCase do recurso. Correção: sempre envolva os dados em{"OrderStatus": { ... }}, tanto na criação quanto na atualização.❌ Usar
/orders/statusespara mudar o status de um pedido específico. Este endpoint gerencia o catálogo de tipos de status da loja, não o status atribuído a um pedido individual. Por que quebra: criar/editar um tipo de status aqui não move pedido algum; o pedido continua no status anterior e a operação pretendida silenciosamente não acontece. Correção: para mudar o status de um pedido, usePUT /orders/:idcom{"Order":{"status_id":<id>}}no recursotray-pedidos, usando umidobtido emGET /orders/statuses.❌ Tentar editar ou excluir um status padrão da plataforma. Os status default da Tray são imutáveis;
PUT/DELETEneles falha (HTTP 400/403). Por que quebra: a plataforma protege os status base do ciclo de vida do pedido contra alteração. Correção: nunca tente sobrescrever um status padrão — crie um status personalizado novo comPOST /orders/statusespara representar o ponto desejado do pipeline.❌ Excluir um status sem migrar os pedidos vinculados. Remover um status ainda referenciado por pedidos (via
status_id) deixa pedidos sem status válido ou bloqueia oDELETE(HTTP 400). Por que quebra: a integridade do pipeline depende de todo pedido apontar para um status existente. Correção: primeiro liste e reatribua os pedidos a outro status comPUT /orders/:id(recursotray-pedidos), confirme que não há mais vínculos, e só então execute oDELETE /orders/statuses/:id.❌ Enviar
typefora do enum (open|closed|cancelled). Valores comotype:"shipped","entregue"ou"pago"são inválidos e causam HTTP 400. Por que quebra:typeé apenas a classificação de comportamento do status no fluxo (em andamento / finalizado / cancelado), não o texto visível. Correção: use somenteopen,closedoucancelledemtype; coloque o rótulo legível (ex.: "Despachado", "Entregue") emname/description.❌ Esperar webhook ao gerenciar o catálogo de status. Criar/editar/excluir um tipo de status em
/orders/statusesnão dispara notificação alguma. Por que quebra: não existe escopo de webhook próprio para o catálogo de status; o escopoordersó dispara quando um pedido muda (inclusive ao trocar destatus_id). Correção: não dependa de webhook para mudanças no catálogo — sincronize via chamada direta aGET /orders/statuses. Para reagir a mudanças de status de pedidos, assine o escopoorder(açãoupdate) — vertray-webhooks.
State machine
O recurso tray-status-pedido gerencia o catálogo de tipos de status da loja (nome, cor, type). O ciclo de vida real é percorrido por cada pedido individual (campo status_id em tray-pedidos), que aponta para um item deste catálogo. O type de cada status classifica seu comportamento no fluxo: open (em andamento), closed (finalizado) ou cancelled (cancelado).
Importante: a transição de estado acontece no pedido, não no catálogo. Mudar o
status_idde um pedido é feito viaPUT /orders/:id(skilltray-pedidos) e dispara o webhook de escopoorder(açãoupdate). Criar, editar ou excluir um tipo de status (/orders/statuses) não dispara webhook algum.
Ciclo de vida do pedido (agrupado por type)
stateDiagram-v2
[*] --> AguardandoPagamento : criação do pedido (escopo order / insert)
state "type = open" as Open {
AguardandoPagamento --> Pago : pagamento aprovado
Pago --> EmSeparacao : início do fulfillment
EmSeparacao --> Enviado : despacho + tracking_number
Enviado --> Entregue : confirmação de entrega
}
state "type = closed" as Closed {
Entregue
}
state "type = cancelled" as Cancelled {
Cancelado
}
AguardandoPagamento --> Cancelado : cancelamento (PUT /orders/:id/cancel)
Pago --> Cancelado : pagamento estornado / cancelamento
EmSeparacao --> Cancelado : ruptura de estoque / cancelamento
Enviado --> Cancelado : devolução / extravio
Entregue --> [*]
Cancelado --> [*]
Os estados acima são exemplos típicos de um pipeline de loja Tray. Os nomes dos status (name) são livres e configuráveis por loja; o que a plataforma classifica de fato é o type (open / closed / cancelled). Use GET /orders/statuses para descobrir os id e type reais antes de mapear transições.
Transições
Toda transição de estado ocorre sobre o pedido (PUT /orders/:id alterando status_id, ou PUT /orders/:id/cancel). A coluna "Webhook" indica a notificação disparada — sempre escopo order, ação update, nunca um webhook do catálogo de status.
| De | Para | Gatilho | Webhook |
|---|---|---|---|
| (inexistente) | Aguardando Pagamento (open) |
Criação do pedido (POST /orders) |
order / insert |
Aguardando Pagamento (open) |
Pago (open) |
Pagamento aprovado pelo gateway; PUT /orders/:id muda status_id |
order / update |
Pago (open) |
Em Separação (open) |
Início do fulfillment; PUT /orders/:id |
order / update |
Em Separação (open) |
Enviado (open) |
Despacho com tracking_number; PUT /orders/:id |
order / update |
Enviado (open) |
Entregue (closed) |
Confirmação de entrega; PUT /orders/:id |
order / update |
Aguardando Pagamento (open) |
Cancelado (cancelled) |
Pagamento não realizado / PUT /orders/:id/cancel |
order / update |
Pago (open) |
Cancelado (cancelled) |
Estorno / PUT /orders/:id/cancel |
order / update |
Em Separação (open) |
Cancelado (cancelled) |
Ruptura de estoque / PUT /orders/:id/cancel |
order / update |
Enviado (open) |
Cancelado (cancelled) |
Devolução ou extravio / PUT /orders/:id/cancel |
order / update |
Estados terminais: status de
type = closed(ex.: Entregue) etype = cancelled(ex.: Cancelado) encerram o ciclo de vida — não há transição de saída esperada a partir deles no fluxo padrão.
Notas sobre o catálogo de status (não há máquina de estados própria)
- Criar/editar/excluir um tipo de status (
POST/PUT/DELETEem/orders/statuses) é uma operação de configuração; não participa do ciclo de vida de nenhum pedido e não emite webhook. - Status padrão da plataforma são imutáveis: não podem ser editados (
PUT) nem excluídos (DELETE). Para personalizar o pipeline, crie um status novo comtypecoerente — não tente sobrescrever o padrão. - Antes de excluir um status do catálogo, migre os pedidos vinculados para outro status (via
PUT /orders/:id); excluir um status em uso pode ser bloqueado ou deixar pedidos órfãos. - O
typedefine em qual grupo da máquina de estados o status se encaixa — defina-o explicitamente na criação para evitar comportamento default que não reflita o ponto pretendido do fluxo.
Webhooks relacionados
Cross-link:
../webhooks/SKILL.md
Este recurso (/orders/statuses) gerencia o catálogo de tipos de status da loja, que não dispara webhook próprio. Criar, editar ou excluir um tipo de status não gera notificação.
O que dispara webhook é a mudança de status de um pedido individual, feita em tray-pedidos via PUT /orders/:id (campo status_id):
| Escopo | Ação | Quando dispara | Relação com este recurso |
|---|---|---|---|
order |
update |
Quando o status_id de um pedido muda para um id deste catálogo |
A mudança aponta para um id criado/listado aqui (GET /orders/statuses) |
order |
insert |
Quando um pedido é criado já com um status_id |
O status inicial referencia um id deste catálogo |
Não existe escopo de webhook para o catálogo de status. Não há
order_statuscomo escopo. Por padrão a Tray libera apenas o escopoorder; outros escopos exigem ticket de suporte informando a URL de notificação. Veja../webhooks/SKILL.mdpara o fluxo de ativação, formatox-www-form-urlencodede lógica de retry.
Fluxo típico de integração:
- Crie/liste os tipos de status aqui (
/orders/statuses) para obter osid. - Atribua um
status_ida um pedido viatray-pedidos(PUT /orders/:id). - Receba a notificação no escopo
order(açãoupdate) no seu endpoint receptor. - Consulte
GET /orders/:id/fullpara obter os dados completos e atualizados do pedido.
Glossário
| Termo | Definição |
|---|---|
OrderStatus |
Chave de recurso (wrapper) usada no body de POST/PUT e na resposta da API. Todo payload deve estar envolto em {"OrderStatus": {...}}; na listagem cada item vem como OrderStatuses[].OrderStatus. |
| status de pedido (catálogo) | Tipo/configuração de status disponível na loja (nome, cor, tipo). Gerenciado por /orders/statuses. Distinto do status atribuído a um pedido individual (campo status_id em tray-pedidos). |
type |
Classificação de comportamento do status no fluxo do pedido: open (em andamento), closed (finalizado/concluído) ou cancelled (cancelado). Impacta como a plataforma trata o pedido. |
| status padrão da plataforma | Status pré-configurados pela Tray que não podem ser editados nem excluídos. Personalizações são feitas criando novos status, não modificando os padrão. |
background_color / font_color |
Cores hexadecimais (#RRGGBB) de fundo e fonte do status para exibição no painel administrativo; devem contrastar entre si para legibilidade. |
status_id (no pedido) |
Campo do recurso pedido (tray-pedidos) que aponta para o id de um status deste catálogo. A mudança desse campo em PUT /orders/:id dispara o webhook de escopo order. |
escopo order (webhook) |
Escopo de webhook (ações insert/update) disparado quando um pedido muda — inclusive ao mudar de status. Não há webhook próprio para alterações no catálogo de status. Ver ../webhooks/SKILL.md. |
Referências
- Documentação oficial: API de Status de Pedido — Tray (seção de status de pedido)
- Regras invariantes da plataforma:
../visao-geral/SKILL.md— autenticação OAuth, URL base por loja, wrapper de recurso, rate limit, paginação - Mudança de status de um pedido individual:
../pedidos/SKILL.md—PUT /orders/:id(campostatus_id),GET /orders/:id/full - Notificações de mudança de status:
../webhooks/SKILL.md— escopoorder, ativação via ticket, formato do payload - Autenticação e renovação de token:
../autorizacao/SKILL.md— fluxo OAuth,refresh_token, códigos de erro 1000–1099 - Schemas locais deste recurso:
schemas/order_status.update.json - Issue de aprofundamento: ai/tasks#100 (P2.1, Fase 2)
Exemplos de resposta JSON por endpoint
Exemplos realistas dos corpos JSON retornados pelos endpoints de
/orders/statuses. Todos os valores são ilustrativos — NÃO-VERIFICADOS contra sandbox — validar antes do merge. Use-os para mapear os campos da resposta, nunca como contrato fixo. A chave de recurso é sempreOrderStatus; na listagem cada item vem envolto emOrderStatuses[].OrderStatus.
GET /orders/statuses — listagem com paging. Note paging.total (use para iterar), paging.maxLimit fixo em 50, e o array OrderStatuses em que cada elemento é um objeto { "OrderStatus": {...} }. Os primeiros itens costumam ser status padrão da plataforma (imutáveis); os de id maior tendem a ser personalizados da loja.
{
"paging": {
"total": 8,
"page": 1,
"offset": 0,
"limit": 30,
"maxLimit": 50
},
"OrderStatuses": [
{
"OrderStatus": {
"id": "1",
"name": "Aguardando Pagamento",
"description": "Pedido criado, aguardando confirmação do pagamento",
"background_color": "#F39C12",
"font_color": "#FFFFFF",
"type": "open"
}
},
{
"OrderStatus": {
"id": "2",
"name": "Pago",
"description": "Pagamento aprovado pelo gateway",
"background_color": "#27AE60",
"font_color": "#FFFFFF",
"type": "open"
}
},
{
"OrderStatus": {
"id": "15",
"name": "Em Separação",
"description": "Pedido sendo preparado para envio",
"background_color": "#3498DB",
"font_color": "#FFFFFF",
"type": "open"
}
},
{
"OrderStatus": {
"id": "8",
"name": "Entregue",
"description": "Entrega confirmada ao cliente",
"background_color": "#16A085",
"font_color": "#FFFFFF",
"type": "closed"
}
},
{
"OrderStatus": {
"id": "99",
"name": "Cancelado",
"description": "Pedido cancelado",
"background_color": "#C0392B",
"font_color": "#FFFFFF",
"type": "cancelled"
}
}
]
}
GET /orders/statuses/:id — status individual. Retorna um único objeto OrderStatus (sem paging, sem array). Todos os campos vêm como string, inclusive id.
{
"OrderStatus": {
"id": "15",
"name": "Em Separação",
"description": "Pedido sendo preparado para envio no centro de distribuição",
"background_color": "#3498DB",
"font_color": "#FFFFFF",
"type": "open"
}
}
Resposta de atualização do status de um pedido (recurso tray-pedidos). A mudança de status de um pedido não acontece neste recurso — é feita em PUT /orders/:id com status_id. O corpo de sucesso segue o padrão message/id/code da plataforma; o id retornado é o do pedido, não o do status. Incluído aqui para fechar o ciclo de sincronização.
{
"message": "Saved",
"id": 1001,
"code": 200
}
Se o status_id enviado não existir no catálogo, a API responde HTTP 400 com mensagem de validação:
{
"message": "Validation error",
"code": 400,
"causes": ["status_id inexistente no catálogo da loja"]
}
Sincronização de status com sistema externo
Cenário completo: espelhar o estado dos pedidos da Tray em um sistema externo (ERP/OMS) e refletir mudanças de status de volta na Tray. O código combina três recursos: este catálogo (
/orders/statuses, para resolverid → type),tray-pedidos(GET /orderspara listar,PUT /orders/:idpara gravar) e o backoff deHTTP 429. NÃO-VERIFICADO contra sandbox — validar antes do merge. Tokens sempre via env,access_tokensempre query param.
// NÃO-VERIFICADO contra sandbox — validar antes do merge.
// Sincroniza pedidos de um dado status para o sistema externo e grava transições.
const BASE = process.env.TRAY_API_ADDRESS; // varia por loja (callback OAuth)
const TOKEN = process.env.TRAY_ACCESS_TOKEN; // nunca hardcoded; query param
const q = (path, extra = "") =>
`https://${BASE}/${path}?access_token=${encod
…(truncated)