Minstrel

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:

ValorQuando cobraUso tipico
start (padrao)No inicio de cada periodo: na adesao e a cada renovacaoSaaS, clube de assinatura
endNo fim de cada periodo, pelo que foi usadoConsumo, 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

StatusSignificado
incompletePre-pago aguardando o pagamento da primeira fatura (ou o cartao)
trialingPeriodo de teste: nada e cobrado ate ele terminar
activeCobrando normalmente
past_dueHa fatura vencida; retentativa e regua em curso
pausedCobrancas suspensas ate a retomada
canceledEncerrada
incomplete_expiredA 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:

  1. gera a proxima fatura quando chega a antecedencia do plano;
  2. 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/cancel cancela 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: PATCH com { "cancelAtPeriodEnd": false }.
  • POST /v1/subscriptions/:id/pause suspende as cobrancas; faturas ja geradas para periodos que ainda nao comecaram sao canceladas.
  • POST /v1/subscriptions/:id/resume abre 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" }'
scenarioResultado de toda cobranca
aprovaAprovada
51Saldo insuficiente: reversivel, a retentativa reagenda
41Cartao perdido: irreversivel, pede cartao novo
R0Suspensao de recorrencia: a assinatura e cancelada
acaoExige 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.