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.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.