Pular para o conteúdo

Planos

O plano é a oferta comercial, montada sem cliente nenhum: período, método de pagamento padrão, parcelamento máximo, fidelidade e os produtos com suas réguas de desconto. Modelo completo em Conceitos.

Rota O que faz
POST /v1/plans Cria a oferta completa num POST
GET /v1/plans Lista as ofertas, paginadas
GET /v1/plans/{planId} O plano com itens e réguas de desconto
PUT /v1/plans/{planId} Publica uma nova versão da oferta
POST /v1/plans/{planId}/archive Bloqueia assinaturas novas
Campo Tipo Descrição
id string (uuid) Identificador do plano
name string Nome do plano
version integer Versão vigente da oferta — toda edição cria uma versão nova; assinantes ficam pinados na deles
periodMonths integer Meses por ciclo — ver valores
defaultPaymentMethod enum Método padrão de quem assinar — ver valores
maxInstallments integer Parcelamento máximo no cartão (1 = à vista)
commitmentCycles integer | null Fidelidade em ciclos — só registro; a tratativa de quebra é sua. null = sem fidelidade
archivedAt datetime | null Quando foi arquivado — arquivado não aceita assinatura nova. null = ativo
createdAt datetime Quando foi criado
items[] array Produtos e réguas de desconto — presente no detalhe, criação e nova versão

Cada elemento de items[]:

Campo Tipo Descrição
productId string (uuid) Produto do catálogo
position integer Ordem do item no plano
discounts[] array Régua de desconto do produto, na ordem de prioridade

Cada regra de discounts[]:

Campo Tipo Descrição
percent integer Percentual de desconto, 1 a 100
fromCycle integer Primeiro ciclo em que a regra vale, ≥ 1 (ciclo = fatura)
toCycle integer | null Último ciclo em que a regra vale — null = desconto sem fim

Aceita apenas 1, 3, 6 ou 12. É o multiplicador do preço: cada ciclo gera uma fatura de periodMonths × preço mensal de cada produto. Um plano semestral com produto de R$ 249,90/mês fatura R$ 1.499,40 a cada 6 meses.

Valor Significado
card Cartão de crédito — o único método que aceita parcelamento
pix Pix — sempre à vista
boleto Boleto — sempre à vista

É o padrão de quem assinar; cada assinatura pode sobrescrever. O plano é agnóstico de gateway: na criação basta que algum gateway ativo da conta suporte o método e o parcelamento pedidos — senão 422 (engine.payment_method_unsupported / engine.installments_unsupported); nada é convertido por conta própria. Quem valida contra um gateway específico é a assinatura, na conexão pinada dela.

  • A cada ciclo, o motor percorre discounts[] do item na ordem da lista e aplica a primeira regra cujo intervalo fromCycletoCycle contém o ciclo. Nada empilha.
  • Ciclo = fatura, não mês. Num plano semestral, “2 ciclos com desconto” = 1 ano de desconto.
  • Desconto só existe em produto de preço fixo — produto variável já chega com o valor calculado do seu endpoint (422 se tentar).
POST /v1/plans

Headers:

Header Obrigatório Descrição
Idempotency-Key Sim Chave única sua — repetir devolve a mesma resposta

Corpo:

Campo Tipo Obrigatório Descrição
name string Sim 1–120 caracteres
periodMonths integer Sim 1, 3, 6 ou 12 — meses por ciclo
defaultPaymentMethod enum Sim card, pix ou boleto
maxInstallments integer Não 1–12, padrão 1. Independente do período: semestral à vista é válido
commitmentCycles integer Não ≥ 1. Fidelidade em ciclos — só registro
items[] array Sim 1 a 20 produtos
items[].productId uuid Sim Produto do catálogo — produto arquivado é recusado com 409
items[].discounts[] array Não Até 20 regras, na ordem de prioridade
items[].discounts[].percent integer Sim 1–100
items[].discounts[].fromCycle integer Sim ≥ 1
items[].discounts[].toCycle integer Não fromCycle — omita para desconto sem fim
Janela do terminal
curl -X POST $MOTOR/plans -H "$AUTH" -H "Idempotency-Key: plano-semestral-1" \
-H "Content-Type: application/json" -d '{
"name": "Clube Semestral",
"periodMonths": 6,
"defaultPaymentMethod": "card",
"maxInstallments": 6,
"commitmentCycles": 2,
"items": [{
"productId": "0199c1a2-…",
"discounts": [
{ "percent": 20, "fromCycle": 1, "toCycle": 2 },
{ "percent": 10, "fromCycle": 3, "toCycle": 5 }
]
}]
}'

Leitura: uma fatura a cada 6 meses de 6 × R$ 249,90, com 20% off nos 2 primeiros ciclos, 10% do 3º ao 5º, cheia depois. Cartão em até 6x. Fidelidade de 2 ciclos (= 1 ano).

Resposta 201: o objeto Plano com version: 1 e items[] completos.

Erros: 400 · 409 (produto arquivado) · 422 (desconto em produto variável; método ou parcelamento não suportado pelo gateway).

GET /v1/plans

Paginação padrão (page, pageSize). Resposta 200: { data: [Plano…], pagination }, mais recentes primeiro, sem items[] — use o detalhe para ver as réguas.

GET /v1/plans/{planId}

Resposta 200: o objeto Plano com items[] e réguas. Erros: 404.

PUT /v1/plans/{planId}

O corpo é a oferta completa de novo — mesmos campos e obrigatoriedades do criar (sem Idempotency-Key). Não é um patch: o que não vier, não existe na versão nova.

O que acontece:

  • version incrementa; a resposta é o plano na versão nova.
  • Quem já assinou segue pinado na versão que assinou — só assinaturas novas pegam a nova. Propagar condições para quem já assina é sempre uma operação explícita, nunca efeito colateral.
  • Para mudar as condições de um assinante só, use POST /v1/subscriptions/{id}/customize.

Resposta 200: o objeto Plano. Erros: 404, e os mesmos 409/422 do criar.

POST /v1/plans/{planId}/archive

Sem assinaturas novas (POST /v1/subscriptions com este plano passa a devolver 409); as existentes seguem faturando. Resposta 200: o objeto Plano com archivedAt. Erros: 404.