Familias de productos

Agrupa productos y planes relacionados bajo una única entidad de catálogo y define un comportamiento de cobro de cambios predeterminado para las transiciones de oferta dentro del grupo.

Una familia de productos agrupa productos y planes relacionados en una única entidad de catálogo — por ejemplo, los niveles de una misma suscripción (Light, Pro, Premium) o un conjunto de complementos de pago único vendidos en conjunto. Las familias dan estructura a tu catálogo: en lugar de una lista plana de productos, modelas las relaciones entre ellos.

Una familia también lleva un comportamiento de cobro de cambios predeterminado — la regla que se aplica cuando una suscripción se mueve entre ofertas pertenecientes a productos de la misma familia (una mejora, una degradación o un cambio de plan). Defínelo una sola vez en la familia, y cada transición dentro de esa familia lo hereda a menos que se anule.

Tokeflow orquesta pagos; no procesa ni liquida fondos. Las familias de productos son puro modelado de catálogo — describen qué vendes y cómo se cobran los cambios de plan, nunca quién mueve el dinero.

Las familias de productos 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 Authentication.

Dónde encajan las familias

Una familia está en la cima de la jerarquía del catálogo. Los productos pertenecen a una familia; las ofertas y los precios cuelgan de los productos; las suscripciones se apoyan en las ofertas.

Cuando un suscriptor pasa de una oferta de un producto a una oferta de otro producto en la misma familia, el change_charge_behavior de la familia decide cómo se factura el cambio.

El comportamiento de cobro de cambios

change_charge_behavior define el tratamiento de facturación predeterminado para las transiciones de oferta dentro de la familia.

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

Si omites change_charge_behavior al crear, la familia usa next_renew de forma predeterminada.

El motor de transiciones ejecuta los tres comportamientos — next_renew, prorated y override. El change_charge_behavior predeterminado almacenado en la familia se aplica a cada cambio dentro de ella, salvo que una transición de oferta anule un par específico.

El objeto de familia de productos

FieldTypeDescription
idstringIdentificador único, prefijado con pfa_.
merchant_idstringMerchant propietario, prefijado con mrc_.
namestringNombre legible para humanos, p. ej. Streaming Plans.
slugstringIdentificador en minúsculas, único por merchant.
descriptionstring | nullDescripción opcional de texto libre.
custom_plan_idstring | nullReferencia opcional de plan externo, solo para visualización. Único por merchant cuando se define.
change_charge_behaviorenumComportamiento de transición predeterminado: next_renew, prorated u override.
created_atstringMarca de tiempo de creación en UTC ISO 8601.
updated_atstringMarca de tiempo de última actualización en UTC ISO 8601.
deleted_atstring | nullMarca de tiempo de eliminación lógica en UTC ISO 8601, o null cuando está activo. Presente solo en registros eliminados de forma lógica.
{
  "id": "pfa_a1b2c3d4e5",
  "merchant_id": "mrc_a1b2c3d4e5",
  "name": "Streaming Plans",
  "slug": "streaming-plans",
  "description": "Family of streaming subscription plans",
  "custom_plan_id": "plan_external_42",
  "change_charge_behavior": "next_renew",
  "created_at": "2026-05-19T12:00:00.000Z",
  "updated_at": "2026-05-19T12:00:00.000Z"
}

Crear una familia de productos

POST/api/v1/product-families

Auth: clave de Organization (con merchant_id) o clave de Merchant. Requiere el scope products:write.

Crea una nueva familia en el catálogo del merchant de destino.

Parámetros del cuerpo

FieldTypeRequiredDescription
namestringSíNombre legible para humanos.
slugstringSíIdentificador en minúsculas, único por merchant (entre las familias activas).
descriptionstringNoDescripción de texto libre.
custom_plan_idstringNoReferencia de plan externo (solo para visualización), única por merchant cuando se define.
change_charge_behaviorenumNonext_renew (predeterminado), prorated u override.
merchant_idstringCondicionalRequerido solo con una clave de Organization, para apuntar a un merchant. Se infiere de una clave de Merchant.
curl -X POST https://api.tokeflow.com/api/v1/product-families \
  -H "Authorization: Bearer sk_live_mer_…" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 8f3c1d20-9b4a-4e2c-9f6a-2c1d0e7b5a44" \
  -d '{
    "name": "Streaming Plans",
    "slug": "streaming-plans",
    "description": "Family of streaming subscription plans",
    "custom_plan_id": "plan_external_42",
    "change_charge_behavior": "next_renew"
  }'

