Transições de Oferta

Defina como a movimentação de uma assinatura de uma oferta para outra é cobrada, com substituições por par que têm precedência sobre o padrão da família de produtos.

Uma transição de oferta descreve como uma assinatura é cobrada quando ela se move de uma oferta para outra — um upgrade, um downgrade ou uma troca de plano dentro da mesma família de produtos. Ela vincula um par específico from_offer_id → to_offer_id a uma regra de cobrança (change_charge_behavior) e a um interruptor (is_active).

As famílias de produtos já carregam um comportamento de cobrança de mudança padrão para toda movimentação dentro da família. Uma transição de oferta é a substituição de granularidade fina: quando você precisa que um par específico seja cobrado de forma diferente do padrão da família, você cria uma transição para esse par.

O Tokeflow orquestra pagamentos; ele não processa nem liquida fundos. As transições de oferta são pura modelagem de catálogo — elas descrevem como uma mudança de plano deve ser cobrada, nunca quem movimenta o dinheiro.

As transições de oferta fazem parte do catálogo, que é escopado por Merchant. Com uma chave de Merchant, o merchant é inferido. Com uma chave de Organization, direcione um merchant com o parâmetro de query merchant_id (em list/get) ou campo do corpo (em create). Consulte Authentication.

O problema que elas resolvem

A maioria das mudanças de plano dentro de uma família é cobrada da mesma forma — defina essa regra uma vez na família e pronto. Mas catálogos reais têm exceções:

  • Um upgrade de uma oferta mensal para uma anual deve alternar imediatamente (override), enquanto toda outra movimentação aguarda a próxima renovação.
  • Um downgrade específico nunca deve ratear proporcionalmente, mesmo que o padrão da família rateie.
  • Você quer desabilitar temporariamente a cobrança para um par de transição sem tocar no restante da família.

As transições de oferta permitem que você codifique essas exceções por par, deixando o padrão da família cuidar de todo o resto.

Precedência: transição explícita vence o padrão da família

Quando uma assinatura se move entre duas ofertas, o Tokeflow resolve a regra de cobrança efetiva nesta ordem:

Em palavras:

  1. Se houver uma transição ativa para o par exato from_offer_id → to_offer_id e ela definir um change_charge_behavior não nulo, esse valor vence.
  2. Caso contrário — sem transição, uma transição inativa ou uma transição com change_charge_behavior nulo — o Tokeflow recorre ao change_charge_behavior padrão da família de produtos.

Para resolver o comportamento efetivo de qualquer par sem reproduzir essa lógica você mesmo, chame o endpoint de effective-behavior das ofertas. Ele retorna o único valor que se aplicaria, após a precedência.

O motor de transição executa os três comportamentos — next_renew, prorated e override. O change_charge_behavior definido para um par é o que será aplicado quando uma assinatura se mover entre essas ofertas.

O comportamento de cobrança de mudança

change_charge_behavior é opcional em uma transição. Deixe-o como null para herdar o padrão da família para esse par enquanto ainda usa a linha da transição para o seu interruptor is_active.

ValorSignificado
next_renewAplica a mudança na próxima renovação — o novo preço entra em vigor no ciclo de cobrança seguinte.
proratedRateia proporcionalmente a diferença para o ciclo atual.
overrideSubstitui a cobrança atual pelos termos da nova oferta imediatamente.

O objeto de transição de oferta

FieldTypeDescription
idstringIdentificador único, prefixado com oft_.
from_offer_idstringA oferta da qual a assinatura está saindo. Prefixado com ofr_.
to_offer_idstringA oferta para a qual a assinatura está indo. Prefixado com ofr_. Deve pertencer à mesma família de produtos que from_offer_id.
change_charge_behaviorenum | nullSubstituição por par: next_renew, prorated ou override. null significa recorrer ao padrão da família.
is_activebooleanSe a transição está elegível para processamento. Transições inativas são ignoradas e o padrão da família se aplica. O padrão é true.
created_atstringTimestamp de criação em ISO 8601 UTC.
updated_atstringTimestamp da última atualização em ISO 8601 UTC.
{
  "id": "oft_a1b2c3d4e5",
  "from_offer_id": "ofr_3hk9d2",
  "to_offer_id": "ofr_7pq4m1",
  "change_charge_behavior": "override",
  "is_active": true,
  "created_at": "2026-05-19T12:00:00.000Z",
  "updated_at": "2026-05-19T12:00:00.000Z"
}

