Skip to main content
Un producto (Product) sirve para agrupar y categorizar tus cobros (deudas, suscripciones y ligas de pago). Su uso es completamente opcional: puedes cobrar sin asociar ningún producto. Lo usas cuando quieres reportar tus cobros por línea de producto o servicio, por ejemplo “Plan Premium”, “Cuota mensual gimnasio” o “Internet 100MB”.

Llave natural: name

El name es la llave natural del producto y es único por company. Si ya existe un producto activo con ese name, POST /products responde 201 con el producto existente, sin modificarlo: no genera un duplicado ni un error.
Por eso POST /products es idempotente por diseño: repetir el mismo name te devuelve el mismo producto, tal como está guardado (si mandas otros valores en el body, se ignoran). La excepción es el externalProductId: si el producto existente ya tiene otro externalProductId, la API responde 409 RESOURCE_CONFLICT.

Crear un producto

La respuesta refleja lo que quedó guardado (timestamps, externalProductId y active), no el request.
El productId es el ID público del producto, con prefijo prd_ (ej. prd_12985). En el path de GET, PATCH y DELETE /products/{id} también se acepta el número sin prefijo (12985); otros prefijos o valores no numéricos devuelven 404 RESOURCE_NOT_FOUND.
string
Tu propio identificador del producto (opcional). Es el que después usas para referenciarlo al crear deudas, sin tener que guardar el productId de Tapi. No admite los caracteres ', ", \ ni ; (devuelve 400).

Validaciones

  • name y externalProductId se recortan (trim) antes de guardarse.
  • Los campos no declarados en el body se ignoran.
  • Si el externalProductId ya lo usa otro producto, o si el name ya existe con otro externalProductId, la API responde 409 RESOURCE_CONFLICT (con el mismo mensaje en los dos casos).

Clientes con varias companies

Si tu cliente de TapiPay tiene una sola company, no tienes que indicar nada: todo lo que creas queda asociado a ella. Si tu cliente administra varias companies (por ejemplo, una red de escuelas donde cada escuela es una company de Tapi), indica en el body para cuál de ellas es el producto con companyCode:
El producto se crea dentro de esa company: name y externalProductId son únicos por company, así que el mismo nombre puede existir en cada una de tus companies sin chocar. Para listar los productos de una company en particular usa GET /products?companyCode=MX-S-04937.
string
Company de Tapi (MX-S-…) en la que se crea el producto. Opcional si tu cliente tiene una sola company. Debe pertenecer a tu cliente.
Esta regla aplica a toda la API, no solo a productos: un cliente con varias companies indica companyCode en cada request (en el body en POST/PATCH, o como ?companyCode= en GET). En un PATCH, el companyCode del body se toma como contexto y no como un campo a modificar. Ver Convenciones de la API. Al crear deudas con POST /v2/debts, el producto se busca dentro de la company del request: un producto de una company no puede usarse en una deuda de otra.

Referenciar un producto en una deuda

Al crear una deuda con POST /v2/debts, el producto debe existir de antemano y se referencia por productId (formato prd_<número>; otro formato devuelve 400 INVALID_REQUEST) o por externalProductId (uno solo; enviar los dos devuelve 400). El endpoint de deudas no crea productos: enviar productName devuelve 400 INVALID_REQUEST, y referenciar un producto inexistente devuelve 404 RESOURCE_NOT_FOUND sin crear la deuda.
En la respuesta de la deuda, el producto viene embebido:
Referenciar un producto es lo que habilita el débito automático de esa deuda.

Creación en línea (productName)

En suscripciones y ligas de pago puedes enviar el producto en línea con el campo productName: si el nombre no existe, se crea; si ya existe, se reutiliza sin duplicarlo.
Esto no aplica a deudas. POST /v2/debts no acepta productName (devuelve 400 INVALID_REQUEST) y nunca crea productos: ver Referenciar un producto en una deuda.
En la respuesta del cobro, el producto viene embebido con cuatro campos:
El campo createdInline es true si el producto se creó en esa misma petición, y false si ya existía y se reutilizó. En deudas es siempre false.

Listar productos

GET /products devuelve solo productos activos, ordenados por productId descendente. La paginación usa page (default 1) y limit (default 50, máximo 500). Ver Convenciones de la API.

Actualizar

PATCH /products/{id} acepta solo dos campos:
string
Nuevo nombre, string no vacío. Si ya lo usa otro producto, incluso uno inactivo, devuelve 409 RESOURCE_CONFLICT.
boolean
Solo true o false. active: false desactiva el producto igual que DELETE. active: true no cambia nada: un producto que puedes leer ya está activo, y uno inactivo devuelve 404. Se acepta para que puedas enviar el objeto completo.
Un body vacío, o cualquier otro campo, devuelve 400 INVALID_REQUEST. Los tipos inválidos (por ejemplo "active": "no") devuelven 400 con el detalle en details[]. El companyCode del body se toma como contexto, no como campo a modificar.
Limitación conocida: updatedAt no refleja los cambios hechos con PATCH.

Desactivar

boolean
predeterminado:"true"
Estado del producto.
DELETE /products/{id} hace un soft-delete: pone active: false sin eliminar el producto, de modo que el historial se conserva. Hacer DELETE sobre un producto ya eliminado devuelve 404 RESOURCE_NOT_FOUND.
Un producto inactivo (eliminado, desactivado con PATCH o creado con active: false) queda fuera de la API:
  • No aparece en GET /products, y GET /products/{id} devuelve 404.
  • No se puede reactivar por la API: un PATCH con active: true también devuelve 404.
  • No se puede usar en nuevas deudas, ligas de pago ni suscripciones.
  • Su nombre sigue ocupado: otro producto no puede renombrarse a ese nombre (409 RESOURCE_CONFLICT).
Crear un producto con active: false devuelve el producto con active: false y createdAt/updatedAt en null.

Endpoints

Pruébalo en el API Reference

Explora cada endpoint con su playground interactivo.