Aller au contenu

Troca a opção de plano da assinatura

POST/api/subscriptions/{id}/change-tier

Auth
Jeton requis
Clé d’API:
Clé d’API non acceptée
X-CommunityId
X-CommunityId Envoyez le X-CommunityId de la communauté où l’opération a lieu.
Les descriptions des endpoints viennent directement de la spécification de l’API et sont en portugais pour l’instant. L’interface autour est traduite.

Move a assinatura do plano para outra opção de plano à venda na mesma comunidade (de outro plano também, ex.: Starter → Growth). Só o próprio assinante; assinatura de outra pessoa ou de outra comunidade responde 404. A assinatura continua a mesma (mesmo `id`, histórico, período e adicionais); muda `productId`, `billingAmount` e `billingInterval`. Veja a prévia em `POST /change-tier/quote`. **Comunidade suspensa pela Memberfy**: 403 com `code: COMMUNITY_SUSPENDED` (`param = newProductId`), como nas demais recusas de suspensão; para owner, admin, moderador e financeiro vem também o motivo (em `message` e em `reason`). **Upgrade** (opção mais cara na mesma periodicidade, com `immediate: true`): vale na hora e cobra agora, no cartão salvo do membro (o padrão, ou `paymentMethodId`), a diferença proporcional aos dias que faltam no período; a próxima renovação já vem no preço novo. Abaixo do piso (menos de 3 dias ou de R$ 10) troca sem cobrar. A cobrança é uma venda como as outras: taxa da plataforma e `feePayer` da opção nova, parcelas até o `maxInstallments` da prévia (`installments`). Se o cartão for recusado ou a cobrança não for confirmada na hora, **nada muda**: 402 (recusa) ou 502 (provedor fora do ar). Sem cartão salvo: 400 `param = paymentMethodId`, ou mande um cartão novo em `cardToken` (tokenizado no navegador como no checkout; `customerData` opcional, como no checkout). Pago, ele vira o cartão da assinatura (o padrão, que a renovação cobra) e a resposta traz `charge.cardSaved = true`; recusado, nada muda e o cartão não fica salvo. `cardToken` e `paymentMethodId` juntos: 400 `param = cardToken`. **Adicionais:** `addOnProductIds` entram na mesma operação, com as regras da prévia (`POST /change-tier/quote`). No upgrade cobrado agora, um pedido só no provedor com a linha do plano e uma por adicional (`charge.items` quando há mais de uma linha; `charge.amount` é o total); pago, a assinatura muda e os adicionais passam a ser cobrados com o plano, na mesma data. Se a cobrança falha, nada muda. Na troca agendada, os adicionais ficam em `scheduledChange.addOns` e entram na renovação, sem cobrança hoje. **PIX e boleto:** `paymentMethod` (`CREDIT_CARD`, padrão, `PIX` ou `BOLETO`), entre os `allowedMethods` da prévia. Com PIX ou boleto, a troca cobrada agora cria o pedido no valor proporcional calculado agora (fixo) e responde 200 com `mode = PENDING_PAYMENT`: **o plano ainda não muda**. `charge` traz o pedido (`purchaseId`, `orderId`, `amount`, `paymentMethod`, `items` quando há mais de uma linha) e `pendingChange` o que pagar (`pixCode` copia e cola, `qrCode`, `boletoUrl`, `boletoBarcode`, `expiresAt`). A troca (e os adicionais) só se aplica quando o pagamento é confirmado, no mesmo webhook `order.paid` (ou na conciliação) que conclui as compras; antes de aplicar, a assinatura precisa estar ainda na opção e no período em que o pedido foi calculado e o destino e os adicionais ainda válidos, senão o pagamento é estornado e nada muda. Pedido vencido ou cancelado: nada muda e a assinatura fica livre. Enquanto a troca espera o pagamento, qualquer outra troca responde 409 `monetization.subscription.changeTierPendingPayment` (a prévia traz `pendingChange` com o link de pagamento). Boleto quando faltam 4 dias ou menos para a renovação: 400 `changeTierBoletoTooLate` (`param = paymentMethod`). PIX ou boleto com `cardToken` ou `paymentMethodId`: 400 `param = paymentMethod`. A mesma `idempotencyKey` enquanto o pedido espera devolve os mesmos dados de pagamento (`replayed = true`, `mode = PENDING_PAYMENT`, `pendingChange`). **Idempotência:** mande `idempotencyKey` (ou o header `Idempotency-Key`), de 8 a 100 caracteres `[A-Za-z0-9_.:-]`, um por tentativa da pessoa. A mesma chave de novo devolve 200 com `data.replayed = true`, `mode`, `subscription` (como está agora), `scheduledChange` e `charge` (`purchaseId`, `orderId`, `amount`, `currency`, `installments`) da primeira vez, sem cobrar nem mudar nada. Enquanto uma cobrança de troca da assinatura está em andamento (com qualquer chave): 409 `monetization.subscription.changeTierInProgress`. Uma cobrança recusada libera a chave. **Agendada** (opção mais barata ou de mesmo preço, outra periodicidade — mensal ↔ anual, sem proporcional entre períodos —, upgrade com `immediate: false`, ou upgrade que tiraria um adicional): nada é cobrado agora. Na renovação de `effectiveDate` a assinatura passa para a opção nova e a cobrança já é no preço e na periodicidade dela. Uma nova troca agendada substitui a anterior; dá para desfazer com `DELETE /scheduled-change`. **Adicionais**: os que a opção nova oferece continuam (no valor da periodicidade nova); os que ela não oferece terminam na troca. **Contrato**: o contrato em vigor continua até o fim; sem contrato, uma opção nova com contrato começa o dela na troca. **Cupom**: deixa de valer na troca. Recusas, todas antes de qualquer cobrança: 400 `param = id` quando a assinatura não está `ACTIVE`, tem cancelamento agendado, é cortesia ou é um adicional ligado a um plano; 400 `param = newProductId` para a mesma opção, opção que não é de plano, fora de venda, em outra moeda, ou já assinada; 404 `newProductId` de outra comunidade ou inexistente; 403 `newProductId` para um adicional sem o plano que ele exige; 403 `param = id` quando a comunidade não tem informações comerciais aprovadas (só no upgrade cobrado); 409 `param = id` enquanto há uma cobrança de renovação do próximo período em aberto (PIX ou boleto já gerado, ou cartão em análise). O texto da recusa vem em `errors[0].message`. O upgrade cobrado é uma venda e passa pelo mesmo portão do checkout — vendas da comunidade desligadas (`payoutEnabled` falso, a pausa do dono ou o desligamento do sistema) ou, em BRL, recebedor conhecido fora de `active` recusam 400 `param = id` com `monetization.salesDisabled`, antes de gravar qualquer coisa ou chamar o provedor. Responde 200. `data`: `mode` (`IMMEDIATE` ou `SCHEDULED`), `changeType`, `scheduledReason`, `effectiveDate`, `currentProduct`, `newProduct`, `subscription` (como ficou), `scheduledChange` (o mesmo objeto de `GET /scheduled-change`, ou `null`), `charge` (`purchaseId`, `orderId`, `amount`, `currency`, `installments`, `feeBreakdown` só com a taxa da plataforma; `null` sem cobrança), `addOns`, `contract`, `couponEnds`. **Empresa:** o admin da empresa com vínculo vivo age como o assinante na assinatura da empresa (`companyId` na resposta); funcionário da empresa que não é admin recebe 403 (`monetization.company.adminOnly`); quem não tem relação com ela, 404.

