Pular para o conteúdo

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}/gateway Re-pina a assinatura em outra conexão de gateway
POST /v1/subscriptions/{subscriptionId}/cancel Encerra, devolvendo o estado da fidelidade
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
expirationDays integer Prazo de vencimento efetivo desta assinatura, em dias após a geração — vira o paymentDueDate de cada fatura
expirationDaysSource enum De onde o prazo veio: plan_default ou overridemesma semântica do método
gatewayConnectionId uuid | null Conexão de gateway pela qual esta assinatura fatura — congelada na criação, trocável depois. 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 (o resumo — documento, telefone e endereço vivem em Clientes):

Campo Tipo Descrição
customer.id string (uuid) O identificador do cliente no motor — use-o em PATCH /v1/customers/{id} para corrigir os dados
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
Valor Significado
active Faturando — uma fatura nova nasce a cada ciclo
canceled Encerrada — nenhuma fatura nova; a do ciclo corrente segue o fluxo
Valor Significado
plan_default Herdou o defaultPaymentMethod do plano
override Método foi sobrescrito na criação da assinatura
POST /v1/subscriptions

Cria (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 com os dados que já tem (para corrigir, edite o cliente)
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
customer.phone string Não Telefone com DDD, só dígitos (ex.: 5511999998888) — a pagar.me exige para emitir pix
customer.address object Não Endereço do cliente — a pagar.me exige para emitir boleto. Campos abaixo
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
expirationDays integer Não 0–90. Sobrescreve o prazo de vencimento do plano só nesta assinatura. Omitido, herda o plano
gatewayConnectionId uuid Depende Em qual gateway esta assinatura fatura — ver a regra

O objeto customer.address (todos obrigatórios quando o endereço vem):

Campo Tipo Descrição
address.line string Logradouro com número (ex.: Rua das Videiras, 52)
address.zipCode string CEP, 8 dígitos
address.city string Cidade
address.state string UF (ex.: SP)
Janela do terminal
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": "ana@exemplo.com.br"
},
"chargeDay": 10
}'

Resposta 201 — o objeto Assinatura:

{
"id": "0199c1b0-…",
"planId": "0199c1a8-…",
"planVersion": 1,
"customized": false,
"customer": {
"id": "",
"externalRef": "cliente-4512",
"name": "Ana Beatriz Sales",
"email": "ana@exemplo.com.br"
},
"status": "active",
"chargeDay": 10,
"paymentMethod": "card",
"paymentMethodSource": "plan_default",
"expirationDays": 0,
"expirationDaysSource": "plan_default",
"gatewayConnectionId": "0199d1…",
"cycleCount": 0,
"commitmentCycles": 2,
"nextDueDate": "2026-09-10",
"startedAt": "2026-08-29T18:20:11.000Z",
"canceledAt": null
}

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 no meta:

    {
    "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 array gateways[] — 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).

GET /v1/subscriptions

Paginação padrão (page, pageSize). Resposta 200: { data: [Assinatura…], pagination }, com cliente, plano e ciclo em cada item.

GET /v1/subscriptions/{subscriptionId}

Resposta 200: o objeto Assinatura. Erros: 404.

GET /v1/subscriptions/{subscriptionId}/preview

Roda 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) Data do ciclo da fatura simulada (o chargeDay)
paymentDueDate string (date) Vencimento da cobrança simulada — dueDate + expirationDays
expirationDays integer Prazo efetivo que a geração usaria
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).

POST /v1/subscriptions/{subscriptionId}/customize

Clona 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
expirationDays integer Não 0–90, padrão 0 — prazo de vencimento da condição nova
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.

POST /v1/subscriptions/{subscriptionId}/gateway

Re-pina a assinatura em outra conexão, valendo do próximo ciclo — faturas já emitidas ficam onde nasceram, ciclos e fidelidade seguem intactos. Método e parcelamento da assinatura são validados contra a conexão nova.

Corpo:

Campo Tipo Obrigatório Descrição
gatewayConnectionId uuid Sim A conexão nova — as opções estão em GET /v1/integration
externalCustomerId string Não 1–120. De-para opcional: o id deste cliente no gateway novo, quando ele foi importado pela portabilidade de cofre

O que acontece com o cliente no gateway novo:

  • Sem externalCustomerId: o motor cria o cliente lá com os dados que guarda, antes da próxima fatura — o espelho chega aquecido na geração.
  • Com externalCustomerId: o motor aponta o espelho para o cliente já existente — o caso de cartão, em que o cliente foi importado pela portabilidade de cofre entre gateways. O de-para em lote vive em GET /v1/integration/migration-map.
Janela do terminal
curl -X POST $MOTOR/subscriptions/0199c1b0-…/gateway -H "$AUTH" \
-H "Content-Type: application/json" \
-d '{ "gatewayConnectionId": "0199d2…" }'

Resposta 200: o objeto Assinatura já na conexão nova. Erros: 404 · 409 (assinatura cancelada não muda de gateway) · 422 (conexão inexistente/inativa, ou método/parcelamento que ela não suporta).

POST /v1/subscriptions/{subscriptionId}/cancel

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