Respuesta 201 Created

{
  "success": true,
  "data": {
    "id": "pfa_a1b2c3d4e5",
    "merchant_id": "mrc_a1b2c3d4e5",
    "name": "Streaming Plans",
    "slug": "streaming-plans",
    "description": "Family of streaming subscription plans",
    "custom_plan_id": "plan_external_42",
    "change_charge_behavior": "next_renew",
    "created_at": "2026-05-19T12:00:00.000Z",
    "updated_at": "2026-05-19T12:00:00.000Z"
  },
  "request_id": "req_8f3c1d20",
  "timestamp": "2026-05-19T12:00:00.000Z"
}

Envía un encabezado Idempotency-Key al crear. Reenviar la misma clave devuelve el resultado original (HTTP 200 al reintentar frente a 201 en la primera creación) en lugar de crear un duplicado. Consulta Idempotency and rate limits.

slug debe ser único por merchant entre las familias activas. Un duplicado devuelve 409 (conflict_error). Lo mismo aplica a custom_plan_id cuando se define.


Listar familias de productos

GET/api/v1/product-families

Auth: clave de Organization (con merchant_id) o clave de Merchant. Requiere el scope products:read.

Devuelve una lista paginada de familias del merchant, de la más reciente a la más antigua.

Parámetros de consulta

FieldTypeRequiredDescription
namestringNoFiltro de coincidencia parcial (sin distinción de mayúsculas y minúsculas) sobre el nombre de la familia.
slugstringNoFiltra por slug exacto.
change_charge_behaviorenumNoFiltra por next_renew, prorated u override.
pageintegerNoNúmero de página, predeterminado 1, mínimo 1.
limitintegerNoElementos por página, predeterminado 20, máximo 100.
merchant_idstringCondicionalRequerido solo con una clave de Organization.
curl -G https://api.tokeflow.com/api/v1/product-families \
  -H "Authorization: Bearer sk_live_mer_…" \
  --data-urlencode "page=1" \
  --data-urlencode "limit=20" \
  --data-urlencode "name=Streaming" \
  --data-urlencode "change_charge_behavior=next_renew"

Respuesta 200 OK

{
  "success": true,
  "data": [
    {
      "id": "pfa_a1b2c3d4e5",
      "merchant_id": "mrc_a1b2c3d4e5",
      "name": "Streaming Plans",
      "slug": "streaming-plans",
      "description": "Family of streaming subscription plans",
      "custom_plan_id": "plan_external_42",
      "change_charge_behavior": "next_renew",
      "created_at": "2026-05-19T12:00:00.000Z",
      "updated_at": "2026-05-19T12:00:00.000Z"
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "limit": 20,
      "total": 1,
      "total_pages": 1,
      "has_next": false,
      "has_prev": false
    }
  },
  "request_id": "req_8f3c1d20",
  "timestamp": "2026-05-19T12:00:00.000Z"
}

Obtener una familia de productos

GET/api/v1/product-families/:id

Auth: clave de Organization (con merchant_id) o clave de Merchant. Requiere el scope products:read.

Recupera una única familia por su ID.

curl https://api.tokeflow.com/api/v1/product-families/pfa_a1b2c3d4e5 \
  -H "Authorization: Bearer sk_live_mer_…"

Respuesta 200 OK

{
  "success": true,
  "data": {
    "id": "pfa_a1b2c3d4e5",
    "merchant_id": "mrc_a1b2c3d4e5",
    "name": "Streaming Plans",
    "slug": "streaming-plans",
    "description": "Family of streaming subscription plans",
    "custom_plan_id": "plan_external_42",
    "change_charge_behavior": "next_renew",
    "created_at": "2026-05-19T12:00:00.000Z",
    "updated_at": "2026-05-19T12:00:00.000Z"
  },
  "request_id": "req_8f3c1d20",
  "timestamp": "2026-05-19T12:00:00.000Z"
}

Un ID desconocido devuelve 404 (not_found_error).


Actualizar una familia de productos

PATCH/api/v1/product-families/:id

