Cancelamento e contestação
O cliente do app consulta as regras, pede o cancelamento de um pedido, contesta um pedido recebido com fotos e acompanha a decisão.
Dois pedidos diferentes passam por esta rota, e a loja decide cada um depois:
- Cancelamento: o cliente se arrependeu antes de o pedido ser entregue. A loja analisa e, se aceitar, cancela o pedido.
- Contestação (
request_typeigual arefund): o pedido foi entregue, mas há um problema (defeito, produto diferente, não chegou). O cliente descreve o motivo, anexa até 5 fotos e a loja decide aprovar (estornando total ou parcialmente) ou recusar.
Nos dois casos o pedido passa para a situação de solicitação pendente (letra M) até a decisão. Nada é reembolsado nem movimentado nesta chamada: ela só registra o pedido do cliente. Todas as rotas exigem a ekey do cliente, e o pedido precisa ser dele; pedido de outra pessoa responde 404.
As mensagens de erro desta rota voltam em português, como no servidor.
/api/4.0/CustomerCancelApiClienteRegras de cancelamento e contestação
Devolve o que o app pode mostrar: em quais situações do pedido há o botão Cancelar e o Contestar, os motivos disponíveis e o prazo. É a lista que a loja configurou, e o servidor aplica as mesmas regras no POST.
Parâmetros de consulta
user_idstring/api/4.0/CustomerCancelApiClientePedir cancelamento ou contestar um pedido
Registra o pedido. O corpo tem no máximo 40 MiB (para caber as fotos em Base64).
Corpo da requisição
request_typestringobrigatóriocancellationrefundcancellation pede o cancelamento. refund abre uma contestação. Outro valor responde 400.order_idstringobrigatório?order_id=). Sub-pedidos (números com -V) não podem ser cancelados por aqui: use o pedido principal.user_idstringadditional_detailsstringreason_idintegerrefund_reasons das regras.photosarray{"data": "<imagem em Base64>"} (também aceita data:image/png;base64,...). Cada foto tem no máximo 5 MB e precisa ser uma imagem de verdade. Caminho de arquivo e URL são recusados./api/4.0/CustomerCancelApi/{orderId}ClienteSituação da contestação de um pedido
Mostra se o pedido pode ser contestado e a última contestação, com a decisão da loja. O dono do pedido recebe 200 mesmo que nunca tenha contestado.
Parâmetros de caminho
orderIdstringobrigatório/api/4.0/CustomerCancelApi/photos/{token}PúblicaFoto de uma contestação
Entrega os bytes de uma foto da contestação. Não usa ekey: o endereço já vem assinado nos campos photos[].url e vale por 24 horas. Link adulterado ou vencido responde 404.
Parâmetros de caminho
tokenstringobrigatóriophotos[].url.Exemplo de requisição
Contestar um pedido entregue, com uma foto:
curl -X POST "$BASE_URL/api/4.0/CustomerCancelApi" \
-H "Authorization: Basic $(printf '%s' "$CUSTOMER_TOKEN" | base64 -w0):" \
-H "Content-Type: application/json" \
-d '{
"request_type": "refund",
"order_id": "1987349551",
"reason_id": 1,
"additional_details": "A tela chegou trincada.",
"photos": [
{
"data": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ..."
}
]
}'Pedir o cancelamento:
curl -X POST "$BASE_URL/api/4.0/CustomerCancelApi" \
-H "Authorization: Basic $(printf '%s' "$CUSTOMER_TOKEN" | base64 -w0):" \
-H "Content-Type: application/json" \
-d '{
"request_type": "cancellation",
"order_id": "1987349551",
"additional_details": "Desisti da compra."
}'Resposta
{
"mobile_cancellable_statuses": ["B", "E", "F", "O"],
"mobile_disputable_statuses": ["C"],
"refund_reasons": [
{ "id": 1, "name": "Produto com defeito" },
{ "id": 2, "name": "Produto diferente do anunciado" },
{ "id": 3, "name": "Não recebi o pedido" }
],
"cancellation_reasons": [ { "id": 4, "name": "Desisti da compra" } ],
"allow_customer_refund": true,
"cancellation_deadline_days": 7
}{ "status": "M", "order_id": 1987349551, "request_type": "cancellation" }{
"status": "M",
"order_id": 1987349551,
"request_type": "refund",
"dispute": {
"dispute_id": 42,
"order_id": 1987349551,
"status": "pending",
"status_label": "Em análise",
"reason_id": 1,
"reason": "Produto com defeito",
"message": "A tela chegou trincada.",
"photos": [
{
"photo_id": 7,
"url": "https://minhaloja.io.venddor.com.br/api/4.0/CustomerCancelApi/photos/eyJwIjo3LCJlIjoxNzkxNzUzMDAwfQ.9f2c...",
"mime_type": "image/jpeg",
"size": 183204
}
],
"photos_expire_at": 1791839400,
"decision_message": null,
"created_at": 1791753000,
"decided_at": null,
"refund_amount_cents": null
}
}{
"order_id": 1987349551,
"order_status": "M",
"can_dispute": false,
"has_dispute": true,
"dispute": { "dispute_id": 42, "status": "pending", "status_label": "Em análise", "...": "mesmos campos da contestação" }
}Campos da resposta
mobile_cancellable_statusesarrayB, E, F, O.mobile_disputable_statusesarrayC, pedido entregue).refund_reasons[]arrayid e name. Padrão: 1 defeito, 2 diferente do anunciado, 3 não recebi.cancellation_reasons[]arrayid e name. Padrão: 4 desisti da compra.allow_customer_refundbooleancancellation_deadline_daysinteger0 é sem prazo.statusstringM: o pedido ficou com solicitação pendente.order_idintegerrequest_typestringcancellationrefunddispute.dispute_idintegerdispute.statusstringpendingapprovedrejectedpending em análise, approved aprovada, rejected recusada. status_label traz o texto em português (Em análise, Aprovada, Recusada).dispute.reason_idintegerdispute.reasonstringdispute.messagestringdispute.photos[]arrayphoto_id, url (assinada, 24 horas), mime_type e size em bytes.dispute.photos_expire_atintegerdispute.decision_messagestring | nullnull enquanto em análise.dispute.created_atintegerdispute.decided_atinteger | nullnull enquanto em análise.dispute.refund_amount_centsinteger | nulldispute.refund_modestringfullpartialmanualorder_statusstringM enquanto há solicitação pendente).can_disputebooleanhas_disputebooleanErros
| Status | Quando | Corpo |
|---|---|---|
| 400 | Corpo inválido ou maior que 40 MiB | {"error":"Corpo da requisição inválido."} |
| 400 | request_type ausente ou desconhecido | {"error":"Tipo de solicitação inválido."} |
| 400 | Contestação sem reason_id válido | {"error":"Informe o motivo da contestação."} |
| 400 | reason_id que não existe | {"error":"Motivo de contestação inválido."} |
| 400 | Mensagem com mais de 2000 caracteres | {"error":"A mensagem pode ter no máximo 2000 caracteres."} |
| 400 | Mais de 5 fotos | {"error":"Envie no máximo 5 fotos."} |
| 400 | Foto maior que 5 MB | {"error":"Cada foto pode ter no máximo 5 MB."} |
| 400 | Foto como caminho ou URL | {"error":"Envie a foto em base64, sem caminho ou URL."} |
| 400 | Foto que não é imagem em Base64 | {"error":"Não foi possível ler as fotos. Envie imagens em base64."} |
| 401 | Sem ekey, vencida, ou token que não é de cliente | {"error":"unauthorized"} |
| 404 | Pedido inexistente, de outro cliente, sub-pedido ou user_id de outra pessoa | {"error":"Pedido não encontrado."} |
| 404 | Foto: assinatura inválida ou vencida | {"error":"Foto não encontrada."} |
| 409 | Já existe um cancelamento pendente | {"error":"Já existe uma solicitação de cancelamento para este pedido."} |
| 409 | Já existe uma contestação em análise | {"error":"Já existe uma contestação em análise para este pedido."} |
| 422 | Pedido numa situação que não permite cancelar | {"error":"Este pedido não pode ser cancelado neste status."} |
| 422 | Pedido numa situação que não permite contestar | {"error":"Este pedido não pode ser contestado neste status."} |
| 422 | Loja não aceita contestações | {"error":"A contestação de pedidos não está disponível nesta loja."} |
| 422 | Fora do prazo de contestação | Mensagem informando o prazo da loja. |
| 422 | Loja sem como publicar as fotos | {"error":"Não foi possível publicar as fotos da contestação."} |
| 500 | Falha ao registrar | {"error":"Não foi possível registrar o cancelamento."} ou ...a contestação. |
Veja também
- Status de pedido
- Visão geral da API 4.0