VenddorDocumentação API
API atualAPI legada
Guia rápidoReferência completa
Carregando índice…
API atual/Referência completa/Cotações e propostas B2B

Negociar em rodadas

Contrapropostas, histórico e aceite de rodadas para cotações negociadas.

Quando a loja liga o módulo enhanced-rfq, cliente e seller trocam propostas em rodadas antes de fechar. Cada rodada é uma cesta completa (produtos, quantidades e preços). Estas cinco rotas exigem os dois módulos, b2b-pricing e enhanced-rfq; sem o segundo, respondem 403 module_disabled.

Fazer contraproposta

Abre uma nova rodada de negociação com a cesta e os preços que o cliente quer. A cotação passa a negotiating, as propostas pendentes anteriores viram countered e o total da cotação passa a ser o da nova rodada. A loja define um máximo de rodadas (5 se não configurou).

POST/api/v1/storefront/quotes/{id}/counterCliente

O cliente propõe uma nova cesta e novos preços

Parâmetros de caminho

idintegerobrigatório
Id numérico da cotação.

Corpo da requisição

itemsarrayobrigatório

Cesta proposta. Pelo menos um item.

product_iduuidobrigatório
Produto.
quantityintegerobrigatório
Quantidade, no mínimo 1.
price_centsintegerobrigatório
Preço unitário proposto, em centavos. Não pode ser negativo.
notesstring
Observação da linha.
messagestring
Mensagem para o seller.
expires_atstring
Até quando a proposta vale (RFC 3339). Depois disso a rodada vira expired.

Exemplo de requisição

Resposta

201Rodada criada

Campos da resposta

iduuid
Id da rodada.
quote_idinteger
Cotação a que a rodada pertence.
round_numberinteger
Número da rodada, a partir de 1.
initiated_bystring
customervendoradmin
Quem fez a proposta.
messagestring
Mensagem que acompanha a proposta.
itemsarray
Cesta proposta: product_id, product_name (nas consultas), quantity, price_cents (centavos por unidade) e notes.
total_centsinteger
Soma de price_cents x quantity, em centavos.
statusstring
pendingacceptedrejectedcounteredexpired
countered é uma proposta substituída por outra mais nova.
expires_atstring
Validade da proposta (RFC 3339). Ausente se não houver.
created_atstring
Criação (RFC 3339).

Erros

StatusQuandoCorpo de exemplo
400O id não é um número.{"error":"invalid quote id"}
401Sem token de cliente no cabeçalho Authorization.{"error":"missing authorization header"}
403A cotação é de outro cliente.{"error":"quote does not belong to this user"}
403O módulo enhanced-rfq está desligado nesta loja.{"error":"module_disabled","module":"enhanced-rfq"}
404Cotação inexistente.{"error":"quote not found"}
400Corpo inválido, sem itens, quantidade ou preço inválido, cotação fora de um estado negociável (pending, quoted, negotiating) ou limite de rodadas atingido.{"error":"counter-offer failed","detail":"maximum negotiation rounds (5) exceeded"}

Ver o histórico da negociação

Lista as rodadas em ordem crescente, de quem quer que as tenha feito (cliente, seller ou administrador), junto com o limite e a rodada atual. É a base para a tela de negociação: a rodada pending mais recente é a que espera resposta.

GET/api/v1/storefront/quotes/{id}/negotiationsCliente

Todas as rodadas de uma cotação

Parâmetros de caminho

idintegerobrigatório
Id numérico da cotação.

Exemplo de requisição

Resposta

200Histórico

Campos da resposta

quote_idinteger
A cotação.
max_roundsinteger
Máximo de rodadas permitido (5 se a loja não definiu).
current_roundinteger
Número da última rodada aberta; 0 se ninguém propôs ainda.
expires_atstring
Validade geral da negociação (RFC 3339). Ausente se não houver.
roundsarray
Rodadas, no formato descrito em Fazer contraproposta.

Erros

