Transiciones de oferta

Define cómo se factura el traslado de una suscripción de una oferta a otra, con anulaciones por par que tienen prioridad sobre el valor predeterminado de la familia de productos.

Una transición de oferta describe cómo se factura una suscripción cuando pasa de una oferta a otra — una mejora, una degradación o un cambio de plan dentro de la misma familia de productos. Fija un par específico from_offer_id → to_offer_id a una regla de facturación (change_charge_behavior) y a un conmutador (is_active).

Las familias de productos ya llevan un comportamiento de cargo por cambio predeterminado para cada traslado dentro de la familia. Una transición de oferta es la anulación de grano fino: cuando necesitas que un par específico se facture de forma distinta al valor predeterminado de la familia, creas una transición para ese par.

Tokeflow orquesta pagos; no procesa ni liquida fondos. Las transiciones de oferta son pura modelización de catálogo — describen cómo debe cobrarse un cambio de plan, nunca quién mueve el dinero.

Las transiciones de oferta forman parte del catálogo, que tiene alcance de merchant. Con una clave de Merchant, el merchant se infiere. Con una clave de Organization, apunta a un merchant con el parámetro de consulta merchant_id (en list/get) o el campo del cuerpo (en create). Consulta Autenticación.

El problema que resuelven

La mayoría de los cambios de plan dentro de una familia se facturan de la misma manera — establece esa regla una vez en la familia y listo. Pero los catálogos reales tienen excepciones:

  • Una mejora de una oferta mensual a una anual debería cambiar de inmediato (override), mientras que cualquier otro traslado espera a la siguiente renovación.
  • Una degradación específica nunca debería prorratearse, aunque el valor predeterminado de la familia sí prorratee.
  • Quieres deshabilitar temporalmente la facturación de un par de transición sin tocar el resto de la familia.

Las transiciones de oferta te permiten codificar estas excepciones por par, dejando que el valor predeterminado de la familia se ocupe de todo lo demás.

Precedencia: la transición explícita gana al valor predeterminado de la familia

Cuando una suscripción se traslada entre dos ofertas, Tokeflow resuelve la regla de facturación efectiva en este orden:

En palabras:

  1. Si existe una transición activa para el par exacto from_offer_id → to_offer_id y define un change_charge_behavior no nulo, ese valor gana.
  2. En caso contrario — sin transición, una transición inactiva o una transición con un change_charge_behavior nulo — Tokeflow recurre al change_charge_behavior predeterminado de la familia de productos.

Para resolver el comportamiento efectivo de cualquier par sin reproducir tú mismo esta lógica, llama al endpoint effective-behavior de ofertas. Devuelve el único valor que se aplicaría, tras la precedencia.

El motor de transiciones ejecuta los tres comportamientos — next_renew, prorated y override. El change_charge_behavior que definas en un par es el que se aplica cuando una suscripción se traslada entre esas ofertas.

El comportamiento de cargo por cambio

change_charge_behavior es opcional en una transición. Déjalo en null para heredar el valor predeterminado de la familia para ese par mientras sigues usando la fila de la transición para su conmutador is_active.

ValueMeaning
next_renewAplica el cambio en la siguiente renovación — el nuevo precio entra en vigor en el ciclo de facturación posterior.
proratedProrratea la diferencia para el ciclo actual.
overrideReemplaza el cargo actual con los términos de la nueva oferta de inmediato.

El objeto de transición de oferta

FieldTypeDescription
idstringIdentificador único, con el prefijo oft_.
from_offer_idstringLa oferta de la que se traslada la suscripción. Con el prefijo ofr_.
to_offer_idstringLa oferta a la que se traslada la suscripción. Con el prefijo ofr_. Debe pertenecer a la misma familia de productos que from_offer_id.
change_charge_behaviorenum | nullAnulación por par: next_renew, prorated u override. null significa recurrir al valor predeterminado de la familia.
is_activebooleanSi la transición es elegible para procesamiento. Las transiciones inactivas se ignoran y se aplica el valor predeterminado de la familia. El valor predeterminado es true.
created_atstringMarca de tiempo de creación ISO 8601 UTC.
updated_atstringMarca de tiempo de última actualización 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"
}

Un par de transición es único. Cada combinación from_offer_id → to_offer_id puede tener como máximo una transición. Ambas ofertas deben pertenecer a la misma familia de productos, y from_offer_id debe ser distinto de to_offer_id.

Endpoints

POST/api/v1/offer-transitions

Auth: clave de Organization (con merchant_id) o clave de Merchant. Requiere el ámbito offers:write.

Crea una transición para un par de ofertas específico.

FieldTypeRequiredDescription
from_offer_idstringSíLa oferta de la que se traslada la suscripción.
to_offer_idstringSíLa oferta a la que se traslada la suscripción. Debe compartir la misma familia de productos que from_offer_id y ser distinta de ella.
change_charge_behaviorenumNonext_renew, prorated u override. Omítelo o déjalo en null para heredar el valor predeterminado de la familia.
is_activebooleanNoSi la transición es elegible para procesamiento. El valor predeterminado es true.
merchant_idstringCondicionalRequerido con una clave de Organization; omítelo con una clave 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"
}

Envía un encabezado Idempotency-Key en la creación para que una solicitud reintentada nunca produzca una transición duplicada. Reproducir la misma clave devuelve el resultado original. Consulta Idempotencia y límites de tasa.

Errores comunes:

StatusTypeWhen
400validation_errorfrom_offer_id es igual a to_offer_id, una oferta no existe, o las dos ofertas están en familias de productos diferentes.
409conflict_errorYa existe una transición 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: clave de Organization (con merchant_id) o clave de Merchant. Requiere el ámbito offers:read.

Lista las transiciones del merchant. Admite paginación y filtrado.

Query paramTypeDescription
pageintegerNúmero de página, indexado desde 1. Predeterminado 1, mín 1.
limitintegerElementos por página. Predeterminado 20, máx 100.
from_offer_idstringFiltra a las transiciones que se originan en esta oferta.
to_offer_idstringFiltra a las transiciones dirigidas a esta oferta.
is_activebooleanFiltra a las transiciones activas (true) o inactivas (false).
change_charge_behaviorenumFiltra por comportamiento: next_renew, prorated u override.
merchant_idstringRequerido con una clave de Organization; omítelo con una clave 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"
}

Consulta Paginación y filtrado para conocer las convenciones compartidas.

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

Auth: clave de Organization (con merchant_id) o clave de Merchant. Requiere el ámbito offers:read.

Recupera una única transición por 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"
}

Una transición que no existe o pertenece a otro merchant devuelve 404 not_found_error.

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

Auth: clave de Organization (con merchant_id) o clave de Merchant. Requiere el ámbito offers:write.

Actualiza la regla de facturación o el estado activo de una transición. Envía solo los campos que quieras cambiar.

FieldTypeRequiredDescription
change_charge_behaviorenum | nullNoNuevo comportamiento, o null para recurrir al valor predeterminado de la familia.
is_activebooleanNoHabilita o deshabilita la transición.

El par de ofertas (from_offer_id, to_offer_id) es inmutable. Cambiar el par es un cambio estructural, no una actualización — elimina la transición y crea una nueva para reasignar el destino.

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: clave de Organization (con merchant_id) o clave de Merchant. Requiere el ámbito offers:write.

Elimina una transición. Tras la eliminación, los traslados entre ese par de ofertas recurren al valor predeterminado de la familia de productos. Devuelve 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"

Deshabilitar una transición con PATCH … { "is_active": false } es reversible y conserva la fila. Usa DELETE solo cuando quieras que el par desaparezca de forma definitiva.

Relacionado

En esta página