Um par de transição é único. Cada combinação from_offer_id → to_offer_id pode ter no máximo uma transição. Ambas as ofertas devem pertencer à mesma família de produtos, e from_offer_id deve diferir de to_offer_id.

Endpoints

POST/api/v1/offer-transitions

Auth: chave de Organization (com merchant_id) ou chave de Merchant. Requer o escopo offers:write.

Cria uma transição para um par de ofertas específico.

FieldTypeRequiredDescription
from_offer_idstringSimA oferta da qual a assinatura está saindo.
to_offer_idstringSimA oferta para a qual a assinatura está indo. Deve compartilhar a mesma família de produtos que from_offer_id e diferir dela.
change_charge_behaviorenumNãonext_renew, prorated ou override. Omita ou use null para herdar o padrão da família.
is_activebooleanNãoSe a transição está elegível para processamento. O padrão é true.
merchant_idstringCondicionalObrigatório com uma chave de Organization; omita com uma chave de Merchant.
curl -X POST https://api.tokeflow.com/api/v1/offer-transitions \
  -H "Authorization: Bearer sk_live_mer_REPLACE_WITH_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 3a7f9c2e-2c1d-4a8b-9f10-1e2d3c4b5a6f" \
  -d '{
    "from_offer_id": "ofr_3hk9d2",
    "to_offer_id": "ofr_7pq4m1",
    "change_charge_behavior": "override",
    "is_active": true
  }'
{
  "success": true,
  "data": {
    "id": "oft_a1b2c3d4e5",
    "from_offer_id": "ofr_3hk9d2",
    "to_offer_id": "ofr_7pq4m1",
    "change_charge_behavior": "override",
    "is_active": true,
    "created_at": "2026-05-19T12:00:00.000Z",
    "updated_at": "2026-05-19T12:00:00.000Z"
  },
  "request_id": "req_8f3c1a2b4d5e",
  "timestamp": "2026-05-19T12:00:00.000Z"
}

Envie um cabeçalho Idempotency-Key na criação para que uma requisição repetida nunca produza uma transição duplicada. Repetir a mesma chave retorna o resultado original. Consulte Idempotency & rate limits.

Erros comuns:

StatusTypeWhen
400validation_errorfrom_offer_id é igual a to_offer_id, uma oferta não existe ou as duas ofertas estão em famílias de produtos diferentes.
409conflict_errorJá existe uma transição para este par from_offer_id → to_offer_id.
{
  "error": {
    "type": "conflict_error",
    "code": "OFFER_TRANSITION_ALREADY_EXISTS",
    "message": "A transition for this offer pair already exists.",
    "details": {
      "from_offer_id": "ofr_3hk9d2",
      "to_offer_id": "ofr_7pq4m1"
    },
    "request_id": "req_2b9e7c1f0a3d",
    "timestamp": "2026-05-19T12:00:00.000Z"
  }
}

GET/api/v1/offer-transitions

Auth: chave de Organization (com merchant_id) ou chave de Merchant. Requer o escopo offers:read.

Lista as transições do merchant. Suporta paginação e filtragem.

