Skip to main content
POST
Trocar o plano da assinatura
POST /subscriptions/:id/change-plan Faz parte do recurso Assinaturas — o conceito e os dez estados estão lá. Troca o que a assinatura cobra: outro plano do catálogo em planId, ou um conjunto de itens avulsos em items. Pelo menos um dos dois — mandando os dois, planId vence e items é ignorado.

Quando a troca passa a valer

Depende do preço do destino, e é o ponto que mais surpreende quem integra. Plano mais caro vale na hora. O que resta do ciclo é acertado por rateio: uma fatura separada nasce em aberto, com o crédito do que sobrou do plano atual e o débito do novo. A fatura do período corrente não é tocada — ela já foi emitida. Plano mais barato é sempre agendado para a virada. A assinatura segue no plano atual até o fim do período, e o novo entra no ciclo seguinte. Rebaixar agora exigiria mexer numa fatura que o cliente já recebeu.
Pedir effectiveAt: "now" num plano mais barato responde 409. Não é um caso a contornar: é a regra. Omita o campo e o rebaixamento é agendado sozinho — esse é o caminho normal.effectiveAt não tem valor padrão de propósito. "now" significa “eu quero que valha agora”, e é esse pedido que a rota recusa num rebaixamento. Se houvesse padrão, todo rebaixamento responderia 409, inclusive o de quem só mandou planId.

A conta do rateio

O cálculo é por dia, e o dia corrente conta como usado. Numa troca de R100,00paraR 100,00 para R 129,90 faltando 25 dias de um ciclo de 31: netAmount traz esse total em centavos. Numa troca agendada ele é zero — não há o que cobrar hoje.
A fatura da diferença ainda não existe quando a resposta chega. O prorationInvoiceId é reservado na hora, e a fatura é gravada logo em seguida, de forma assíncrona — normalmente em 100ms a 2s.GET /invoices/{id} chamado na sequência responde 404, e o mesmo vale para o latestInvoiceId da assinatura, que aponta para ela. Escute o webhook invoice.created em vez de ler logo depois da troca.
Para ver a conta antes de confirmar, use simular a troca. Ela devolve o mesmo valor e as duas pernas separadas.
Rebaixamento que geraria crédito é recusado. Quando o rateio daria saldo a favor do cliente, a troca responde 409: crédito de assinatura ainda não existe. Como todo rebaixamento é agendado para a virada, o caso não aparece no fluxo normal.

Cortesia: trocar sem cobrar

prorationBehavior: "none" troca na hora e não cobra a diferença. Nenhuma fatura é emitida — prorationInvoiceId volta null e netAmount, zero. Serve para cortesia comercial ou para corrigir um erro seu. Só vale junto de effectiveAt: "now" — pedida numa troca agendada, a chamada responde 409.

O plano novo vale antes de a fatura ser paga

A troca é aplicada no ato. A fatura da diferença segue a régua de cobrança normal — e se ela não for paga, a troca não é desfeita. Quem entra em inadimplência é a assinatura inteira, pelo caminho de sempre. É deliberado: liberar acesso é reversível, cobrar não é. Segurar o plano novo até o pagamento cair deixaria sem o que comprou justamente quem já pagou, durante o processamento.

O destino precisa ser compatível

O contrato vigente fixa três coisas, e o plano de destino tem de respeitá-las:
  • moeda — a mesma da assinatura;
  • recorrência — mensal continua mensal; não dá para migrar de mensal para anual por aqui;
  • momento de cobrança — antecipado continua antecipado.
Qualquer divergência responde 409. Assinatura que não esteja ativa também, assim como contrato com cobrança antecipada de todos os ciclos — nele as faturas futuras já foram emitidas.
Simular recusa pelos mesmos motivos. Use change-plan/preview na tela onde o cliente escolhe o plano: o erro aparece ali, e não na hora de confirmar.

Como saber que há uma troca agendada

O campo scheduledPlanChange da assinatura traz { planId, effectiveDate } enquanto houver troca marcada, e null quando não houver. Ele aparece no GET /subscriptions/{id} e no corpo desta rota. É por ele que se sabe se vale a pena chamar o desfazer — e se ele funcionou.

Desfazer

Enquanto a troca estiver agendada, DELETE /subscriptions/:id/change-plan a apaga. Depois que ela entra em vigor, o caminho de volta é uma nova troca.

Authorizations

x-api-key
string
header
required

API Key da Credential (gerada no Backoffice)

Headers

Idempotency-Key
string

Chave única para garantir idempotência da requisição

Path Parameters

id
string
required

ID da assinatura

Body

application/json
planId
string

Plano de destino. Ausente ⇒ o destino é avulso e items é obrigatório.

Minimum string length: 1
items
object[]

Itens do destino avulso (referência ou inline). Ignorado quando há planId.

itemOverrides
object

Override de quantidade por componente do plano destino.

effectiveAt
enum<string>

Quando a troca vale. Ausente ⇒ imediata para plano mais caro, na virada para mais barato. Pedir now num plano mais barato é recusado.

Available options:
now,
period_end
prorationBehavior
enum<string>
default:create_prorations

none troca agora sem cobrar a diferença (cortesia). Só vale com effectiveAt=now.

Available options:
create_prorations,
none

Response

Plano trocado ou troca agendada para a virada