O que entra aqui. Mudança de contrato: tipo de campo, nome de campo, valor de
enum, resposta de erro, endpoint novo ou removido. Melhoria de texto e correção de
exemplo na documentação não entram.Como ler.
Incompatível altera o que a API já devolvia e exige ação de quem
integra. Corrigido, Adicionado e Documentado não exigem nada.Produtos, ofertas, bumps, clientes e checkouts pelo negócio da chave
Incompatível
Escopo pelo negócio da chave. Nas contas com a leitura por negócio liberada,products,
offers, bumps, customers e checkouts passam a listar e alterar só o que é do negócio da
chave de API, como já acontece com pedidos, saldo e saques. Chave sem negócio vale para o negócio
pessoal. Item de outro negócio responde 404. Nas demais contas nada muda.Assinatura informa quem a cancelou e o motivo do assinante
Adicionado
canceledBy e cancellationFeedback na assinatura. Os dois campos saem em todo objeto de
assinatura: na API pública e no subscription dos webhooks.canceledBydiz quem fez o último cancelamento:subscriber(o assinante, pelo portal),producer(o painel),api(a API pública) ousystem(régua de cobrança, disputa, reembolso, cobrança recusada).cancellationFeedbacktraz o motivo que o assinante escolheu ao cancelar pelo portal:too_expensive,not_using,not_as_expected,access_problemouother.
null em assinatura nunca cancelada, em cancelamento anterior a esta mudança e, no
caso do motivo, quando o assinante não informou. Até aqui, todo cancelamento pedido chegava
igual, e não dava para separar o que o produtor fez do que a integração ou o assinante fizeram.Duplicação de produto copia a área de membros
Adicionado
Duplicação copia a área de membros.POST /public_api/products/{id}/duplicate/
passa a copiar a área de membros do produto, sem alunos nem progresso, e a resposta ganha o campo
member_area_copy: status (done ou copying) e member_area_id, ou null quando o produto não
tem área de membros. Com copying, o conteúdo da área chega em segundo plano.Resposta 409 na duplicação. Enquanto a área de membros do produto de origem ainda está sendo
copiada, POST /public_api/products/{id}/duplicate/ responde 409 com code: member_area_copying e
não cria nada.Chargeback e MED: aviso por webhook e defesa pela API
Adicionado
Eventodispute_defense_requested. Sai quando um chargeback ou MED abre prazo de defesa, com a
forma de pedido e o
bloco dispute: tipo (chargeback ou med), registro
da contestação, fim do prazo do produtor (deadline, 23:59 de Brasília) e o link da contestação no
painel. O evento chargeback também dispara no pré-chargeback, que não comporta defesa, e o MED não
tinha evento: quem precisa saber que há uma defesa a enviar assina este. Ele pode ser testado em
Testar Webhook.Endpoints de chargeback e MED, com o escopo orders e o id do pedido no caminho, como em
reembolsos:GET /public_api/disputes/: as contestações por aba (awaiting,in_review,won,lost,expired), com o estado da defesa e o próximo prazo;GET /public_api/disputes/{id}/: prazo, regras de envio e, depois do envio, a carta, os documentos e o andamento;POST /public_api/disputes/{id}/defense/: a defesa emmultipart/form-data, com os PDFs, a carta ao banco e o aceite;POST /public_api/disputes/{id}/complement/: a resposta ao pedido de complemento do Compliance.
Webhook de pedido informa a moeda da venda
Adicionado
currency no data dos eventos de pedido. A moeda em que vêm baseAmount, amount, fees,
discount e as comissões, que é a moeda do produto (BRL, USD, …). Antes ela só aparecia em
offer.currency, e quem lia amount sem olhar a oferta tratava uma venda de US 19,18. Em produto em real nada muda: o campo vem "BRL".Chave de API de negócio adicional: escrita financeira só depois da aprovação
Adicionado
409 com code: "business_not_approved". Uma chave de API pertence a um negócio. Quando é a
chave de um negócio adicional que ainda não foi aprovado, as operações que alteram dados ou
movimentam dinheiro respondem 409:- Onde vale:
POST /public_api/withdrawals/,PUT /public_api/installment-interest/,POST /public_api/refunds/{id}/approve/ePOST /public_api/orders/{id}/refund/. - O que continua liberado: todas as consultas (
GET), inclusive saldo, taxas e saques. - O que fazer: trate pelo
code, não pelo texto. Repetir a chamada não resolve; a escrita passa a funcionar quando o negócio for aprovado, sem trocar a chave.
403 quando o dono da chave não é proprietário do negócio. Nas mesmas operações de escrita, a
chave de quem deixou de ser proprietário ativo do negócio responde 403 com
{"detail": "Apenas o proprietário do negócio pode executar esta ação."}.Documentado
Saldo, saques, taxas, juro adicional e reembolsos passam a valer para o negócio da chave. Uma chave sem negócio continua valendo para o seu negócio pessoal. O headerX-Cakto-Business não tem
efeito na API pública: quem usa a chave não escolhe outro negócio.X-Idempotency-Key é isolado por negócio nas contas com o financeiro por negócio liberado.
Nessas contas, chaves de API de negócios diferentes do mesmo usuário podem reutilizar o mesmo valor
sem que um pedido confunda o outro. Nas demais, todas as chaves do usuário movimentam a mesma conta
e o valor continua valendo para o usuário inteiro, como antes.Cupom em valor, percentual com centavos e cupom só na 1ª cobrança da assinatura
Incompatível
coupon.discount do pedido deixa de ser sempre um percentual. O objeto coupon que vem no
pedido ganha discountType. Com "percentage", discount continua sendo o percentual, agora com
até duas casas decimais. Com "fixed", discount é um valor na moeda de coupon.currency:- Nada muda nos cupons que já existiam: todos vêm
"percentage", com o mesmo número. - Quem sente: quem calcula o desconto multiplicando o preço por
coupon.discount / 100. LeiadiscountTypeantes, ou use odiscountdo pedido, que sempre foi o valor descontado em dinheiro e não mudou.
Adicionado
coupon.discountType e coupon.currency. O tipo do desconto (percentage ou fixed) e a
moeda do cupom. No fixed, currency é a moeda em que discount está.coupon.couponType. default: o desconto vale em toda cobrança, como sempre. first_charge: o
desconto vale só na 1ª cobrança da assinatura, e as renovações saem pelo preço cheio da oferta.
Os pedidos de renovação de uma assinatura vendida com cupom first_charge vêm sem cupom e com
discount zero.Regras do coupon na criação de pagamento (POST /public_api/payments/).- Cupom
fixedvale só na oferta principal (nunca em order bump), só em oferta da mesma moeda e até 80% do preço da oferta. Fora disso, o cupom é ignorado e o pagamento segue sem desconto, como já acontece com cupom inválido ou expirado. - Cupom
first_chargevale só em oferta de assinatura (em oferta única é ignorado) e só com cartão, Pix ou Pix Automático. Com outro método, a criação devolve400com{"detail": "Este cupom não vale para esse meio de pagamento."}. - No Pix Automático com cupom
first_charge, o comprador paga a 1ª cobrança com desconto e o mandato fica autorizado pelo valor cheio das renovações.
Saldo separa o total bloqueado por reembolso das demais parcelas
Incompatível
pending e reserved de GET /public_api/balance/ mudam de valor. Eles passam a vir
descontados do que está retido por pedido de reembolso em processamento. Antes, a parte retida
ainda aparecia dentro deles — e, no caso do dinheiro já liberado, aparecia ao mesmo tempo em
heldByRefund e em pending, contando o mesmo valor duas vezes.- Nada mudou de nome nem de tipo. Continuam string decimal, na mesma posição. O que mudou é o número, e ele fica menor quando há retenção — por isso este aviso: uma mudança assim não quebra o parsing e passa despercebida numa conferência rápida.
-
Quem sente: quem concilia
pendingoureservedcontra um histórico próprio, ou soma os campos para exibir um total. Conta sem pedido de reembolso em processamento não muda de número. -
Para reconstituir os valores anteriores, use as duas fatias publicadas junto:
No exemplo acima:
3890.15 + 120.00 + 89.90 = 4100.05e412.00 + 50.00 = 462.00. As fórmulas fecham exatamente sobre os valores da mesma resposta, sem tolerância de arredondamento: se na sua conciliação não fecharem, é inconsistência a investigar — registre a chamada e fale com o suporte. -
O
+ heldByRefundda primeira linha não é erro de digitação. Até esta mudança, a parte já liberada do bloqueio era contada ao mesmo tempo empendinge emheldByRefund— o mesmo dinheiro em dois campos. Reconstituir o valor antigo exige devolver essa duplicata, que é justamente o que a mudança apagou. -
Não use
refundBlocked - heldByRefundno lugar das fatias. Essa diferença mistura o que saiu depending, o que saiu dereservede o retido que nunca esteve em nenhum dos dois — ela não é a parcela de campo nenhum, e erra em quase todos os casos. -
Com
refundBlocked: nullas duas fatias vêmnulljunto com ele, ependingereservednão sofreram desconto nenhum:pending_antigo = pending + heldByRefundereserved_antigo = reserved. Com a retenção desligadaheldByRefundé"0.00"; quando a apuração falhou, ele traz a fatia já descontada deavailable, que a resposta antiga também somava empending.
Adicionado
refundBlocked no saldo, com as duas fatias de onde ele saiu. O total bloqueado por pedidos de
reembolso em processamento: a soma de todas as partes da sua conta nesses pedidos, tenha o dinheiro
liberado ou não. Junto com ele vêm refundBlockedFromPending e refundBlockedFromReserved, que
dizem quanto desse total saiu de cada campo.heldByRefund continua existindo e não foi renomeado: ele conta só a fatia já liberada, que é a
única que o saque de fato recusa. refundBlocked conta essa fatia e a que ainda não liberou — e é
por isso que é sempre maior ou igual a heldByRefund. Parte do bloqueio não aparecia em campo nenhum
até aqui.As fatias não somam o total. heldByRefund + refundBlockedFromPending + refundBlockedFromReserved
pode ser menor que refundBlocked — no exemplo acima, 89.90 + 120.00 + 50.00 = 259.90 contra
289.90. Os 30.00 de diferença são exatamente o bloqueio que não aparecia em campo nenhum antes:
pendente já dentro da janela de antecipação, e venda parcialmente antecipada.Com ele, available, pending, reserved, anticipatable e refundBlocked são parcelas
disjuntas: cada real aparece em um campo só, então somá-las não conta nada duas vezes. A soma não
é “o patrimônio da conta” — uma venda parcialmente antecipada fora de reembolso deixa o resto a
receber fora dos cinco campos. anticipatable entra nessa lista porque ele não é um recorte de
pending: os dois são baldes separados, e a descrição anterior dizia o contrário.refundBlockedpode virnull, enullnão é zero. Significa que não há número a publicar — a retenção não está ativa para a sua conta, ou a apuração falhou naquela chamada. Zero de verdade vem"0.00". Tratarnullcomo zero anuncia ao produtor que nada está bloqueado, o que pode ser falso.- As duas fatias acompanham esse
null. Sem apuração não há fatia a publicar, e"0.00"ali afirmaria que nada saiu daquele campo. heldByRefundnão acompanha onull: ele mantém o próprio valor, que é"0.00"com a retenção desligada e a fatia já descontada deavailablequando a apuração falhou.refundBlockednão concilia 1:1 com o valor das vendas em análise. Numa venda parcialmente antecipada que ainda não liberou, o bloqueio é só o resto — R 50,00 com R$ 20,00 já antecipados. Depois que a venda libera, e na venda antecipada por inteiro, o bloqueio é o valor cheio da venda, e fica também emheldByRefund.- Detalhe e exemplos em Saldo.
Reembolsos: evento de webhook refund_requested, consulta e aprovação pela API
Adicionado
Evento de webhookrefund_requested. Dispara quando o comprador pede reembolso, com a janela
aberta. Além da forma de pedido de sempre, data traz o bloco refundRequest, com
requestedAt, autoApproveAt (quando o reembolso é efetivado sozinho, se ninguém agir antes) e
reason. O contato do comprador é o customer de sempre. Ver
Guia de Webhooks.- Nenhuma ação é necessária para quem não quer o evento. Os demais eventos de pedido não
mudaram: o bloco só existe no
refund_requested. - Para receber, assine o evento no webhook (painel ou Atualizar Webhook).
orders que as chaves já têm:GET /public_api/refunds/: Listar Reembolsos, com filtro porstatus, data do pedido de reembolso e produto.GET /public_api/refunds/{id}/: Consultar Reembolso.POST /public_api/refunds/{id}/approve/: Aprovar Reembolso, que antecipa um reembolso pedido pelo comprador. Só alcança solicitação aberta: se o comprador desistiu, responde409e não estorna nada. Repetir a chamada é seguro.
id do reembolso é o id do pedido, o mesmo data.id do webhook.Produto em moeda estrangeira exige a venda internacional habilitada na conta
Incompatível
Criar produto comcurrency diferente de BRL passou a exigir a venda em moeda estrangeira
habilitada na conta. A habilitação é feita pela Cakto, por conta, e o painel já só oferecia a
escolha de moeda a quem a tinha; a API aceitava de qualquer conta. Agora
POST /public_api/products/ com moeda estrangeira, e POST /public_api/products/{id}/duplicate/
de um produto nessa moeda, voltam 400 para conta sem a habilitação:- Quem sente: conta sem a venda internacional habilitada que criava ou duplicava produto em dólar (ou em outra moeda que não o real) pela API ou pelo MCP.
- Produto que já existe continua editável. A moeda de um produto nunca pôde ser trocada depois da criação, então editar não passa por esta regra.
- Produto em real não muda, inclusive o criado sem
currencyno corpo, que nasce emBRL.
Evento de pedido ganha o campo callback
Adicionado
callback no payload de pedido. Todo evento de pedido passa a trazer mais um campo: o token
que o produtor pôs em ?callback= no link do checkout. É null quando a compra não veio com um.- Nenhuma ação é necessária. É adição de campo: o payload não mudou de forma, nada foi renomeado e nada saiu. Um handler que ignora chaves desconhecidas continua funcionando.
- A lista de campos fixos do evento de pedido foi de 43 para 44 — ver Guia de Webhooks.
callback, esse, chega para todo mundo — apenas vem null para quem não usa o recurso.Listagem de saques passa a usar o envelope padrão de paginação
Corrigido
GET /public_api/withdrawals/ estava paginando fora do padrão. A operação nasceu hoje devolvendo
{ count, total_pages, page, page_size, results } e aceitando page_size — um formato que não é o
do contrato. Toda listagem da API pública usa limit e devolve
{ count, next, previous, results }, e a página de Paginação afirma que o
envelope é o mesmo em todas. Agora é.- Se você integrou a listagem de saques nas primeiras horas de hoje, troque
page_sizeporlimite leia a próxima página pornextem vez de calcular a partir detotal_pages. É a única ação necessária, e só afeta a listagem — solicitar e consultar saque não mudaram. - O teto de
limitnesta operação é 1000, como nas demais listagens ampliadas.
Saque pela API pública, com escopos próprios
Adicionado
Saque. Três operações novas: solicitar, consultar e listar. É a primeira operação do contrato que tira dinheiro da conta, e por isso ela chega com regras que as outras não têm.POST /public_api/withdrawals/— solicita o saque.GET /public_api/withdrawals/{id}/— estado do pedido.GET /public_api/withdrawals/— histórico, paginado.
withdrawals_read— consulta e listagemwithdrawals_write— solicitar saque
withdrawals_write explicitamente. Isso é proteção, não
burocracia: uma chave antiga que vazasse não deve conseguir esvaziar a conta.O que a operação não faz, e não vai fazer:- Não cadastra nem altera chave Pix. O saque vai sempre para a chave já cadastrada no painel;
pixKeyeaccountno corpo são ignorados. Quem tem a chave de API decide quanto sacar, nunca para onde. - Não paga na hora. Todo saque pedido pela API entra na fila de análise com
status: "pending".201significa pedido registrado, não dinheiro transferido — acompanhe pela consulta.
X-Idempotency-Keyobrigatória noPOST. Sem ela a requisição é recusada com400: num endpoint que move dinheiro, um retry de timeout sem chave de idempotência vira um segundo saque. A resposta fica guardada por 24h; repetir a mesma chave devolve o mesmo resultado.- 2 solicitações por hora, por chave de API. Acima disso,
429comRetry-After.
"10.00", e a taxa de saque
descontada do pedido — você pede amount, a conta recebe amountReceived.Saldo e agenda de recebimentos na API pública
Adicionado
Saldo e agenda de recebimentos. Duas operações novas, escopopayments. São as mesmas
informações do painel: o cartão de saldo e a tela Agenda Financeira.GET /public_api/balance/— quanto está disponível para saque agora e quanto ainda vai liberar.GET /public_api/balance/schedule/— quanto libera em cada dia.
availablepode ser negativo. Retenção por reembolso, chargeback e MED descontam do disponível sem piso, e o resultado é dívida real. Cliente que trate saldo como “sempre ≥ 0” esconde exatamente o que o produtor precisa ver.- A agenda filtra por data de liberação, não pela data da venda.
releaseDate__gteereleaseDate__lterecortam quando o dinheiro cai; para recortar vendas por criação, useGET /public_api/orders/. Sem os dois parâmetros a resposta traz os próximos 30 dias, e a janela não passa de 365 dias. - Dia sem valor não aparece na agenda. A lista é esparsa: para montar um calendário, preencha os buracos com zero.
"1250.40"), como no resto do contrato. Conta sem cadastro de
recebimento concluído responde 409, que não significa saldo zero: saldo zero é 200 com
"0.00".Documentado
Valores e campos que já existiam no backend e não constavam na referência.multi_cardecard_pixno enum depaymentMethod. Os dois métodos já chegavam nos seus webhooks; a referência é que listava só os demais. Quem validava o enum como fechado tratava pedido real como valor inválido.offerdo order bump pode virnull— o schema declarava o campo como sempre presente.- Descrição de
paymentMethodemGET /public_api/fees/: a lista é a das taxas configuradas e inclui método que a cobrança não aceita.
Boleto sai do contrato e o pré-requisito de conta Cakto Banking deixa de existir
Incompatível
boleto saiu de paymentMethod em POST /public_api/payments/. O trilho de boleto
liquidava numa conta Cakto Banking, que a Cakto deixou de usar. Cobranças com
paymentMethod: "boleto" agora voltam 400:- Quem sente: quem emite boleto pela API. Migre para
pixoupix_auto, que aceitam o mesmo payload sem os camposdueDateeboleto. POST /public_api/subscriptions/{id}/change-payment-method/também recusaboleto, pelo mesmo motivo. Assinatura que hoje cobra por boleto precisa ser migrada de método.- Boleto já emitido não é cancelado por esta mudança: o que existe segue com o mesmo status e a mesma baixa. O que muda é a emissão de novos.
Corrigido
Pix e Pix Automático não exigem mais conta Cakto Banking. Até aqui,pix e pix_auto
voltavam 400 no campo paymentMethod quando o produtor não tinha conta Cakto Banking
aberta e ativa. A exigência não correspondia ao fluxo real — esses métodos não liquidam
nessa conta — e bloqueava a maioria dos integradores. O gate foi removido: nenhuma
resposta nova aparece, uma que não deveria existir deixa de aparecer.- Nada a fazer. Quem tratava esse
400pode remover o tratamento; quem estava bloqueado volta a cobrar sem mudar payload. - O erro
ContaBankingAusentedeixou de existir no schema.
Dígito verificador do cartão na tokenização
Incompatível
POST /public_api/card-tokens/ passou a recusar número de cartão com dígito
verificador inválido. Antes o número era tokenizado e a recusa só vinha da adquirente,
na autorização. Agora a validação acontece na entrada e a resposta é 422, o mesmo
status que a operação já usa para corpo inválido:- Só é recusado o que já não era cobrável. Todo cartão termina num dígito verificador calculado pelo algoritmo de Luhn; número que não fecha essa conta não existe, e nenhuma adquirente autoriza. Cartão real continua tokenizando normalmente.
- Quem sente: quem envia número gerado ou digitado sem conferência — teste automatizado
com PAN fictício, principalmente. Se a sua suíte usa número inventado, troque por um que
feche o Luhn (
4111 1111 1111 1111e5555 5555 5555 4444fecham). - Espaço e hífen continuam aceitos: a validação normaliza antes de conferir.
- Como o pagamento por cartão só aceita
cardToken, isso fecha a porta para o número inválido em todo o fluxo — não há outro caminho de PAN na API. - A validação não diz que o cartão existe, está ativo ou tem saldo. Recusa por saldo, limite ou antifraude continua vindo da adquirente como sempre.
Assinatura nos webhooks e expiração do Pix aplicada de verdade
Adicionado
Webhooks passam a ir assinados. Toda entrega leva agora dois headers novos:X-Cakto-Timestamp (Unix time do envio) e X-Cakto-Signature, no formato
v1=<hmac-sha256> — HMAC-SHA256 de {timestamp}.{corpo cru}, com o secret do webhook
como chave. Serve para provar a origem sem depender do segredo que vem no corpo, e detecta
payload adulterado ou reenviado.Nada muda para quem já valida pelo corpo. O campo secret continua em toda entrega e a
validação por comparação segue válida — os headers são adicionais. Ver
Validando a origem.Corrigido
pixExpiresIn passa a valer. O campo era aceito e validado contra o limite do produto,
mas não chegava à adquirente: a validade do QR acabava sendo sempre o padrão de quem
processou a cobrança. Agora o valor enviado é repassado, e o pix.expirationDate da
resposta reflete o que foi pedido.Se você já mandava o campo, a validade do QR muda a partir de agora — passa a ser a que
você pediu, em vez do padrão da adquirente (que costumava ser maior). Quem não envia o campo
não é afetado: segue valendo o padrão da adquirente, igual a antes.Juro adicional de parcelamento, e a taxa que o comprador paga
Adicionado
Juro adicional de parcelamento. Três operações novas, escopopayments (a escrita
também exige write). É o juro que você cobra do comprador por parcelar, somado por
cima do juro-base da Cakto que sai em GET /public_api/fees/ — são dois números
diferentes, cobrados por partes diferentes, na mesma parcela.GET /public_api/installment-interest/— a sua tabela de juro adicional.PUT /public_api/installment-interest/— configura essa tabela.GET /public_api/installment-interest/earnings/— quanto de juro foi cobrado e quanto ficou com você num período.
- A faixa é de 2x a 12x, sempre com as onze faixas na resposta e sempre na mesma
ordem. Não existe juro adicional em 1x. Parcela sem juro configurado vem com
interestPercentage: null—nullnão é zero. interestPercentageé number em pontos percentuais (1.5é 1,5%), como toda porcentagem no contrato.activeé quem decide se algo é cobrado. Comactive: falsea tabela continua guardada e nada é somado ao comprador — desligar preserva os percentuais em vez de apagá-los. Sempre cruze os dois campos antes de calcular o valor de uma parcela.- O
PUTsubstitui a tabela inteira: parcela que não estiver no corpo fica sem juro, e uma lista vazia zera todas. Mandar o mesmo corpo duas vezes deixa a conta no mesmo estado, então a chamada é segura de repetir — e por isso ela não lê o headerX-Idempotency-Key. - O
PUTmuda o que o comprador paga, a partir do próximo pagamento parcelado. Pedidos já pagos não mudam. O checkout que o comprador já tem aberto continua exibindo a tabela antiga até recarregar, mas a cobrança usa a tabela nova — os detalhes estão em Configurar Juro Adicional. - Não há teto de negócio no percentual — o quanto cobrar é decisão sua, e a API
aceita a mesma faixa que o painel. O limite é técnico (
99999999.99, o que cabe no campo) e o percentual aceita no máximo duas casas decimais. - Reativar é explícito.
activeomitido valetrue, então umPUTsemactivesobre uma tabela desligada volta409em vez de religar a cobrança em silêncio. Mandeactive: truepara religar, ouactive: falsepara mexer nos percentuais mantendo desligado. Com a tabela vigente, ou nunca configurada, omitir segue valendotrue. 409tem três motivos, distinguíveis pelodetail: conta sem cadastro de recebimento concluído, recurso não habilitado para a conta, ou a reativação implícita acima. Nenhum dos três se resolve repetindo a chamada.
GET /public_api/fees/ passou a devolver customerFees. Campo novo, aditivo — a
lista de taxas que a Cakto cobra do comprador nas vendas da sua conta, somadas ao
total que ele paga e que não saem do seu repasse. Ver
Taxas e Prazos.- Hoje traz uma linha: Taxa de serviço,
amount"0.99", todos os métodos (paymentMethod: null), devolvida ao comprador no reembolso (refundable: true). O valor é por pedido, não por parcela, e não varia com o valor da venda. - Leia a lista, não assuma os R$ 0,99. Em parte das contas essa taxa é cobrada do
produtor em vez do comprador, ou não é cobrada — nesses casos ela não aparece, e
customerFees: []é resposta válida. - É lista, e não um campo fixo, justamente para a composição poder mudar sem quebrar quem já integra.
- Se você monta a tela de preço do comprador, o total dele é o produto mais
amount. Se você calcula o seu líquido,customerFeesnão entra na conta.
- A resposta traz
chargedeearnedlado a lado, e eles não são o mesmo número.chargedé o juro que o comprador pagou nos seus pedidos;earnedé a fatia que ficou com você depois do rateio por comissão. Num produto com coprodutor a 30%,earnedé 70% decharged. Somar o juro dos pedidos e chamar de ganho superestima quem divide receita. - Os dois vêm como string decimal (
"1000.00"), como todo dinheiro no contrato novo. - A janela é obrigatória por consequência: sem
startDate/endDatea consulta responde os últimos 30 dias, e o período pedido não pode passar de 92 dias (400acima disso). Os camposstartDateeendDateda resposta ecoam a janela que foi realmente aplicada — confira, principalmente se você não mandou nenhuma das duas. - Só entram pedidos pagos, e uma consulta responde sobre uma moeda só (
currency, padrãoBRL). - O total de um período passado pode mudar. Não há registro de reversão: se um pedido daquele período for reembolsado ou sofrer chargeback depois, ele sai do total. Se você armazenar o valor, reconcilie em vez de tratá-lo como fechado.
Contrato de pagamentos, webhooks, produtos e taxas
Incompatível
initiate_checkout saiu do catálogo de webhooks. Ele era assinável e nunca foi
entregue — é evento de pixel, disparado no carregamento do checkout, quando ainda não
existe pedido nem pagamento. Assinar não dava erro e nada chegava. Não há substituto por
webhook hoje.Só afeta quem tentou assinar esse evento; nenhuma entrega existente muda.Corrigido
Nestes casos a documentação descrevia algo diferente do que a API sempre fez. O comportamento não mudou — a referência é que passou a dizer a verdade.- Campo de antifraude com o nome errado. Era publicado em camelCase; o contrato só
aceita
antifraud_profiling_attempt_reference, em snake_case. Quem copiava o exemplo recebia400. - Obrigatoriedade errada do antifraude. Estava marcado como obrigatório nos cinco
métodos de pagamento. Só é exigido em
credit_cardethreeDs. - Objeto
pixcom nomes errados. A referência diziaexpiresAteqrCodeBase64; o real éexpirationDateeqrCode.expirationDatetambém não édate-time: vem como2026-04-29 01:30:00+00:00, com espaço. - Resposta de criar produto descrevia o serializer errado, mostrando 7 campos onde a API devolve 59.
- Listagem de checkouts documentava paginação dentro de paginação, envelope que a API nunca devolveu. O correto é um envelope só.
Adicionado
GET /public_api/fees/ — taxas e prazos da sua conta. Endpoint novo. Devolve, por
método de pagamento, o percentual e o valor fixo cobrados por venda aprovada e o prazo de
recebimento em dias, mais a tabela de juro-base do parcelamento no cartão de 1x a 18x. É a
mesma informação da tela Taxas e Prazos do painel. Escopo payments, leitura. Ver
Taxas e Prazos.- Corpo com dois campos:
paymentMethods(lista depaymentMethod,percentage,fixed,releaseDays) ecreditCardInstallments(lista deinstallments,interestPercentage). paymentMethodstraz sempre os dez métodos, na mesma ordem:pix,pix_auto,boleto,credit_card,threeDs,picpay,pagaleve,googlepay,applepay,openfinance_nubank. Método sem taxa vigente configurada vem com os três valores emnull—nullnão é zero.fixedvem como string decimal ("2.49"), epercentageeinterestPercentagecomo number em pontos percentuais (4.99é 4,99%). Não é inconsistência: é o padrão novo, explicado abaixo.409tem um único motivo nesta operação: conta sem cadastro de recebimento concluído.503é falha temporária ao consultar as taxas, e pode ser repetida com backoff.
Padrão de valores, daqui pra frente
Nada muda no que já existe. Esta seção descreve a regra que passa a valer para o que
for publicado a partir de agora, para você não ser surpreendido pela diferença.
"197.00" no POST que o
cria e 197.0 no GET seguinte. A partir de agora, o que for publicado segue uma regra
só:Dinheiro em string porque
0.1 + 0.2 não é 0.3 em ponto flutuante, e dinheiro não tolera
esse erro. Percentual não sofre disso e continua number.GET /public_api/fees/ é o primeiro endpoint no padrão: por isso fixed é string e
percentage é number no mesmo objeto.Os endpoints que já existem continuam como estão. Migrá-los muda o tipo de campos que
integrações em produção já consomem, então será feito com aviso prévio aqui, numa
entrada marcada Incompatível, com a lista completa dos campos afetados e o que fazer.
Não há data.Se você está escrevendo uma integração nova agora, o mais seguro é converter todo valor
monetário para um tipo decimal na entrada, aceitando tanto 2.49 quanto "2.49". Isso
já é boa prática para dinheiro e torna a migração um não-evento para você.Documentado
Campos e comportamentos que sempre existiram e não constavam na referência.- Cartão no enum de
paymentMethod.credit_cardethreeDssempre foram aceitos, mas a referência listava sópix,pix_autoeboleto. Os objetoscardethreeDSecuree o campoinstallmentspassaram a constar. - Pré-requisito de conta Cakto Banking. Cobrar por
pix,pix_autoouboletoexige conta aberta e ativa; cartão não exige. Ver Pré-requisitos. - Corpo entregue nos webhooks, campo a campo, incluindo o fato de
datater duas formas:checkout_abandonmentnão trazidnemstatus, e quebra handler que deduplica pordata.id. Ver Webhooks. - Respostas de erro
400,403e404em 16 operações que não as declaravam. - Campos que a referência omitia:
currencyem ofertas e produtos,idno cliente do pedido e no order bump,errorsno histórico de eventos de webhook, e mais oito campos de produto. Já vinham na resposta; agora estão descritos.