Pular para o conteúdo principal
Esta página é conceitual: explica como o motor de recorrência decide quando cada fatura nasce e quando ela é cobrada. Os campos citados aqui são os mesmos que você envia ao criar uma assinatura — veja Assinaturas para o request completo e Faturas para o ciclo de vida de cada fatura.
Todas as datas internas do motor são normalizadas em UTC. O cálculo de ciclo é determinístico: depende apenas da data de início e da regra de recorrência (recurrence), sem relógio externo. Em transport (body/query), datas sempre viajam em ISO 8601 com offset — veja Convenções.

A regra de recorrência

Cada assinatura tem uma recurrence (herdada do preço do plano ou informada inline). Ela é o que define o tamanho do ciclo e o ponto de alinhamento das faturas.
interval
integer
obrigatório
Multiplicador da unidade. Inteiro positivo. Ex.: interval=3 + unit=month → a cada 3 meses.
unit
string
obrigatório
Unidade do ciclo. Um de: day, week, month, year.
anchor
string
obrigatório
Como o ciclo se alinha a um ponto de referência. Um de: subscription_start, day_of_month, end_of_month. Detalhado abaixo.
anchorDay
integer
Obrigatório quando anchor='day_of_month'. Dia do mês, faixa de 1 a 31. Ignorado nas outras âncoras.
collectionTiming
string
padrão:"prepaid"
Quando cobrar dentro do ciclo: prepaid (início) ou postpaid (fim). Detalhado em Prepaid vs Postpaid.
As âncoras day_of_month e end_of_month só fazem sentido com unit='month' ou unit='year'. Combiná-las com day/week é rejeitado na validação (“a cada 1 dia, todo dia 15” não tem semântica).

Âncoras

A âncora decide em que data cai o fim do ciclo atual — que é também o início do próximo ciclo e, por padrão, a data da próxima fatura.
O próximo ciclo é simplesmente início + intervalo. Preserva o horário (hora/min/seg) da data de início.Exemplo (unit=month, interval=1, início em 15/jan/2026 10:00):
CicloInícioFim (= próxima fatura)
115/jan 10:0015/fev 10:00
215/fev 10:0015/mar 10:00
315/mar 10:0015/abr 10:00
Para meses curtos vale o clamp de fim de mês (veja abaixo): início em 31/jan → próximo fim em 28/fev (ou 29/fev em ano bissexto). Diferente do day_of_month, o subscription_start não re-ancora no dia original: cada passo avança a partir do fim do ciclo anterior (já clampado), então depois de 28/fev o ciclo seguinte é 28/mar, depois 28/abr — o dia “encolhe” para o menor mês atravessado e não volta a 31.
Cobra sempre no dia anchorDay. A primeira fatura recorrente cai ao menos um intervalo à frente — nunca no mês corrente da assinatura. Isso evita ciclos curtos no arranque.Exemplo (unit=month, interval=1, anchorDay=10):
Início da assinaturaFim do 1º ciclo (1ª fatura recorrente)
05/abr10/mai
19/abr10/mai
10/abr (já no dia da âncora)10/mai
Ou seja: compra dia 5 com âncora no dia 10 não cobra no dia 10 do mesmo mês — vai para o mês seguinte.
Se anchorDay for maior que o número de dias do mês alvo, o motor ajusta para o último dia do mês (compatível com Stripe). anchorDay=31 em fevereiro vira 28/fev (ou 29/fev em ano bissexto). E como o alinhamento re-ancora no dia original a cada passo, não há drift: depois de 28/fev (31 clampado), o ciclo seguinte volta para 31/mar.
Cobra sempre no último dia de cada mês do ciclo, qualquer que seja seu tamanho.Exemplo (unit=month, interval=1, início em 10/jan):
CicloFim (= próxima fatura)
128/fev (ou 29/fev bissexto)
231/mar
330/abr
Assim como day_of_month, a primeira fatura recorrente cai um intervalo à frente, nunca no mês de início.
O horário (hora/minuto/segundo) da data de início é preservado ao avançar os ciclos. O clamp só mexe no dia, nunca no relógio.

Prepaid vs Postpaid

collectionTiming define onde, dentro do ciclo, a cobrança acontece.

prepaid (padrão)

Cobra no início de cada período. É o modelo clássico de SaaS/streaming: você paga pelo período que está começando.

postpaid

Cobra no fim de cada período. Modelo de consumo/utility: você paga pelo período que já passou.
No request de criação de assinatura há dois lugares que tratam timing:
  • collectionTiming no nível da assinatura — prepaid (default) ou postpaid.
  • collectionTiming dentro da própria recurrence — quando ausente, assume prepaid (retrocompatibilidade com preços antigos que não tinham o campo).
Ausência do campo sempre significa prepaid. Se você não definir nada, suas assinaturas cobram no início do ciclo.

Geração das faturas: just_in_time vs upfront

invoiceGenerationMode controla quantas faturas são criadas e quando.
ModoQuando as faturas nascemPara que serve
just_in_time (padrão)1 fatura por ciclo, gerada pelo agendador a cada viradaAssinaturas “infinitas” (SaaS/streaming) e contratos sem necessidade de ver ciclos futuros
upfrontTodas as maxCycles faturas no momento da criação, cada uma com dueAt distintoContratos finitos de prazo fixo (EAD, parcelamento) onde o lojista quer previsibilidade de fluxo de caixa
invoiceGenerationMode='upfront' exige maxCycles informado (não pode ser nulo). Sem ele, a criação da assinatura é rejeitada na validação.
Em just_in_time, o número total de ciclos é limitado por maxCycles (quando informado); sem maxCycles, a assinatura é considerada perpétua e o agendador continua gerando uma fatura por ciclo indefinidamente.

