Recorrencia
Assinaturas e faturas recorrentes
Planos pre e pos-pagos, ciclo de vida da assinatura, geracao de faturas, troca de cartao, pausa, cancelamento e fatura avulsa.
A recorrencia do Minstrel separa tres coisas que costumam vir misturadas:
- plano: o preco e o ritmo ("R$ 149,90 por mes, cobrado no inicio");
- assinatura: o contrato de um cliente com um plano;
- fatura: a intencao de cobrar um ciclo. E ela que e cobrada, retentada e avisada pela regua - nunca a assinatura direto.
Momento da cobranca
Cada plano define billingTiming:
| Valor | Quando cobra | Uso tipico |
|---|---|---|
start (padrao) | No inicio de cada periodo: na adesao e a cada renovacao | SaaS, clube de assinatura |
end | No fim de cada periodo, pelo que foi usado | Consumo, servico pos-pago |
curl https://api.minstrel.com.br/v1/plans \
-H "Authorization: Bearer $MINSTREL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"productId": "prod_01HQ...",
"name": "Mensal",
"amount": 14990,
"interval": "month",
"billingTiming": "start",
"trialDays": 7,
"invoiceLeadDays": 3
}'
invoiceLeadDays antecipa a geracao da fatura (nao a cobranca): a fatura
nasce 3 dias antes do vencimento para a regua avisar o cliente antes de
cobrar.
Ciclo de vida
| Status | Significado |
|---|---|
incomplete | Pre-pago aguardando o pagamento da primeira fatura (ou o cartao) |
trialing | Periodo de teste: nada e cobrado ate ele terminar |
active | Cobrando normalmente |
past_due | Ha fatura vencida; retentativa e regua em curso |
paused | Cobrancas suspensas ate a retomada |
canceled | Encerrada |
incomplete_expired | A primeira fatura nao foi paga ate o fim do primeiro periodo |
No pre-pago, a assinatura so fica active quando a primeira fatura e paga.
Ativar antes daria acesso a quem nao pagou - e a recusa no primeiro pagamento
(cartao digitado errado, sem limite) e a mais comum de todas. O evento
subscription.activated marca esse momento: use-o para liberar o acesso.
Criar uma assinatura
curl https://api.minstrel.com.br/v1/subscriptions \
-H "Authorization: Bearer $MINSTREL_API_KEY" \
-H "Idempotency-Key: assinatura-cliente-1234" \
-H "Content-Type: application/json" \
-d '{ "customerId": "cus_01HQ...", "planId": "plan_01HQ..." }'
Num plano pre-pago sem teste, a resposta ja traz a primeira fatura e o resultado da cobranca:
{
"id": "sub_01M4...",
"status": "active",
"latestInvoice": { "number": "2026-000123", "status": "paid", "total": 14990 },
"firstCharge": { "outcome": "paid", "detail": "Fatura paga." }
}
A primeira cobranca vai como transacao com o cliente presente (CIT), que e o
que o emissor espera no inicio de uma recorrencia; as seguintes vao como MIT
recorrente. Com recusa, a assinatura fica incomplete e a fatura segue a
politica de retentativa.
Geracao e virada de periodo
O worker de recorrencia faz duas coisas separadas, nessa ordem:
- gera a proxima fatura quando chega a antecedencia do plano;
- vira o periodo quando o atual termina - ou encerra a assinatura, se havia cancelamento agendado ou se o ultimo ciclo contratado acabou.
Separar os dois garante que "periodo atual" nunca aponte para o futuro e que um worker parado por dias recupere ciclo a ciclo, sem pular nenhuma fatura. Cada ciclo e faturado uma unica vez: o banco impede duas faturas para o mesmo ciclo, e uma fatura cancelada pelo operador conta como tratada.
GET /v1/subscriptions/:id devolve upcoming, o cronograma das proximas
cobrancas com data de geracao, vencimento e valor. Para antecipar a proxima
fatura manualmente, use POST /v1/subscriptions/:id/renew.
Valor proporcional
Com dia fixo de cobranca (billingDay), o primeiro periodo e mais curto que o
intervalo - adesao em 25/03 num plano que cobra todo dia 10 gera um periodo de
16 dias. A fatura desse periodo e proporcional, arredondada a favor do
cliente, e o item descreve a conta: Mensal - ciclo 1 (proporcional: 16 de 31 dias). O mesmo vale para a retomada de uma assinatura pausada.
Trocar o cartao
curl -X PATCH https://api.minstrel.com.br/v1/subscriptions/sub_01M4... \
-H "Authorization: Bearer $MINSTREL_API_KEY" \
-d '{ "paymentMethodId": "pm_01M4..." }'
As faturas vencidas e nao pagas voltam para a fila de cobranca na hora
(rescheduledInvoices na resposta informa quantas) - a causa mais comum de
atraso e justamente o cartao. O status da assinatura muda quando a fatura for
paga, nao antes: trocar o cartao nao quita a divida.
Cancelar, pausar e retomar
POST /v1/subscriptions/:id/cancelcancela ao fim do periodo por padrao: o cliente pagou pelo periodo inteiro, e cortar no meio gera contestacao. Envie{ "atPeriodEnd": false }para encerrar na hora. Para desfazer um cancelamento agendado:PATCHcom{ "cancelAtPeriodEnd": false }.POST /v1/subscriptions/:id/pausesuspende as cobrancas; faturas ja geradas para periodos que ainda nao comecaram sao canceladas.POST /v1/subscriptions/:id/resumeabre um ciclo novo a partir de agora, em vez de cobrar o periodo em que o cliente ficou sem acesso.
Assinatura cancelada pelo emissor (Visa R0/R1/R3, Mastercard MAC 21) nao pode ser reativada com o mesmo cartao: crie uma nova com outro meio de pagamento.
Baixa manual
Dinheiro que entrou por fora (Pix direto na conta, deposito, acordo) e registrado na fatura sem criar transacao:
curl https://api.minstrel.com.br/v1/invoices/inv_01M4.../mark-paid \
-H "Authorization: Bearer $MINSTREL_API_KEY" \
-H "Idempotency-Key: baixa-2026-000123" \
-d '{ "note": "Pix recebido direto na conta em 14/10" }'
A fatura fica paid com paidOutOfBand: true e a nota informada, e a
assinatura e reativada como numa cobranca aprovada. Faturas em processamento
recusam a baixa: uma cobranca em voo pode ser aprovada a qualquer momento. Se
havia um link de pagamento ativo, ele e cancelado
na mesma hora (cancelReason: "invoice_paid"): o cliente nao paga duas vezes.
Fatura avulsa
POST /v1/invoices cria uma fatura sem assinatura - implantacao, servico
extra, acordo de divida. Ela nao e cobrada sozinha: sem acordo de
recorrencia, cobrar o cartao salvo do cliente por iniciativa da loja (MIT) e o
tipo de cobranca que o emissor recusa ou que vira contestacao. A fatura nasce
com nextAttemptAt: null e fica fora da fila do cobrador; o vencimento serve
para a regua e para marcar atraso.
Para receber:
- envie um link de pagamento: o cliente paga na pagina do parceiro, com cartao, Pix ou boleto, numa transacao iniciada por ele (CIT);
- ou, com o cliente no seu checkout agora, cobre o cartao salvo dele marcando a presenca:
curl https://api.minstrel.com.br/v1/invoices/inv_01M4.../charge \
-H "Authorization: Bearer $MINSTREL_API_KEY" \
-H "Idempotency-Key: cobranca-2026-000123" \
-H "Content-Type: application/json" \
-d '{ "customerPresent": true }'
Sem customerPresent: true, a fatura avulsa responde 409
(invoice_not_payable), com o caminho do link em meta.paymentLinks. A recusa
de uma cobranca avulsa nao agenda retentativa (noRetryReason: "standalone_invoice"): quem tenta de novo e o cliente, e a fatura segue em
aberto.
Na fatura de assinatura, POST /v1/invoices/:id/charge continua igual: cobra o
cartao salvo como MIT recorrente, e a recusa segue a
politica de retentativa.
Testar no sandbox
Gere um cartao de teste com resultado fixo e assine um plano com ele:
curl https://api.minstrel.com.br/v1/customers/cus_01HQ.../payment-methods/test-card \
-H "Authorization: Bearer $MINSTREL_API_KEY" \
-d '{ "scenario": "51", "brand": "visa" }'
scenario | Resultado de toda cobranca |
|---|---|
aprova | Aprovada |
51 | Saldo insuficiente: reversivel, a retentativa reagenda |
41 | Cartao perdido: irreversivel, pede cartao novo |
R0 | Suspensao de recorrencia: a assinatura e cancelada |
acao | Exige autenticacao 3DS |
O cartao de teste so existe no sandbox e, como todo cartao no Minstrel, e um token: numero e CVV nunca trafegam pela API.
Indicadores
GET /v1/billing/summary devolve MRR, ARR, ticket medio, churn de 30 dias,
assinaturas por status e faturas em aberto, vencidas, a vencer em 7 dias e
pagas no mes. O MRR conta assinaturas active e past_due pelo valor
negociado de cada uma, convertido para mes.