Paramètres

NomEmplacementTypeDescription
idobligatoirepathstring (uuid)

En-têtes

NomTypeDescription
X-CommunityIdfacultatifstring (uuid)ID da comunidade em que a operação acontece. Obrigatório na maioria dos endpoints com escopo de comunidade.

Corps de la requête application/json

NomTypeDescription
newProductIdobligatoirestring (uuid)
immediatefacultatifboolean`true` aplica um upgrade agora, com a cobrança proporcional; ausente ou `false`, agenda para o fim do período. Downgrade e troca de periodicidade são sempre agendados.
paymentMethodIdfacultatifstring (uuid)Cartão salvo do membro (/payment-methods) para o upgrade cobrado agora. Ausente: o cartão padrão.
analyticsSessionIdfacultatifstringOpcional. O `sessionToken` do analytics (o que `POST /api/analytics/events` devolve), para o funil ligar o pedido à visita. Token inválido é ignorado. · max 64
installmentsfacultatifintegerParcelas do proporcional, até o `maxInstallments` da prévia. · ≥ 1, ≤ 12
addOnProductIdsfacultatifstring (uuid)[]Adicionais que entram com a troca.
paymentMethodfacultatifCREDIT_CARD | PIX | BOLETOComo a troca cobrada agora é paga. Ausente: cartão. PIX e boleto deixam a troca esperando o pagamento (`mode = PENDING_PAYMENT`).
cardTokenfacultatifstringCartão novo tokenizado no navegador, quando não há cartão salvo. Pago, vira o cartão da assinatura.
customerDatafacultatifobjectDados do comprador para o provedor com o cartão novo (como no checkout). Opcional.
idempotencyKeyfacultatifstringChave de idempotência da tentativa. Também aceita no header `Idempotency-Key`. · min 8, max 100

Réponses

StatutDescription
200Operação realizada com sucesso.
400Requisição inválida — falha de validação.
401Token ausente, inválido ou expirado; token de outra comunidade (o `X-CommunityId` ou o `communityId` do corpo não é o do token); token antigo ou de uma sessão encerrada (troca de senha, convite aceito). Nesses casos a mensagem pede para entrar de novo (`auth.signInAgain`).
402Requisição inválida — falha de validação.
403Autenticado, mas sem permissão para esta operação.
404Recurso não encontrado.
409Conflito com o estado atual do recurso.
500Erro interno do servidor.
502Erro interno do servidor.

Exemple curl

curl -X POST "https://api.memberfy.net/api/subscriptions/<id>/change-tier" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-CommunityId: $COMMUNITY_ID" \
  -H "Content-Type: application/json" \
  -d '{"newProductId":"e8a1c3f5-7b9d-4f2a-8c6e-0d2f4a6b8c1e"}'