StatusQuandoCorpo de exemplo
400O id não é um número.{"error":"invalid quote id"}
401Sem token de cliente no cabeçalho Authorization.{"error":"missing authorization header"}
403A cotação é de outro cliente.{"error":"quote does not belong to this user"}
403O módulo enhanced-rfq está desligado nesta loja.{"error":"module_disabled","module":"enhanced-rfq"}
404Cotação inexistente.{"error":"quote not found"}

Aceitar uma rodada

Aceita a rodada indicada. A cotação vira accepted, as demais rodadas pendentes viram rejected, e as linhas da cotação são reescritas com a cesta da rodada (quantidades e preços, inclusive itens incluídos ou removidos na negociação). Depois, leve ao carrinho.

POST/api/v1/storefront/quotes/{id}/accept-round/{roundId}Cliente

Fecha a negociação com os preços de uma rodada

Parâmetros de caminho

idintegerobrigatório
Id numérico da cotação.
roundIduuidobrigatório
Id da rodada (campo id de uma rodada).

Exemplo de requisição

Resposta

200Rodada aceita

Erros

StatusQuandoCorpo de exemplo
400O id não é um número.{"error":"invalid quote id"}
401Sem token de cliente no cabeçalho Authorization.{"error":"missing authorization header"}
403A cotação é de outro cliente.{"error":"quote does not belong to this user"}
403O módulo enhanced-rfq está desligado nesta loja.{"error":"module_disabled","module":"enhanced-rfq"}
404Cotação inexistente.{"error":"quote not found"}
400A rodada não existe nesta cotação ou não está pending.{"error":"failed to accept round","detail":"round is not in pending status (current: A)"}
422A regra de margem da loja recusou o preço da rodada. O corpo traz ok: false e um reason (below_floor, cost_missing ou unmodelled_offer).{"ok":false,"reason":"below_floor"}
A rota não olha quem propôs

O cliente pode aceitar qualquer rodada pending, inclusive a que ele mesmo propôs. Na interface, ofereça "Aceitar" só para rodadas com initiated_by diferente de customer.

Recusar uma rodada

Marca a rodada como rejected, com um motivo opcional que é anexado à mensagem da rodada. A cotação continua negotiating: o cliente pode fazer uma nova contraproposta ou desistir de vez com recusar cotação.

POST/api/v1/storefront/quotes/{id}/reject-round/{roundId}Cliente

Recusa uma proposta do seller sem encerrar a cotação

Parâmetros de caminho

idintegerobrigatório
Id numérico da cotação.
roundIduuidobrigatório
Id da rodada (campo id de uma rodada).

Corpo da requisição

reasonstring
Motivo da recusa. Opcional; um corpo ausente ou inválido é ignorado.

Exemplo de requisição

Resposta

200Rodada recusada

Erros

StatusQuandoCorpo de exemplo
400O id não é um número.{"error":"invalid quote id"}
401Sem token de cliente no cabeçalho Authorization.{"error":"missing authorization header"}
403A cotação é de outro cliente.{"error":"quote does not belong to this user"}
403O módulo enhanced-rfq está desligado nesta loja.{"error":"module_disabled","module":"enhanced-rfq"}
404Cotação inexistente.{"error":"quote not found"}
400A rodada não existe nesta cotação ou não está pending.{"error":"failed to reject round","detail":"round is not in pending status (current: R)"}

Levar ao carrinho

Passo final da negociação: pega a cotação já accepted e coloca os itens no carrinho com os preços acordados. A cotação vira converted. Diferente de levar ao carrinho em um passo, esta rota não aceita sozinha: exige a cotação já aceita.

POST/api/v1/storefront/quotes/{id}/convert-to-cartCliente

Coloca a cotação aceita no carrinho do cliente

Parâmetros de caminho

idintegerobrigatório
Id numérico da cotação.

Exemplo de requisição

Resposta

200Carrinho preparado

Campos da resposta

cart_iduuid
Carrinho que recebeu os itens.
quote_idinteger
A cotação convertida.
items_addedinteger
Linhas colocadas no carrinho.
total_centsinteger
Soma das linhas, em centavos.

Erros