Query paramTypeDescription
pageintegerNúmero da página, indexado a partir de 1. Padrão 1, mínimo 1.
limitintegerItens por página. Padrão 20, máximo 100.
from_offer_idstringFiltra para transições originadas desta oferta.
to_offer_idstringFiltra para transições que têm esta oferta como destino.
is_activebooleanFiltra para transições ativas (true) ou inativas (false).
change_charge_behaviorenumFiltra por comportamento: next_renew, prorated ou override.
merchant_idstringObrigatório com uma chave de Organization; omita com uma chave de Merchant.
curl "https://api.tokeflow.com/api/v1/offer-transitions?page=1&limit=20&from_offer_id=ofr_3hk9d2&is_active=true" \
  -H "Authorization: Bearer sk_live_mer_REPLACE_WITH_YOUR_KEY"
{
  "success": true,
  "data": [
    {
      "id": "oft_a1b2c3d4e5",
      "from_offer_id": "ofr_3hk9d2",
      "to_offer_id": "ofr_7pq4m1",
      "change_charge_behavior": "override",
      "is_active": true,
      "created_at": "2026-05-19T12:00:00.000Z",
      "updated_at": "2026-05-19T12:00:00.000Z"
    },
    {
      "id": "oft_f6g7h8i9j0",
      "from_offer_id": "ofr_3hk9d2",
      "to_offer_id": "ofr_2zx5n8",
      "change_charge_behavior": null,
      "is_active": true,
      "created_at": "2026-05-19T12:05:00.000Z",
      "updated_at": "2026-05-19T12:05:00.000Z"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "limit": 20,
      "total": 2,
      "total_pages": 1,
      "has_next": false,
      "has_prev": false
    }
  },
  "request_id": "req_5c1d8e2f9a0b",
  "timestamp": "2026-05-19T12:30:00.000Z"
}

Consulte Pagination & filtering para convenções compartilhadas.

GET/api/v1/offer-transitions/:id

Auth: chave de Organization (com merchant_id) ou chave de Merchant. Requer o escopo offers:read.

Recupera uma única transição pelo ID.

curl "https://api.tokeflow.com/api/v1/offer-transitions/oft_a1b2c3d4e5" \
  -H "Authorization: Bearer sk_live_mer_REPLACE_WITH_YOUR_KEY"
{
  "success": true,
  "data": {
    "id": "oft_a1b2c3d4e5",
    "from_offer_id": "ofr_3hk9d2",
    "to_offer_id": "ofr_7pq4m1",
    "change_charge_behavior": "override",
    "is_active": true,
    "created_at": "2026-05-19T12:00:00.000Z",
    "updated_at": "2026-05-19T12:00:00.000Z"
  },
  "request_id": "req_9a0b1c2d3e4f",
  "timestamp": "2026-05-19T12:30:00.000Z"
}

Uma transição que não existe ou pertence a outro merchant retorna 404 not_found_error.

PATCH/api/v1/offer-transitions/:id

Auth: chave de Organization (com merchant_id) ou chave de Merchant. Requer o escopo offers:write.

Atualiza a regra de cobrança ou o estado ativo de uma transição. Envie apenas os campos que você deseja alterar.

FieldTypeRequiredDescription
change_charge_behaviorenum | nullNãoNovo comportamento, ou null para recorrer ao padrão da família.
is_activebooleanNãoHabilita ou desabilita a transição.

O par de ofertas (from_offer_id, to_offer_id) é imutável. Mudar o par é uma alteração estrutural, não uma atualização — exclua a transição e crie uma nova para redirecioná-la.

curl -X PATCH https://api.tokeflow.com/api/v1/offer-transitions/oft_a1b2c3d4e5 \
  -H "Authorization: Bearer sk_live_mer_REPLACE_WITH_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "change_charge_behavior": "next_renew",
    "is_active": false
  }'
{
  "success": true,
  "data": {
    "id": "oft_a1b2c3d4e5",
    "from_offer_id": "ofr_3hk9d2",
    "to_offer_id": "ofr_7pq4m1",
    "change_charge_behavior": "next_renew",
    "is_active": false,
    "created_at": "2026-05-19T12:00:00.000Z",
    "updated_at": "2026-05-19T13:15:00.000Z"
  },
  "request_id": "req_0b1c2d3e4f5a",
  "timestamp": "2026-05-19T13:15:00.000Z"
}

DELETE/api/v1/offer-transitions/:id

Auth: chave de Organization (com merchant_id) ou chave de Merchant. Requer o escopo offers:write.

Remove uma transição. Após a exclusão, as movimentações entre esse par de ofertas recorrem ao padrão da família de produtos. Retorna 204 No Content.

curl -X DELETE https://api.tokeflow.com/api/v1/offer-transitions/oft_a1b2c3d4e5 \
  -H "Authorization: Bearer sk_live_mer_REPLACE_WITH_YOUR_KEY"

Desabilitar uma transição com PATCH … { "is_active": false } é reversível e preserva a linha. Use DELETE apenas quando você quiser que o par desapareça de vez.

Relacionados

Nesta página