Saltar al contenido

    Señal manual de pago confirmado

    En la web, solo el dueño puede enviar una señal real al webhook. POST /v1/paymentlink/LINK_ID/paid-signal o POST /v1/subscriptions/SUBSCRIPTION_ID/paid-signal, con Authorization: Bearer TOKEN_DEL_DUENO y cuerpo JSON vacío. Empleados, clientes y API keys reciben acceso denegado.

    En suscripciones se usa el enlace más reciente existente. Se requiere un webhook configurado. Envía status paid, sin pago bancario, con metadata confirmation_source=owner_manual y confirmed_by=ID_DEL_DUENO. No modifica el estado del enlace, la suscripción ni sus fechas; no verifica movimientos ni descuenta créditos. El receptor puede ejecutar sus acciones de activación.

    Devuelve delivered, payment_link_id y webhook_response_id si el receptor acepta la entrega. Los intentos quedan en el historial de webhooks y se firman con el mecanismo habitual. Ante un error revisa ese historial antes de reenviar: una respuesta perdida puede haber sido procesada por el receptor.

    API de Suscripciones

    Una suscripción genera un link de pago cada período y le avisa al cliente por el canal que elijas.

    Endpoints

    Todos requieren autenticación (Authorization: Bearer o el header appKey).

    MétodoRutaPara qué
    POST/v1/subscription/makeCrear una suscripción
    POST/me/subscriptionsListar paginado, con filtros
    GET/subscriptions/:id/detailsDetalle con sus renovaciones y links
    POST/v1/subscriptions/:id/cancelbyownerCancelar

    Crear una Suscripción

    POST /v1/subscription/make
    curl -X POST https://api.pabilo.app/v1/subscription/make \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer TU_API_KEY" \
      -d '{
        "name": "Plan Premium",
        "description": "Acceso mensual",
        "currency": "USD",
        "notificationMedium": "email",
        "user_bank_id": "685725869e6febc736848bf2",
        "pay_first": true,
        "webhook_url": "https://tu-sitio.com/webhook/pabilo",
        "items": [
          { "product_id": "ID_DEL_PRODUCTO_CATALOGO", "quantity": 1 },
          { "name": "Mantenimiento", "unit_price": 5, "quantity": 1 }
        ],
        "uniqueClient": {
          "clientName": "Juan Pérez",
          "clientPhone": "+584121234567",
          "clientEmail": "[email protected]"
        }
      }'

    Body de la Petición

    CampoTipoRequeridoDescripción
    namestring✅ SíNombre de la suscripción
    descriptionstring✅ SíSe muestra al cliente en cada aviso
    user_bank_idstring✅ SíCuenta bancaria donde se cobra. Cómo obtener el ID
    currencystring❌ OpcionalVEF (default), USD, EUR, USDT
    notificationMediumstring❌ Opcionalemail (default), whatsapp, sms. Ver abajo
    pay_firstboolean❌ Opcionaltrue: nace pending y espera el primer pago. false: nace active
    webhook_urlstring❌ OpcionalSe propaga a cada link de pago que genere la suscripción
    itemsarray⚠️ Uno de los tresDesglose de lo que se cobra. Si viene, gana sobre uniqueProduct y branchProductId
    uniqueProductobject⚠️ Uno de los tres{ productName, productPrice }
    branchProductIdstring⚠️ Uno de los tresID de un producto del catálogo. Valida pertenencia: da 404 si es de otra cuenta.
    uniqueClientobject⚠️ Uno de los dos clientes{ clientName, clientPhone, clientEmail }
    branchClientIdstring⚠️ Uno de los dos clientesID de un cliente registrado. Valida pertenencia: da 404 si es de otra cuenta.

    Respuesta de Ejemplo

    json
    {
      "message": "Subscription created successfully",
      "subscription": {
        "id": "6a662432d95326f46d526271",
        "created_at": "2026-08-01T12:00:00Z",
        "updated_at": "2026-08-01T12:00:00Z",
        "name": "Plan Premium",
        "description": "Acceso mensual",
        "subscriptionPeriodType": "month",
        "renovationDate": null,
        "renovationIsPaid": false,
        "status": "pending",
        "renovationCount": 0,
        "renovationLimitType": "",
        "clientType": "unique",
        "uniqueClient": {
          "clientName": "Juan Pérez",
          "clientPhone": "+584121234567",
          "clientEmail": "[email protected]",
          "clientCode": ""
        },
        "items": [
          {
            "product_id": "ID_DEL_PRODUCTO_CATALOGO",
            "name": "Plan Premium",
            "quantity": 1,
            "unit_price": 25,
            "currency": "USD"
          }
        ],
        "statusAt": "2026-08-01T12:00:00Z",
        "payFirst": true,
        "userBankId": "685725869e6febc736848bf2",
        "userId": "685725869e6febc736848bf1",
        "webhook": "https://tu-sitio.com/webhook/pabilo",
        "currency": "USD",
        "notificationMedium": "email"
      }
    }

    Nota el detalle: al crear se envía webhook_url, pero en la respuesta el campo se llama webhook.

    Medio de Notificación

    Cada suscripción declara un solo canal por el que se le avisa al cliente del cobro, la renovación y el vencimiento. Los medios son excluyentes: con email no sale WhatsApp, y viceversa.

    ValorDato de contacto que exigeDisponibilidad
    emailCorreo del clienteSiempre disponible. Es el valor por defecto
    whatsappTeléfono del clienteRequiere habilitación
    smsTeléfono del clienteRequiere habilitación

    De dónde sale el contacto

    Depende de si el cliente es único o del catálogo:

    • Cliente único: de uniqueClient.clientEmail y uniqueClient.clientPhone.
    • Cliente de sucursal: del email y el phone del cliente registrado. Si ese cliente no tiene correo, no puedes usar el medio email hasta que se lo agregues con la API de clientes.

    Hace falta al menos uno de los dos datos, y el que exija el medio elegido. Un teléfono que el parser no entiende cuenta como ausente: debe empezar por +, 0, 4 o 58.

    Errores al crear

    Todos llegan con status 400 y "error": "BAD_REQUEST". El message es la cadena completa, tal cual la recibes.

    messageCausa
    bad request: invalid currency, supported: VEF, USD, EUR, USDTMoneda no soportada
    bad request: invalid notificationMedium, supported: sms, whatsapp, emailMedio fuera del enum
    bad request: notificationMedium sms is not enabled for this accountEl medio no está habilitado para tu cuenta
    bad request: uniqueClient or branchClientId is requiredNo mandaste ningún cliente
    bad request: uniqueProduct or branchProductId is requiredNo mandaste ningún producto
    bad request: client phone or email is required: error building subscriptionEl cliente no tiene ni teléfono ni correo
    bad request: notificationMedium email requires a client email: error building subscriptionMedio email sin correo
    bad request: notificationMedium whatsapp requires a valid client phone: error building subscriptionMedio whatsapp o sms sin teléfono válido
    bad request: product is required: error building subscriptionProducto vacío tras validar
    bad request: client is required: error building subscriptionCliente vacío tras validar

    El catálogo completo de códigos está en Errores de la API.

    Ciclo de vida

    El período es mensual. Cada cobro genera un link de pago que hereda el webhook_url de la suscripción, así que tu sistema se entera igual que con un link suelto.

    EstadoQué significa
    pendingEsperando pago. Es el estado inicial con pay_first: true, y al que vuelve cuando vence una renovación impaga
    activeAl día
    cancelledCancelada por el dueño o automáticamente por falta de pago
    inactivePausada
    completedLlegó a su límite de renovaciones

    Avisos automáticos

    Un proceso diario recorre las suscripciones y notifica al cliente por su notificationMedium:

    • 4 días y 1 día antes de la fecha de renovación: recordatorio con el link de pago.
    • El día de la renovación, si no está pagada: la suscripción pasa a pending y se avisa que el pago está pendiente.
    • 3 días después sin pagar: se cancela automáticamente, se avisa al cliente y se anulan los links de pago pendientes.

    Listar Mis Suscripciones

    POST /me/subscriptions
    curl -X POST "https://api.pabilo.app/me/subscriptions?page=1&limit=10&status=active" \
      -H "Authorization: Bearer TU_API_KEY"

    El método declarado es QUERY, pero el servidor lo registra como POST, así que ambos funcionan.

    Parámetros

    ParámetroTipoDescripción
    pageintegerNúmero de página (default: 1)
    limitintegerResultados por página (default: 10)
    statusstringFiltrar por estado
    searchstringBuscar por ID de suscripción
    json
    {
      "message": "Subscriptions fetched successfully",
      "subscriptions": [ … ],
      "total": 1,
      "page": 1,
      "limit": 10
    }

    Detalle de una suscripción

    Devuelve la suscripción con el cliente y el producto ya resueltos, más el historial de renovaciones con su link de pago.

    GET /subscriptions/:id/details
    curl -X GET https://api.pabilo.app/subscriptions/6a662432d95326f46d526271/details \
      -H "Authorization: Bearer TU_API_KEY"
    json
    {
      "message": "Subscriptions fetched successfully",
      "data": {
        "subscription": { … },
        "subscriptionRenovationsPaymentLinks": [ … ]
      }
    }

    Cancelar una Suscripción

    Pasa la suscripción a cancelled, anula sus links de pago no cobrados y le avisa al cliente por su medio de notificación.

    POST /v1/subscriptions/:id/cancelbyowner
    curl -X POST https://api.pabilo.app/v1/subscriptions/6a662432d95326f46d526271/cancelbyowner \
      -H "Authorization: Bearer TU_API_KEY"
    json
    {
      "message": "Subscriptions fetched successfully",
      "data": { "subscription": { "status": "cancelled", … } }
    }

    El message de esta respuesta dice «fetched» por un copy-paste histórico; la cancelación sí se aplicó. Guíate por subscription.status. Cancelar una ya cancelada devuelve 400 con bad request: subscription is already cancelled.

    Cobros, clientes y productos

    Usa el mismo client_id para identificar al comprador, tenga o no credenciales B2B2B. Asócialo en Betaserio, enlaces y suscripciones para consultar lo cobrado por cliente y descargar reportes.

    Ver parámetros, ejemplos y API de reportes JSON / CSV