Auth: clave de Organization (con merchant_id) o clave de Merchant. Requiere el scope products:write.

Actualiza parcialmente una familia. Envía solo los campos que quieras cambiar. Todos los campos de creación son actualizables: name, slug, description, custom_plan_id y change_charge_behavior.

curl -X PATCH https://api.tokeflow.com/api/v1/product-families/pfa_a1b2c3d4e5 \
  -H "Authorization: Bearer sk_live_mer_…" \
  -H "Content-Type: application/json" \
  -d '{
    "description": "All streaming subscription tiers",
    "change_charge_behavior": "prorated"
  }'

Respuesta 200 OK

{
  "success": true,
  "data": {
    "id": "pfa_a1b2c3d4e5",
    "merchant_id": "mrc_a1b2c3d4e5",
    "name": "Streaming Plans",
    "slug": "streaming-plans",
    "description": "All streaming subscription tiers",
    "custom_plan_id": "plan_external_42",
    "change_charge_behavior": "prorated",
    "created_at": "2026-05-19T12:00:00.000Z",
    "updated_at": "2026-05-20T09:15:00.000Z"
  },
  "request_id": "req_8f3c1d20",
  "timestamp": "2026-05-20T09:15:00.000Z"
}

Cambiar slug o custom_plan_id a un valor que ya tenga otra familia activa en el mismo merchant devuelve 409 (conflict_error).


Eliminar de forma lógica una familia de productos

DELETE/api/v1/product-families/:id

Auth: clave de Organization (con merchant_id) o clave de Merchant. Requiere el scope products:write.

Elimina de forma lógica la familia. El registro se conserva con una marca de tiempo deleted_at y se excluye de los resultados de list y get, preservando la auditabilidad. Los espacios de slug y custom_plan_id quedan liberados para su reutilización por nuevas familias activas.

curl -X DELETE https://api.tokeflow.com/api/v1/product-families/pfa_a1b2c3d4e5 \
  -H "Authorization: Bearer sk_live_mer_…"

Respuesta 204 No Content

El cuerpo de la respuesta está vacío. Un ID desconocido devuelve 404 (not_found_error).

Esta es una eliminación lógica — la familia puede recuperarse con el endpoint de restauración que aparece más abajo.


Restaurar una familia de productos

POST/api/v1/product-families/:id/restore

Auth: clave de Organization (con merchant_id) o clave de Merchant. Requiere el scope products:write.

Restaura una familia eliminada de forma lógica, borrando su deleted_at. La restauración recupera el slug y el custom_plan_id originales solo si ninguna familia activa los ha tomado en el ínterin.

curl -X POST https://api.tokeflow.com/api/v1/product-families/pfa_a1b2c3d4e5/restore \
  -H "Authorization: Bearer sk_live_mer_…"

Respuesta 201 Created

{
  "success": true,
  "data": {
    "id": "pfa_a1b2c3d4e5",
    "merchant_id": "mrc_a1b2c3d4e5",
    "name": "Streaming Plans",
    "slug": "streaming-plans",
    "description": "All streaming subscription tiers",
    "custom_plan_id": "plan_external_42",
    "change_charge_behavior": "prorated",
    "created_at": "2026-05-19T12:00:00.000Z",
    "updated_at": "2026-05-21T11:00:00.000Z"
  },
  "request_id": "req_8f3c1d20",
  "timestamp": "2026-05-21T11:00:00.000Z"
}

Casos de error

ConditionHTTPType
La familia ya está activa (no eliminada de forma lógica)400validation_error
Una familia activa ahora tiene el mismo slug409conflict_error
Una familia activa ahora tiene el mismo custom_plan_id409conflict_error
Familia no encontrada404not_found_error

Si la restauración falla por un conflicto de slug o custom_plan_id, renombra o archiva la familia activa que ocupa el espacio y luego reintenta la restauración.

Errores

Todos los errores usan el envelope estándar. Consulta Errors para ver el catálogo completo.

{
  "error": {
    "type": "conflict_error",
    "code": "PRODUCT_FAMILY_SLUG_TAKEN",
    "message": "Product family with slug 'streaming-plans' already exists",
    "details": {},
    "request_id": "req_8f3c1d20",
    "timestamp": "2026-05-19T12:00:00.000Z"
  }
}

Relacionado

En esta página