VenddorDocumentação API
API atualAPI legada
Guia rápidoReferência completa
Carregando índice…
API legada/Referência completa/API 4.0 (app móvel)

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_type igual a refund): 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.

GET/api/4.0/CustomerCancelApiCliente

Regras 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
Opcional. Se vier, precisa ser o próprio cliente da ekey; outro cliente responde 404.
POST/api/4.0/CustomerCancelApiCliente

Pedir 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ório
cancellationrefund
cancellation pede o cancelamento. refund abre uma contestação. Outro valor responde 400.
order_idstringobrigatório
Id do pedido (decimal ou UUID), como número ou texto. Também é aceito na consulta (?order_id=). Sub-pedidos (números com -V) não podem ser cancelados por aqui: use o pedido principal.
user_idstring
Opcional. Se vier, precisa ser o próprio cliente.
additional_detailsstring
Texto livre do cliente. Na contestação, no máximo 2000 caracteres.
reason_idinteger
Só na contestação, obrigatório: id de um dos refund_reasons das regras.
photosarray
Só na contestação, opcional: até 5 fotos. Cada item é um objeto {"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.
GET/api/4.0/CustomerCancelApi/{orderId}Cliente

Situaçã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
Id do pedido (decimal ou UUID).
GET/api/4.0/CustomerCancelApi/photos/{token}Pública

Foto 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ório
Token assinado, tal como veio em photos[].url.

Exemplo de requisição

Contestar um pedido entregue, com uma foto:

bash
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:

bash
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

200Regras (GET /CustomerCancelApi)
json
{
  "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
}
200Cancelamento registrado
json
{ "status": "M", "order_id": 1987349551, "request_type": "cancellation" }
200Contestação registrada
json
{
  "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
  }
}
200Situação (GET /CustomerCancelApi/{orderId})
json
{
  "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_statusesarray
Letras de situação do pedido em que o app pode mostrar Cancelar. Vazio quando a loja desligou o cancelamento. Padrão: B, E, F, O.
mobile_disputable_statusesarray
Letras em que o app pode mostrar Contestar. Nunca vazio (o padrão é C, pedido entregue).
refund_reasons[]array
Motivos de contestação: id e name. Padrão: 1 defeito, 2 diferente do anunciado, 3 não recebi.
cancellation_reasons[]array
Motivos de cancelamento: id e name. Padrão: 4 desisti da compra.
allow_customer_refundboolean
Se a loja aceita contestações.
cancellation_deadline_daysinteger
Prazo, em dias contados da data do pedido, para contestar. 0 é sem prazo.
statusstring
Sempre M: o pedido ficou com solicitação pendente.
order_idinteger
O número do pedido como inteiro, no mesmo formato recebido.
request_typestring
cancellationrefund
O que foi pedido.
dispute.dispute_idinteger
Número da contestação.
dispute.statusstring
pendingapprovedrejected
pending em análise, approved aprovada, rejected recusada. status_label traz o texto em português (Em análise, Aprovada, Recusada).
dispute.reason_idinteger
Motivo escolhido.
dispute.reasonstring
Nome do motivo.
dispute.messagestring
Texto do cliente.
dispute.photos[]array
Fotos: photo_id, url (assinada, 24 horas), mime_type e size em bytes.
dispute.photos_expire_atinteger
Quando as URLs das fotos vencem (Unix timestamp). Peça a situação de novo para receber URLs novas.
dispute.decision_messagestring | null
Texto da decisão da loja. null enquanto em análise.
dispute.created_atinteger
Abertura (Unix timestamp, segundos).
dispute.decided_atinteger | null
Decisão (Unix timestamp). null enquanto em análise.
dispute.refund_amount_centsinteger | null
Valor estornado, em centavos, quando aprovada. Fora do padrão da 4.0, que usa reais.
dispute.refund_modestring
fullpartialmanual
Como o estorno foi feito. Só aparece quando aprovada.
order_statusstring
Letra da situação atual do pedido (M enquanto há solicitação pendente).
can_disputeboolean
Se o cliente pode abrir uma contestação agora: situação liberada, dentro do prazo, sem outra em análise e com a loja aceitando contestações.
has_disputeboolean
Se já existe alguma contestação do pedido.

Erros

StatusQuandoCorpo
400Corpo inválido ou maior que 40 MiB{"error":"Corpo da requisição inválido."}
400request_type ausente ou desconhecido{"error":"Tipo de solicitação inválido."}
400Contestação sem reason_id válido{"error":"Informe o motivo da contestação."}
400reason_id que não existe{"error":"Motivo de contestação inválido."}
400Mensagem com mais de 2000 caracteres{"error":"A mensagem pode ter no máximo 2000 caracteres."}
400Mais de 5 fotos{"error":"Envie no máximo 5 fotos."}
400Foto maior que 5 MB{"error":"Cada foto pode ter no máximo 5 MB."}
400Foto como caminho ou URL{"error":"Envie a foto em base64, sem caminho ou URL."}
400Foto que não é imagem em Base64{"error":"Não foi possível ler as fotos. Envie imagens em base64."}
401Sem ekey, vencida, ou token que não é de cliente{"error":"unauthorized"}
404Pedido inexistente, de outro cliente, sub-pedido ou user_id de outra pessoa{"error":"Pedido não encontrado."}
404Foto: assinatura inválida ou vencida{"error":"Foto não encontrada."}
409Já existe um cancelamento pendente{"error":"Já existe uma solicitação de cancelamento para este pedido."}
409Já existe uma contestação em análise{"error":"Já existe uma contestação em análise para este pedido."}
422Pedido numa situação que não permite cancelar{"error":"Este pedido não pode ser cancelado neste status."}
422Pedido numa situação que não permite contestar{"error":"Este pedido não pode ser contestado neste status."}
422Loja não aceita contestações{"error":"A contestação de pedidos não está disponível nesta loja."}
422Fora do prazo de contestaçãoMensagem informando o prazo da loja.
422Loja sem como publicar as fotos{"error":"Não foi possível publicar as fotos da contestação."}
500Falha ao registrar{"error":"Não foi possível registrar o cancelamento."} ou ...a contestação.
O prazo só vale para contestar

cancellation_deadline_days limita contestações. O cancelamento depende apenas da situação do pedido (e de a loja ter o cancelamento ligado). Não mostre "prazo vencido" no botão Cancelar.

Contestação recusada reabre a chance

Quando a loja recusa uma contestação, o pedido volta à situação anterior e can_dispute pode voltar a ser verdadeiro, desde que ainda esteja no prazo. Já uma contestação aprovada com estorno parcial não cancela o pedido: order_status continua sendo o real.

Use as regras do GET, não valores fixos

As letras, os motivos e o prazo são configuração da loja e mudam. Leia GET /CustomerCancelApi ao abrir a tela do pedido em vez de gravar B,E,F,O no app.

Veja também

  • Status de pedido
  • Visão geral da API 4.0
Anterior
Formas de pagamento
Próxima
Avisos
Nesta página
  • Exemplo de requisição
  • Resposta
  • Erros
  • Veja também