StatusQuandoCorpo de exemplo
400O id não é um número.{"error":"invalid quote id"}
401Sem token de cliente no cabeçalho Authorization.{"error":"missing authorization header"}
403A cotação é de outro cliente.{"error":"quote does not belong to this user"}
403O módulo enhanced-rfq está desligado nesta loja.{"error":"module_disabled","module":"enhanced-rfq"}
404Cotação inexistente.{"error":"quote not found"}
400A cotação não está accepted, expirou ou não tem itens válidos.{"error":"failed to convert quote to cart","detail":"quote must be in 'accepted' status to convert (current: negotiating)"}
Quem responde pelo seller

A resposta do seller acontece no painel dele (API do seller), que não faz parte desta seção. Na vitrine, o cliente enxerga essas respostas como novas rodadas em negotiations.

Veja também

  • Decidir uma cotação
  • Pedir e consultar cotações
Anterior
Decidir uma cotação
Próxima
Proposta por link (sem login)
Nesta página
  • Fazer contraproposta
  • Ver o histórico da negociação
  • Aceitar uma rodada
  • Recusar uma rodada
  • Levar ao carrinho
  • Veja também
bash
curl -X POST "$BASE_URL/api/v1/storefront/quotes/42/counter" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      {
        "product_id": "c3f92551-9dda-4fc7-b518-353d1c4e4035",
        "quantity": 200,
        "price_cents": 1950
      }
    ],
    "message": "Fechamos por R$ 19,50 a unidade?",
    "expires_at": "2026-10-18T23:59:59Z"
  }'
bash
curl "$BASE_URL/api/v1/storefront/quotes/42/negotiations" \
  -H "Authorization: Bearer $TOKEN"
bash
curl -X POST "$BASE_URL/api/v1/storefront/quotes/42/accept-round/9d1c7e52-4a3b-4f60-8e1d-2b5a7c9e1f30" \
  -H "Authorization: Bearer $TOKEN"
bash
curl -X POST "$BASE_URL/api/v1/storefront/quotes/42/reject-round/9d1c7e52-4a3b-4f60-8e1d-2b5a7c9e1f30" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "Abaixo do nosso orçamento"
  }'
bash
curl -X POST "$BASE_URL/api/v1/storefront/quotes/42/convert-to-cart" \
  -H "Authorization: Bearer $TOKEN"
json
{
  "id": "9d1c7e52-4a3b-4f60-8e1d-2b5a7c9e1f30",
  "quote_id": 42,
  "round_number": 1,
  "initiated_by": "customer",
  "message": "Fechamos por R$ 19,50 a unidade?",
  "items": [
    {
      "product_id": "c3f92551-9dda-4fc7-b518-353d1c4e4035",
      "quantity": 200,
      "price_cents": 1950
    }
  ],
  "total_cents": 390000,
  "status": "pending",
  "expires_at": "2026-10-18T23:59:59Z",
  "created_at": "2026-10-12T10:30:00Z"
}
json
{
  "quote_id": 42,
  "max_rounds": 5,
  "current_round": 1,
  "rounds": [
    {
      "id": "9d1c7e52-4a3b-4f60-8e1d-2b5a7c9e1f30",
      "quote_id": 42,
      "round_number": 1,
      "initiated_by": "customer",
      "message": "Fechamos por R$ 19,50 a unidade?",
      "items": [
        {
          "product_id": "c3f92551-9dda-4fc7-b518-353d1c4e4035",
          "product_name": "Caneta esferográfica azul (cx 50)",
          "quantity": 200,
          "price_cents": 1950
        }
      ],
      "total_cents": 390000,
      "status": "pending",
      "expires_at": "2026-10-18T23:59:59Z",
      "created_at": "2026-10-12T10:30:00Z"
    }
  ]
}
json
{
  "message": "round accepted"
}
json
{
  "message": "round rejected"
}
json
{
  "cart_id": "b7a3c1e9-6d24-4f8a-a0b5-93e1c7d2f468",
  "quote_id": 42,
  "items_added": 1,
  "total_cents": 390000
}