Trial (período de teste)

trialSpec define um período inicial sem cobrança.
trialSpec.durationDays
integer
Duração do trial em dias. Inteiro >= 0.
trialSpec.requiresPaymentMethod
boolean
Se o trial exige meio de pagamento anexado para começar.
Durante o trial a assinatura fica no status trialing e nenhuma fatura é cobrada. Ao final do trial, o motor gera a primeira fatura e a assinatura entra em cobrança normal.
trialSpec e bootstrapPayment são mutuamente exclusivos. Trial implica que o ciclo 1 ainda não foi cobrado (é o fim do trial que gera a 1ª fatura); bootstrapPayment significa que o ciclo 1 já foi pago externamente. Enviar os dois juntos é rejeitado.
O trialSpec no nível da assinatura tem precedência sobre o trial derivado de itens baseados em plano (que vem do preço). Use o override no nível da assinatura quando o trial é decidido fora do plano — por exemplo, checkout inline com itens sem preço associado.

chargeLeadTimeDays — antecedência da cobrança

chargeLeadTimeDays é a antecedência, em dias, entre o momento em que a fatura é disparada para cobrança (chargeAt — quando a fatura abre e o boleto/PIX é criado no PSP) e o seu vencimento (dueAt):
chargeAt = dueAt − chargeLeadTimeDays
chargeLeadTimeDays
integer
Faixa aceita: 0 a 30 dias. Quando omitido, deriva automaticamente do tipo do meio de pagamento padrão (defaultPaymentMethodRef.type).
Os defaults derivados por tipo de meio de pagamento:
Meio de pagamentoLead time padrãoPor quê
card0 diasCobrança instantânea
pix1 diaTempo de enviar o QR Code ao cliente
boleto2 diasTempo da rede bancária registrar o boleto
other0 diasSem antecedência
A regra de resolução é: valor explícito vence sempre; senão, deriva do tipo do meio de pagamento; se não houver nenhum dos dois, o padrão é 0. Persistido na assinatura como chargeLeadTimeDays.
Exemplo: uma fatura de boleto que vence em 20/jun (dueAt), com lead time 2, é disparada para cobrança em 18/jun (chargeAt) — dando 2 dias para o boleto circular antes do vencimento.

Dunning — o que acontece quando a cobrança falha

Quando uma cobrança recorrente falha, o motor entra em dunning (régua de inadimplência): ele decide se reagenda uma nova tentativa ou se esgota as tentativas e aplica a política final. O comportamento é configurável por lojista via BillingSettings.

Configuração (BillingSettings)

CampoDefaultFaixa / valoresSignificado
retryIntervalsDays[3, 5, 7]array de inteiros >= 0 (até 10)Espera, em dias, antes de cada retentativa. O índice extrapolado reusa o último intervalo
maxRetries30 a 10Número máximo de retentativas antes de esgotar
dunningFinalPolicymark_unpaidmark_unpaid ou cancelO que fazer ao esgotar o dunning
hardDeclineCategories['hard_decline', 'authentication_required']subconjunto de soft_decline, hard_decline, insufficient_funds, authentication_required, otherCategorias de falha que pulam o retry e vão direto para a política final

Como a régua funciona

A contagem segue o modelo do Stripe: a tentativa nº 1 é a cobrança inicial; as retentativas começam em 2. Logo, retryCountSoFar = attemptNumber − 1.
1

Cobrança falha

A fatura sai de open e vai para past_due. A tentativa é registrada como failed com a categoria de falha.
2

Ainda há retentativas?

Se retryCountSoFar < maxRetries e a falha não é hard decline, o motor agenda a próxima tentativa: nextRetryAt = momento da falha + retryIntervalsDays[índice]. A assinatura permanece ativa e a fatura segue em past_due.
3

Dunning esgotado

Esgota quando retryCountSoFar >= maxRetries ou a falha cai em uma categoria de hardDeclineCategories (que pula o retry de imediato). Aí nextRetryAt fica nulo e a política final é aplicada.
4

Política final

Com dunningFinalPolicy = mark_unpaid (default), a assinatura é marcada como unpaid. Com cancel, a assinatura é cancelada automaticamente.
A transição padrão da assinatura quando a cobrança falha é active/cobrando → past_due (em retentativa) → unpaid (dunning esgotado com política mark_unpaid). Com a política cancel, o desfecho final é canceled em vez de unpaid.
Exemplo concreto (defaults: retryIntervalsDays=[3,5,7], maxRetries=3, dunningFinalPolicy=mark_unpaid), cobrança inicial falhando em 01/jun:
TentativaattemptNumberretryCountSoFarDataResultado
Inicial1001/junFalha → past_due, agenda retry +3d
Retry 12104/junFalha → agenda retry +5d
Retry 23209/junFalha → agenda retry +7d
Retry 34316/junFalha → retryCountSoFar (3) >= maxRetries (3): esgotado → assinatura vira unpaid
Faturas de adesão (kind=enrollment) não entram em dunning: a falha é terminal, sem retentativa. A fatura sai de open para past_due (para não ser recobrada de hora em hora) e a trilha de adesão decide o cancelamento/encerramento da assinatura.
Para os status detalhados da assinatura (incomplete, trialing, active, past_due, unpaid, paused, canceled, completed) veja Assinaturas. Para os códigos de erro de chamadas à API veja Erros.

Veja também

Assinaturas

Criar e gerenciar assinaturas — request completo com recurrence, trialSpec, collectionTiming e demais campos.

Planos e preços

De onde a recurrence é herdada quando a assinatura é baseada em plano.

Faturas

Ciclo de vida de cada fatura — open, past_due, paid e os campos chargeAt/dueAt.

Visão geral de assinaturas

Conceitos do módulo de recorrência da Z2Pay.