Assinaturas
A assinatura vincula um cliente final a um plano. A partir daí o motor gera as faturas sozinho, a cada ciclo. Modelo completo em Conceitos.
| Rota | O que faz |
|---|---|
POST /v1/subscriptions |
Vincula um cliente (criado ou reaproveitado) ao plano |
GET /v1/subscriptions |
Lista as assinaturas, paginadas |
GET /v1/subscriptions/{subscriptionId} |
Uma assinatura pelo id |
GET /v1/subscriptions/{subscriptionId}/preview |
Dry-run da próxima fatura |
POST /v1/subscriptions/{subscriptionId}/customize |
Condição negociada só para esta assinatura |
POST /v1/subscriptions/{subscriptionId}/cancel |
Encerra, devolvendo o estado da fidelidade |
O objeto Assinatura
Seção intitulada “O objeto Assinatura”| Campo | Tipo | Descrição |
|---|---|---|
id |
string (uuid) | Identificador da assinatura |
planId |
string (uuid) | Plano atribuído |
planVersion |
integer | Versão do plano pinada na adesão — edições do plano base não mexem aqui |
customized |
boolean | true quando a assinatura roda uma versão própria |
customer |
object | Cliente final — ver abaixo |
status |
enum | active ou canceled — ver valores |
chargeDay |
integer | Dia do vencimento das faturas, 1 a 28 |
paymentMethod |
enum | Método efetivo desta assinatura: card, pix ou boleto |
paymentMethodSource |
enum | De onde o método veio — ver valores |
gatewayConnectionId |
uuid | null | Conexão de gateway pela qual esta assinatura fatura — congelada na criação. null em assinatura anterior ao recurso (emite pelo comportamento antigo) |
cycleCount |
integer | Faturas já geradas para esta assinatura (incrementa na geração, não no pagamento) |
commitmentCycles |
integer | null | Fidelidade congelada na adesão — mudar o plano depois não mexe aqui. Só registro |
nextDueDate |
string (date) | Vencimento da próxima fatura, YYYY-MM-DD |
startedAt |
datetime | Quando a assinatura começou |
canceledAt |
datetime | null | Quando foi cancelada — null enquanto ativa |
O objeto customer:
| Campo | Tipo | Descrição |
|---|---|---|
customer.id |
string (uuid) | O identificador do cliente no motor |
customer.externalRef |
string | O identificador do cliente no seu sistema — é ele que devolvemos em webhooks e no endpoint de preço |
customer.name |
string | Nome do cliente final |
customer.email |
string | E-mail do cliente final |
O enum status
Seção intitulada “O enum status”| Valor | Significado |
|---|---|
active |
Faturando — uma fatura nova nasce a cada ciclo |
canceled |
Encerrada — nenhuma fatura nova; a do ciclo corrente segue o fluxo |
O enum paymentMethodSource
Seção intitulada “O enum paymentMethodSource”| Valor | Significado |
|---|---|
plan_default |
Herdou o defaultPaymentMethod do plano |
override |
Método foi sobrescrito na criação da assinatura |
Criar assinatura
Seção intitulada “Criar assinatura”POST /v1/subscriptionsCria (ou reaproveita, pelo externalRef) o cliente final e o vincula ao plano. A primeira fatura nasce no próximo ciclo de geração.
Headers:
| Header | Obrigatório | Descrição |
|---|---|---|
Idempotency-Key |
Sim | Chave única sua — repetir devolve a mesma resposta |
Corpo:
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
planId |
uuid | Sim | Plano a atribuir — arquivado devolve 409 |
customer |
object | Sim | Cliente final, inline |
customer.externalRef |
string | Sim | 1–120. O id do cliente no seu sistema — se já existe um cliente com este ref, ele é reusado |
customer.name |
string | Sim | 1–200 caracteres |
customer.email |
string | Sim | E-mail válido |
customer.document |
string | Não | CPF/CNPJ (11–18 caracteres) — alguns gateways exigem para emitir |
paymentMethod |
enum | Não | card, pix ou boleto — sobrescreve o padrão do plano só nesta assinatura. Omitido, herda o plano |
chargeDay |
integer | Não | 1–28. Dia do vencimento. Omitido: o dia da criação, travado em 28 (criou dia 29/30/31 → vira 28) |
firstChargeDate |
string | Não | YYYY-MM-DD, hoje ou futura — adia a primeira fatura. Sem chargeDay junto, o dia dela vira a âncora dos próximos ciclos |
gatewayConnectionId |
uuid | Depende | Em qual gateway esta assinatura fatura — ver a regra |
curl -X POST $MOTOR/subscriptions -H "$AUTH" -H "Idempotency-Key: sub-4512-1" \ -H "Content-Type: application/json" -d '{ "planId": "0199c1a8-…", "customer": { "externalRef": "cliente-4512", "name": "Ana Beatriz Sales", "email": "[email protected]" }, "chargeDay": 10 }'Resposta 201 — o objeto Assinatura:
{ "id": "0199c1b0-…", "planId": "0199c1a8-…", "planVersion": 1, "customized": false, "customer": { "id": "…", "externalRef": "cliente-4512", "name": "Ana Beatriz Sales", }, "status": "active", "chargeDay": 10, "paymentMethod": "card", "paymentMethodSource": "plan_default", "gatewayConnectionId": "0199d1…", "cycleCount": 0, "commitmentCycles": 2, "nextDueDate": "2026-09-10", "startedAt": "2026-08-29T18:20:11.000Z", "canceledAt": null}A escolha do gateway
Seção intitulada “A escolha do gateway”A conexão de gateway é congelada na criação — é ela que emite todas as faturas desta assinatura:
-
Uma conexão emissível ativa: omita
gatewayConnectionId— ela é usada sozinha. -
Duas ou mais: o campo é obrigatório. Omitido, a resposta é
422 engine.gateway_choice_required, com as opções nometa:{"type": "engine.gateway_choice_required","status": 422,"detail": "Esta conta tem mais de um gateway ativo — informe gatewayConnectionId na criação da assinatura. As opções estão em GET /v1/integration.","meta": {"options": [{ "connectionId": "0199d1…", "provider": "vindi" },{ "connectionId": "0199d2…", "provider": "stripe" }]}} -
Os ids vivem em
GET /v1/integration, no arraygateways[]— junto com os métodos e o parcelamento que cada conexão emite. -
Id inexistente ou de conexão inativa:
422 engine.gateway_connection_not_found. -
Conexão que não emite cobrança (ex.: gateway só de Recuperação) não conta como opção nem força escolha.
Método e parcelamento são validados contra a conexão pinada — o mesmo vale para o customize.
Erros: 400 · 404 (plano não existe) · 409 (plano arquivado) · 422 (engine.gateway_choice_required, engine.gateway_connection_not_found, ou método/parcelamento que a conexão pinada não suporta).
Listar assinaturas
Seção intitulada “Listar assinaturas”GET /v1/subscriptionsPaginação padrão (page, pageSize). Resposta 200: { data: [Assinatura…], pagination }, com cliente, plano e ciclo em cada item.
Detalhar assinatura
Seção intitulada “Detalhar assinatura”GET /v1/subscriptions/{subscriptionId}Resposta 200: o objeto Assinatura. Erros: 404.
Simular a próxima fatura (preview)
Seção intitulada “Simular a próxima fatura (preview)”GET /v1/subscriptions/{subscriptionId}/previewRoda a mesma decisão pura da geração real — régua do ciclo seguinte, itens e parcelamento — e devolve a fatura simulada. Zero efeitos: nada é gravado, emitido ou consumido. Use para conferir régua e parcelas antes do primeiro ciclo, ou depois de um customize.
Resposta 200:
| Campo | Tipo | Descrição |
|---|---|---|
subscriptionId |
string (uuid) | Assinatura simulada |
cycle |
integer | O ciclo que seria cobrado (o próximo) |
dueDate |
string (date) | Vencimento da fatura simulada |
paymentMethod |
string | Método efetivo: o override da assinatura ou o padrão do plano |
installments |
integer | null | Parcelas no cartão — null quando à vista ou método não-cartão |
fixedTotalCents |
integer | Soma dos itens de preço fixo, em centavos — itens variáveis entram como zero |
hasPendingItems |
boolean | true quando há item variável: o total final depende do seu endpoint de preço |
items[] |
array | Itens exatamente como a geração real os montaria |
Cada elemento de items[]:
| Campo | Tipo | Descrição |
|---|---|---|
productId |
string (uuid) | Produto do item |
productName |
string | Nome que iria para a fatura |
pricingSource |
string | table (preço fixo) ou endpoint (variável) |
pricingStatus |
string | priced (valor fechado) ou pending (aguarda o pull) |
monthlyPriceCents |
integer | null | Preço mensal de tabela — null em item variável |
months |
integer | Meses do período multiplicando o mensal |
discountPercent |
number | null | Desconto da régua que casa com este ciclo — null = sem desconto |
amountCents |
integer | null | Valor do item — null em item variável |
note |
string | null | Como o valor variável seria resolvido na geração real |
Erros: 404 · 409 (assinatura cancelada não tem próxima fatura).
Condição individual (customize)
Seção intitulada “Condição individual (customize)”POST /v1/subscriptions/{subscriptionId}/customizeClona o plano numa versão própria desta assinatura, com os termos informados, e re-pina só ela — o plano base e os demais assinantes não mudam. Vale a partir do próximo ciclo. Depois disso, customized: true.
O corpo é a condição completa (mesma semântica de criar plano, sem name):
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
periodMonths |
integer | Sim | 1, 3, 6 ou 12 |
defaultPaymentMethod |
enum | Sim | card, pix ou boleto |
maxInstallments |
integer | Não | 1–12, padrão 1 |
commitmentCycles |
integer | Não | ≥ 1 — só registro |
items[] |
array | Sim | Itens e réguas, com a mesma forma e regras de resolução do plano |
Resposta 200: o objeto Assinatura já na versão própria. Erros: 404, e os mesmos 409/422 de validação de plano.
Cancelar assinatura
Seção intitulada “Cancelar assinatura”POST /v1/subscriptions/{subscriptionId}/cancelEncerra de vez: a fatura do ciclo corrente segue o fluxo normal, nenhuma nova é gerada. Não há pausa nem reativação.
Resposta 200: o objeto Assinatura com status: "canceled" e canceledAt, mais o bloco commitment com o estado da fidelidade — o motor registra, não julga:
| Campo | Tipo | Descrição |
|---|---|---|
commitment.cycles |
integer | null | Ciclos de fidelidade combinados na adesão — null = sem fidelidade |
commitment.completed |
integer | Ciclos efetivamente faturados até o cancelamento |
commitment.fulfilled |
boolean | true quando o compromisso foi cumprido — a tratativa de quebra é sua |
Erros: 404 · 409 (já cancelada).