Troca de plano
Escopo write. Troca a oferta de uma assinatura.
curl -X POST "https://api.ribbo.app/v1/subscriptions/sub_01J…/change-plan" \
-H "Authorization: Bearer bk_..." -H "Content-Type: application/json" \
-d '{ "offer_id": "offer_01KZ9R...", "keep_coupon": true }'
- Mesmo ciclo, mais caro (upgrade): entra na hora, com proração cobrada no cartão salvo. Se a proração fica abaixo do mínimo do gateway (Stripe R$ 0,50, Asaas R$ 5,00), a troca é aplicada sem cobrar.
- Mesmo ciclo, mesmo preço: troca na hora, sem cobrança.
- Mesmo ciclo, mais barato (downgrade): agendado para o fim do período atual.
- Troca de ciclo (mensal↔anual): vale o preço por ano (mensal x 12). Se o novo plano custa mais por ano, a troca é na hora: de mensal para anual cobra o anual menos o crédito do período que sobra; de anual para mensal o crédito vira tempo. Se custa o mesmo ou menos por ano, é agendada para o fim do período.
- Oferta de outro gateway: o cartão salvo não atravessa gateways, então a troca vira um link de
pagamento no gateway novo (evento
subscription.migration_link_issuedquando é agendada). - Só assinaturas
activeoutrialingtrocam de plano. keep_coupon(opcional): leva o cupom ativo para a nova oferta (não vale com troca de gateway).
Resposta 200 { "subscription": {...}, "plan_change": {...} }. Sem offer_id → 400;
regra de negócio inválida → 422 {"error":"..."}.
A troca agendada aparece em pending_offer (offer_id, plan_id, plan_name, interval,
amount_cents, effective_at) no payload da assinatura e no webhook
subscription.plan_change_scheduled. Quando entra em vigor, chega subscription.plan_changed.
Cancelar troca agendada
curl -X POST "https://api.ribbo.app/v1/subscriptions/sub_01J…/cancel-plan-change" -H "Authorization: Bearer bk_..."
422 se não houver troca agendada. Emite subscription.plan_change_canceled.