Documentación

Referencia completa de la API REST de Apruvly.

Integraciones

Primeros pasos

Todo lo que necesitas para empezar a automatizar aprobaciones en minutos.

La API de Apruvly es una API JSON RESTful. Todas las solicitudes deben autenticarse con una clave de API. Las respuestas son siempre JSON, salvo cuando la respuesta está vacía (204).

URL base
https://api.apruvly.io/api/v1
Ejemplo rápido

Crea un flujo de aprobación de un solo paso con un único comando curl:

curl -X POST https://api.apruvly.io/api/v1/workflow \
  -H "Authorization: Bearer wf_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "object": {
    "title": "Q1 Marketing Budget",
    "description": "Marketing budget for Q1, $18k total"
  },
  "expires": "48h",
  "start": "step1",
  "workflow": {
    "step1": {
      "type": "email",
      "data": {
        "to": ["[email protected]"],
        "subject": "Q1 Marketing Budget – $18k",
        "body": "Please review the budget breakdown in the linked document and share your decision."
      }
    }
  }
}'

Autenticación

Todas las solicitudes de la API requieren autenticación mediante una clave de API.

Pasa tu clave de API en el encabezado Authorization como token Bearer. Puedes crear y gestionar claves de API desde el panel.

Nunca expongas tu clave de API en código del lado del cliente ni en repositorios públicos. Rótala de inmediato si se ve comprometida.
Formato del encabezado
Authorization: Bearer wf_YOUR_API_KEY

Puedes generar una clave de API desde la sección Claves de API del panel.

POST

Crear flujo de trabajo

/api/v1/workflow

Crea un nuevo flujo de aprobación e inicia de inmediato el primer paso.

Cuerpo de la solicitud
Campo Tipo Obligatorio Descripción
object object Metadatos sobre el elemento que se aprueba.
object.title string Título legible para el flujo de trabajo. Máx. 200 caracteres.
object.description string No Descripción más larga opcional de lo que se está aprobando.
object.links string[] No Lista opcional de URLs relacionadas con la aprobación (documentos, archivos, etc.).
object.tags string[] No Lista opcional de etiquetas para filtrar y organizar.
external_id string No Id de correlación de negocio opcional suministrado por el llamante (máx. 128 caracteres): p. ej. número de contrato, ticket de CRM, referencia de pedido. Requiere el plan Growth o superior. Debe ser único por cuenta.
expires duration Cuánto tiempo permanece abierto el flujo de trabajo antes de caducar. Formato: 30s, 15m, 2h, 7d, 2w.
start string La clave del primer paso a ejecutar (debe coincidir con una clave en workflow).
workflow map[string]Step Mapa de claves de paso a objetos Step que definen la cadena de aprobación.
on map[string]Action[] No Mapa de eventos del ciclo de vida a listas de acciones (webhook, email, twilio-sms) que se disparan automáticamente. Eventos: workflow_created, workflow_approved, workflow_rejected, workflow_expired, workflow_canceled, workflow_completed, step_approved, step_escalated, user_approval, user_rejection.
disable_email_fallback boolean No Desactiva el respaldo por correo predeterminado. Cuando se omite (recomendado), la plataforma entrega automáticamente la solicitud de aprobación por correo si una notificación de integración (Teams, Slack, WhatsApp) falla. Ponlo en true para omitir el respaldo y aceptar el fallo original.
debug boolean No Activa el modo de depuración. Todas las notificaciones (email, Teams, Slack, WhatsApp), webhooks y escalados se suprimen: el flujo de trabajo recorre toda su lógica sin contactar con ningún participante. Útil para probar el flujo sin disparar comunicaciones reales.
Incluso en modo de depuración, los créditos se consumen con normalidad. El modo de depuración solo suprime las comunicaciones externas: no afecta a la facturación.
Solicitud de ejemplo
curl -X POST https://api.apruvly.io/api/v1/workflow \
  -H "Authorization: Bearer wf_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "object": {
    "title": "Contract Sign-off",
    "description": "Legal review for client contract #4821",
    "links": ["https://drive.example.com/contracts/4821"],
    "tags": ["legal", "contract"]
  },
  "external_id": "CONTRACT-2025-0042",
  "expires": "72h",
  "start": "legal-review",
  "workflow": {
    "legal-review": {
      "type": "email",
      "data": {
        "to": ["[email protected]"],
        "subject": "Approval Request: Contract #4821",
        "body": "Please review and approve contract #4821."
      },
      "approved": "ceo-approval",
      "escalation": {
        "type": "email",
        "after": "24h",
        "data": {
          "to": ["[email protected]"],
          "subject": "Escalation: Contract #4821 pending approval",
          "body": "Contract #4821 has not been reviewed. Please take action."
        }
      }
    },
    "ceo-approval": {
      "type": "email",
      "data": {
        "to": ["[email protected]"],
        "subject": "Final Approval: Contract #4821",
        "body": "Legal review is complete. Please provide final approval."
      }
    }
  }
}'
Respuesta de ejemplo 202 Accepted
{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "externalId": "CONTRACT-2025-0042"
  }
}

IDs de correlación de negocio (external_id)

Asocia tu propia referencia de negocio (número de contrato, ticket de CRM, id de despliegue) al crear un flujo de trabajo, y luego consulta su estado o cancélalo sin almacenar el UUID de la plataforma. Requiere el plan Growth o superior. Máx. 128 caracteres; permitidos: letras, dígitos y . _ : / -. Único por cuenta.

402 cuando tu plan es inferior a Growth. 409 cuando otro flujo de trabajo de tu cuenta ya usa el mismo external_id.
Respuesta de ejemplo 402 Payment Required
{
  "success": false,
  "message": "Tu plan no incluye external_id. Mejora a Growth o superior para asociar un id de correlación de negocio a los flujos de trabajo."
}
Crear flujo de trabajo — Solicitud de ejemplo
curl -X POST https://api.apruvly.io/api/v1/workflow \
  -H "Authorization: Bearer wf_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "object": {
    "title": "Contract Sign-off",
    "description": "Legal review for client contract #4821"
  },
  "external_id": "CONTRACT-2025-0042",
  "expires": "72h",
  "start": "legal-review",
  "workflow": {
    "legal-review": {
      "type": "email",
      "data": {
        "to": ["[email protected]"],
        "subject": "Approval Request: Contract #4821",
        "body": "Please review and approve contract #4821."
      }
    }
  }
}'
Respuesta de ejemplo 202 Accepted
{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "externalId": "CONTRACT-2025-0042"
  }
}
Obtener por external_id — Solicitud de ejemplo

Devuelve la misma carga que GET /workflow/{id}, buscado por el external_id suministrado al crearlo. Requiere el plan Growth o superior.

curl https://api.apruvly.io/api/v1/workflow/external/CONTRACT-2025-0042 \
  -H "Authorization: Bearer wf_YOUR_API_KEY"
Respuesta de ejemplo 200 OK
{
  "success": true,
  "data": {
    "id":                  "550e8400-e29b-41d4-a716-446655440000",
    "externalId":          "CONTRACT-2025-0042",
    "status":              "pending",
    "currentStep":         "legal-review",
    "createdAt":           "2025-01-15T10:00:00Z",
    "expiresAt":           "2025-01-18T10:00:00Z",
    "decisions": []
  }
}
Cancelar flujo de trabajo — Solicitud de ejemplo
curl -X DELETE https://api.apruvly.io/api/v1/workflow/external/CONTRACT-2025-0042 \
  -H "Authorization: Bearer wf_YOUR_API_KEY"
Respuesta de ejemplo 200 OK
{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000"
  }
}
Listar flujos de trabajo — Solicitud de ejemplo
curl "https://api.apruvly.io/api/v1/workflows/search?external_id=CONTRACT-2025-0042" \
  -H "Authorization: Bearer wf_YOUR_API_KEY"
Respuesta de ejemplo 200 OK
{
  "success": true,
  "data": [
    {
      "id":             "550e8400-e29b-41d4-a716-446655440000",
      "title":          "Contract Sign-off",
      "external_id":    "CONTRACT-2025-0042",
      "current_status": "pending",
      "current_step":   "legal-review",
      "created_at":     "2025-01-15T10:00:00Z",
      "expires_at":     "2025-01-18T10:00:00Z",
      "completed_at":   null
    }
  ]
}
POST

Validar flujo de trabajo

/api/v1/workflow/validate

Valida la configuración de un flujo de trabajo sin crearlo. Útil para comprobar tu carga antes de enviarla.

Este endpoint no requiere autenticación y no consume créditos. Solo comprueba si la configuración es válida.
Solicitud de ejemplo
curl -X POST https://api.apruvly.io/api/v1/workflow/validate \
  -H "Authorization: Bearer wf_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "object": {
    "title": "Test Workflow"
  },
  "expires": "24h",
  "start": "step1",
  "workflow": {
    "step1": {
      "type": "email",
      "data": {
        "to": ["[email protected]"],
        "subject": "Test Approval",
        "body": "Please approve this test request."
      }
    }
  }
}'
Respuesta de ejemplo 200 OK
{
  "success": true
}
GET

Obtener flujo de trabajo

/api/v1/workflow/{id}

Recupera el estado completo de un flujo de trabajo, incluido su registro de actividad y su historial de decisiones.

Parámetros de ruta
Campo Tipo Descripción
id uuid El ID del flujo de trabajo devuelto cuando se creó el flujo.
Solicitud de ejemplo
curl https://api.apruvly.io/api/v1/workflow/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer wf_YOUR_API_KEY"
Respuesta de ejemplo 200 OK
{
  "success": true,
  "data": {
    "id":                  "550e8400-e29b-41d4-a716-446655440000",
    "externalId":          "CONTRACT-2025-0042",
    "status":              "pending",
    "currentStep":         "ceo-approval",
    "currentEscalation":  0,
    "createdAt":           "2025-01-15T10:00:00Z",
    "expiresAt":           "2025-01-18T10:00:00Z",
    "nextTickAt":          "2025-01-16T10:00:00Z",
    "decisions": [
      {
        "user":        "[email protected]",
        "is_approved": true,
        "ip":          "203.0.113.42",
        "decisionAt":  "2025-01-15T14:22:00Z"
      }
    ]
  }
}
GET

Listar flujos de trabajo

/api/v1/workflows/search

Devuelve una lista paginada de los flujos de trabajo que pertenecen al usuario autenticado.

Parámetros de consulta
Campo Tipo Descripción
status string Filtrar por estado: pending, approved, rejected, expired, canceled
query string Búsqueda de texto completo en el título del flujo de trabajo.
step string Filtrar por nombre del paso activo actual (p. ej. legal-review).
from RFC3339 Filtra los flujos de trabajo creados en o después de esta marca de tiempo (formato RFC 3339, p. ej. 2025-01-01T00:00:00Z).
to RFC3339 Filtra los flujos de trabajo creados en o antes de esta marca de tiempo (formato RFC 3339, p. ej. 2025-01-31T23:59:59Z).
tags string Filtrar por etiquetas del flujo de trabajo (separadas por comas).
external_id string Coincidencia exacta con el id de correlación de negocio suministrado por el llamante. Requiere el plan Growth o superior.
limit integer Número máximo de resultados a devolver (por defecto 50, máx. 500). Max results per page (default 50, max 500).
Solicitud de ejemplo
curl "https://api.apruvly.io/api/v1/workflows/search?status=pending&query=contract" \
  -H "Authorization: Bearer wf_YOUR_API_KEY"
Respuesta de ejemplo 200 OK
{
  "success": true,
  "data": [
    {
      "id":             "550e8400-e29b-41d4-a716-446655440000",
      "title":          "Contract Sign-off",
      "external_id":    "CONTRACT-2025-0042",
      "current_status": "pending",
      "current_step":   "ceo-approval",
      "created_at":     "2025-01-15T10:00:00Z",
      "expires_at":     "2025-01-18T10:00:00Z",
      "completed_at":   null
    }
  ]
}
GET

Flujos de trabajo recientes

/api/v1/workflows/recent

Devuelve los flujos de trabajo creados más recientemente para el usuario autenticado.

Solicitud de ejemplo
curl "https://api.apruvly.io/api/v1/workflows/recent" \
  -H "Authorization: Bearer wf_YOUR_API_KEY"
GET

Facturación

/api/v1/billing

Devuelve la suscripción, el plan, el saldo de créditos y el resumen de uso del usuario autenticado.

Solicitud de ejemplo
curl "https://api.apruvly.io/api/v1/billing" \
  -H "Authorization: Bearer wf_YOUR_API_KEY"
GET

Integraciones

/api/v1/integrations

Gestiona las credenciales de canales de terceros (Slack, MS Teams, Twilio, etc.) a través de la API REST.

MétodoEndpointDescripción
GET/api/v1/integrationsLista el estado de configuración de cada integración compatible.
GET/api/v1/integrations/{integration}Devuelve el estado de configuración de una integración (los secretos nunca se incluyen).
PUT/api/v1/integrations/{integration}Crea o reemplaza las credenciales de una integración.
DELETE/api/v1/integrations/{integration}Elimina las credenciales almacenadas de una integración.
DELETE

Cancelar flujo de trabajo

/api/v1/workflow/{id}

Cancela un flujo de trabajo pendiente. Los flujos completados o caducados no se pueden cancelar.

Solo se pueden cancelar los flujos de trabajo en estado pendiente. Devuelve 406 si el flujo ya está completado, rechazado o caducado.

También puedes cancelar por el id de negocio que estableciste al crearlo: consulta IDs de correlación de negocio (external_id). IDs de correlación de negocio (external_id)

Parámetros de ruta
Campo Tipo Descripción
id uuid El ID del flujo de trabajo devuelto cuando se creó el flujo.
Solicitud de ejemplo
curl -X DELETE https://api.apruvly.io/api/v1/workflow/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer wf_YOUR_API_KEY"
Respuesta de ejemplo 200 OK
{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000"
  }
}
PUT

Aprobar / Rechazar

/api/v1/workflow/{id}/{challenge}/approve o /api/v1/workflow/{id}/{challenge}/reject

Registra una decisión de aprobación o rechazo para un paso del flujo de trabajo. La acción (aprobar o rechazar) se determina por el sufijo de la ruta de la URL, no por el cuerpo de la solicitud. No se requiere cuerpo de solicitud.

El UUID del desafío es único por aprobador y va incrustado en el enlace del correo de notificación. No se requiere encabezado de autenticación para este endpoint: el token del desafío es la prueba de identidad.
Parámetros de ruta
Campo Tipo Descripción
id uuid El ID del flujo de trabajo devuelto cuando se creó el flujo.
challenge uuid El token de desafío UUID por aprobador incluido en el enlace del correo de notificación.
Solicitud de ejemplo
# Approve
curl -X PUT https://api.apruvly.io/api/v1/workflow/550e8400-e29b-41d4-a716-446655440000/7a9f1c2d-4b3e-48f6-9d8c-1a2b3c4d5e6f/approve \
  -H "Authorization: Bearer wf_YOUR_API_KEY"

# Reject
curl -X PUT https://api.apruvly.io/api/v1/workflow/550e8400-e29b-41d4-a716-446655440000/7a9f1c2d-4b3e-48f6-9d8c-1a2b3c4d5e6f/reject \
  -H "Authorization: Bearer wf_YOUR_API_KEY"
Respuesta de ejemplo 200 OK
{
  "success": true
}
CRUD

Directorio

/api/v1/directory

Gestiona tu libreta de direcciones de áreas (equipos) y personas. Los contactos alimentan el respaldo por correo en el momento de la notificación y vinculan a los destinatarios para las analíticas entre canales.

Disponible en todos los planes de pago, pero el cliente debe activar la función primero en la consola web en /directory. Las solicitudes a este endpoint devuelven 402 (plan no elegible) o 409 (función desactivada) hasta que se cumplan ambas condiciones.
La consola web en /directory acepta cargas CSV como un atajo más amigable a los endpoints masivos, práctico para usuarios no técnicos. La validación del lado del servidor, los límites del plan y la transacción de todo o nada son exactamente los mismos que en los endpoints masivos JSON.
Áreas
MétodoEndpointDescripción
GET/api/v1/directory/areasLista todas las áreas activas.
POST/api/v1/directory/areasCrea una nueva área.
POST/api/v1/directory/areas/bulkCrea hasta 100 áreas en una sola llamada.
PUT/api/v1/directory/areas/bulkRenombra muchas áreas a la vez. Cada elemento debe incluir el id del área.
GET/api/v1/directory/areas/{id}Obtiene un área por id.
PUT/api/v1/directory/areas/{id}Renombra un área.
DELETE/api/v1/directory/areas/{id}Elimina un área (las pertenencias se eliminan en cascada; las personas se conservan).
Personas
MétodoEndpointDescripción
GET/api/v1/directory/people?q=&area=&page=Lista paginada de personas. Filtros: q (texto), area (uuid), page (basado en 1).
POST/api/v1/directory/peopleCrea una persona con pertenencias y contactos.
POST/api/v1/directory/people/bulkCrea hasta 1000 personas en una sola llamada (con sus pertenencias y contactos).
PUT/api/v1/directory/people/bulkActualiza muchas personas a la vez (nombre, pertenencias y contactos). Cada elemento debe incluir el id de la persona.
GET/api/v1/directory/people/{id}Obtiene una persona con todas sus pertenencias y contactos.
PUT/api/v1/directory/people/{id}Reemplaza el nombre visible, las pertenencias a áreas y los contactos en una sola llamada.
DELETE/api/v1/directory/people/{id}Elimina la persona (los contactos y las pertenencias se eliminan en cascada).
Solicitud de ejemplo — Crea una persona con pertenencias y contactos.
curl -X POST https://api.apruvly.io/api/v1/directory/people \
  -H "Authorization: Bearer wf_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "display_name": "Ana Souza",
    "area_ids": ["6c2b6e80-1f74-4cf2-9e2f-0d0e3b9b0001"],
    "contacts": [
      { "provider": "email", "address": "[email protected]", "label": "work" },
      { "provider": "twilio-sms", "address": "+5511999999999" }
    ]
  }'
Respuesta de ejemplo 201 Created
{
  "success": true,
  "data": {
    "id": "a4d1f0c6-2d24-49b3-9e3c-7a2e6c4b0001",
    "display_name": "Ana Souza",
    "is_active": true,
    "area_ids": ["6c2b6e80-1f74-4cf2-9e2f-0d0e3b9b0001"],
    "contacts": [
      { "id": "…", "provider": "email", "address": "[email protected]", "label": "work" },
      { "id": "…", "provider": "twilio-sms", "address": "+5511999999999" }
    ]
  }
}
Operaciones masivas

Los endpoints masivos aceptan un array de elementos bajo un único campo «items». La creación está limitada por solicitud (100 áreas, 1000 personas) y las actualizaciones se limitan al doble del tamaño del plan del cliente para el recurso correspondiente.

Solicitud de ejemplo — Crea hasta 1000 personas en una sola llamada (con sus pertenencias y contactos).
curl -X POST https://api.apruvly.io/api/v1/directory/people/bulk \
  -H "Authorization: Bearer wf_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      {
        "display_name": "Ana Souza",
        "area_ids": ["6c2b6e80-1f74-4cf2-9e2f-0d0e3b9b0001"],
        "contacts": [
          { "provider": "email", "address": "[email protected]", "label": "work" }
        ]
      },
      {
        "display_name": "Bruno Lima",
        "contacts": [
          { "provider": "twilio-sms", "address": "+5511988887777" }
        ]
      }
    ]
  }'
Respuesta de ejemplo 201 Created
{
  "success": true,
  "data": {
    "count": 2,
    "items": [
      { "id": "a4d1f0c6-…", "display_name": "Ana Souza", "area_ids": ["6c2b6e80-…"], "contacts": ["…"] },
      { "id": "f10b2e8a-…", "display_name": "Bruno Lima", "area_ids": [], "contacts": ["…"] }
    ]
  }
}

Todo el lote se procesa junto: si una sola entrada no es válida, la solicitud se rechaza y no se guarda nada.

Ámbitos requeridos

Cada endpoint requiere el ámbito de clave de API correspondiente. Concede los ámbitos en Claves de API en la consola.

ÁmbitosDescripción
api:directory:listAPI · Directorio · listar
api:directory:readAPI · Directorio · leer
api:directory:writeAPI · Directorio · crear / actualizar
api:directory:bulkAPI · Directorio · operaciones masivas
api:directory:deleteAPI · Directorio · eliminar
Formatos de dirección de contacto

Cada contacto es un par (proveedor, dirección). Solo se aceptan los proveedores configurados en /integrations (además del correo).

ProveedorDirección
email, slack, ms-teamsE-mail address
twilio-sms, twilio-whatsapp, whatsappE.164 phone (e.g. +5511999999999)
telegramNumeric chat id
discord17–20 digit snowflake

Los robots de grupo de DingTalk no se almacenan en el directorio: difunden a un grupo, no a un contacto individual.

Errores
EstadoDescripción
400Falta un campo obligatorio o la dirección de contacto no es válida (p. ej. correo o teléfono mal formado).
402El plan actual no incluye la función de directorio.
409La función de directorio está desactivada: actívala primero en /directory en la consola web.

Acciones

Efectos secundarios que el motor dispara cuando ocurren eventos del ciclo de vida del flujo de trabajo.

Usa el campo `on` para registrar acciones para los eventos del ciclo de vida del flujo de trabajo. Cada acción tiene un tipo (webhook, email o twilio-sms) y una carga de datos. Cuando se dispara un evento, todas las acciones se ejecutan en orden.

Formas envuelta y plana

Cada acción es un objeto JSON que puede serializarse de dos formas. La forma envuelta ({"type":"...", "data":{...}}) es la forma canónica que produce la API y la única aceptada para twilio-sms. La forma plana infiere el tipo a partir de los campos de la carga (url → webhook, to → email) y se mantiene por compatibilidad con versiones anteriores.

{
  "on": {
    "workflow_approved": [
      { "type": "webhook",    "data": { "url": "https://example.com/hooks/approved", "method": "POST" } },
      { "type": "email",      "data": { "to": ["[email protected]"], "subject": "Approved", "body": "Workflow ${id} is approved." } },
      { "type": "twilio-sms", "data": { "to": ["+14155552671"], "body": "Workflow ${id} approved" } }
    ]
  }
}
Eventos del ciclo de vida
Evento Descripción
workflow_created Se dispara cuando un flujo de trabajo se crea correctamente.
workflow_approved Se dispara cuando todo el flujo de trabajo alcanza un estado final de aprobado.
workflow_rejected Se dispara cuando todo el flujo de trabajo se rechaza.
workflow_expired Se dispara cuando el flujo de trabajo caduca antes de llegar a una decisión final.
workflow_canceled Se dispara cuando el flujo de trabajo se cancela explícitamente mediante la API.
workflow_completed Se dispara cuando el flujo de trabajo alcanza cualquier estado terminal (aprobado, rechazado, caducado o cancelado).
step_approved Se dispara cuando un paso individual se aprueba y el flujo de trabajo avanza al siguiente paso.
step_escalated Se dispara cuando se activa el temporizador de escalado de un paso y se envía la notificación de escalado.
user_approval Se dispara cada vez que un único usuario emite un voto de aprobación en un paso.
user_rejection Se dispara cada vez que un único usuario emite un voto de rechazo en un paso.
WebhookAction type: "webhook"

Envía una solicitud HTTP a un endpoint externo. Los hosts privados y de bucle invertido se rechazan en el momento del envío.

Campo Tipo Obligatorio Descripción
type string Debe ser «webhook».
url string La URL de destino. Debe ser un URI válido.
method string No Método HTTP: GET, POST, PUT, PATCH o DELETE. Por defecto, POST.
headers object No Encabezados HTTP personalizados enviados con la solicitud. Útiles para tokens de autenticación o claves de API.
body object|string No Cuerpo de la solicitud. Admite interpolación de variables con la sintaxis ${variable}.
timeout duration No Duración del tiempo de espera de la solicitud (p. ej. «30s», «5m»). Por defecto, la configuración del servidor.
async boolean No Si es true, la solicitud se envía de forma asíncrona y no bloquea el flujo de trabajo.
skipCertVerify boolean No Si es true, omite la verificación del certificado TLS. Úsalo solo en entornos de desarrollo.
EmailAction type: "email"

Envía un correo a través de tu SMTP personalizado (cuando está configurado) o el mensajero del sistema.

Campo Tipo Obligatorio Descripción
to string[] Direcciones de destinatario. Se requiere al menos una.
subject string No Línea de asunto del correo.
body string No Cuerpo del correo. Admite interpolación de ${variable}.
cc string[] No Lista opcional de destinatarios en CC.
bcc string[] No Lista opcional de destinatarios en CCO.
html boolean No Si es verdadero, el cuerpo se envía como HTML; de lo contrario, como texto sin formato.
SmsAction type: "twilio-sms"

Envía un SMS de tipo «dispara y olvida» a través de Twilio. Solo informativo: sin correlación de códigos cortos ni seguimiento de respuestas.

Campo Tipo Obligatorio Descripción
to string[] Números de teléfono en formato E.164 (p. ej. +14155552671). Las entradas duplicadas y no válidas se rechazan.
body string Texto del mensaje (hasta 1600 caracteres). Admite interpolación de ${variable}.
Requiere un plan con Twilio habilitado y una integración de Twilio a nivel de inquilino. Los destinatarios en la lista de exclusión se omiten y se aplica la cuota diaria del inquilino. Debe usarse la forma envuelta ({"type":"twilio-sms", ...}) para evitar ambigüedad con el correo.
Interpolación de variables

Puedes usar las siguientes variables dentro de los valores del cuerpo del webhook. Se reemplazan automáticamente en el momento de la ejecución.

Variable Descripción
${id} El UUID único del flujo de trabajo.
${status} Estado actual del flujo de trabajo (p. ej. approved, rejected, expired).
${current_step} El identificador del paso actualmente activo.
${escalation_level} Nivel de profundidad de escalado actual (0 si no se ha producido ningún escalado).
Solicitud de ejemplo
{
  "on": {
    "workflow_approved": [
      {
        "type": "webhook",
        "data": {
          "url":     "https://api.yourapp.com/webhooks/approved",
          "method":  "POST",
          "headers": { "Authorization": "Bearer your-token" },
          "body": {
            "workflow_id":  "${id}",
            "status":       "${status}",
            "current_step": "${current_step}"
          },
          "timeout": "30s"
        }
      }
    ],
    "workflow_rejected": [
      {
        "type": "webhook",
        "data": {
          "url":   "https://api.yourapp.com/webhooks/rejected",
          "async": true
        }
      }
    ],
    "step_approved": [
      {
        "type": "webhook",
        "data": {
          "url":  "https://api.yourapp.com/webhooks/step-done",
          "body": {
            "step": "${current_step}"
          }
        }
      }
    ]
  }
}
Acciones por paso

Además de los eventos a nivel de flujo de trabajo, cada paso puede registrar sus propias acciones que se disparan cuando ESE paso se aprueba o se rechaza, independientemente del resultado final del flujo. Usa `step.actions.approved` y `step.actions.rejected` para activar webhooks o correos por decisión.

{
  "workflow": {
    "review": {
      "type": "email",
      "data": {
        "to":      ["[email protected]"],
        "subject": "Please review",
        "body":    "Approve or reject ${id}"
      },
      "actions": {
        "approved": [
          {
            "type": "webhook",
            "data": {
              "url":    "https://example.com/hooks/review-approved",
              "method": "POST"
            }
          }
        ],
        "rejected": [
          {
            "type": "email",
            "data": {
              "to":      ["[email protected]"],
              "subject": "Review rejected",
              "body":    "${id} was rejected"
            }
          }
        ]
      }
    }
  }
}

Coste: cada webhook cuenta como 1 crédito; cada destinatario en acciones de email o twilio-sms cuenta como 1 crédito por destinatario. Las CC y CCO en acciones de correo no se cobran.

Coste en créditos

Cada paso cuesta 1 crédito más 1 por cada nivel de escalado configurado. Las acciones de entrega externa añaden un único recargo fijo compartido entre webhook y twilio-sms.

Tipo Coste
webhook +1 por flujo de trabajo (independientemente de cuántos webhooks o eventos).
email Sin coste adicional.
twilio-sms +1 por flujo de trabajo (compartido con webhook: máximo +1 en total).
twilio-whatsapp +1 por flujo de trabajo (compartido con webhook: máximo +1 en total).
discord +1 por flujo de trabajo (independientemente de cuántos webhooks o eventos).

Los créditos se debitan una sola vez al crear el flujo de trabajo. No hay cargo por envío.

Referencia de objetos

Descripción detallada de todos los objetos de solicitud y respuesta.

Step
Campo Tipo Obligatorio Descripción
type string Tipo de notificación. Actualmente compatible: email, ms-teams, slack, whatsapp, telegram, dingtalk, discord, twilio-sms, twilio-whatsapp
data EmailData | MSTeamsData | SlackData | WhatsAppData | TelegramData | DingTalkData | DiscordData | TwilioSMSData | TwilioWhatsAppData Carga de la notificación. La forma depende del tipo.
minApprovals integer No Número mínimo de aprobaciones necesarias para avanzar. Por defecto: 1.
minRejections integer No Número mínimo de rechazos necesarios para rechazar el flujo de trabajo. Por defecto: 1.
approved string No Clave del paso a ejecutar cuando este se apruebe. Omítela para terminar el flujo de trabajo con estado aprobado.
rejected string No Clave del paso a ejecutar cuando este se rechace. Omítela para terminar el flujo de trabajo con estado rechazado.
escalation Escalation No Configuración de escalado opcional que se dispara si los aprobadores no responden a tiempo.
actions {approved, rejected} No Acciones opcionales que se disparan cuando ESTE paso se aprueba o se rechaza, independientemente del resultado final del flujo de trabajo. Consulta la sección de Acciones para ver las formas compatibles. (Acciones por paso)
Channel delivery

La entrega por canal compartido publica un único mensaje de aprobación en un canal, grupo o chat de equipo. Solo los usuarios incluidos en allowList pueden hacer clic en los botones interactivos de Aprobar/Rechazar; el registro de decisiones anota a quien hace clic, no el ID del canal.

Tipo Descripción
slack to: ID de canal (C…). allowList: IDs de usuario de Slack (U…) o correos del espacio de trabajo. Requiere Signing Secret.
ms-teams to: teamId/channelId. allowList: IDs de objeto de Azure AD o correos. Las publicaciones en canal usan una API protegida de Microsoft Graph: tu inquilino debe conceder consentimiento específico de recurso (p. ej. ChannelMessage.Send) en la app de Teams o un permiso de aplicación aprobado por un administrador. El bot de Apruvly debe estar instalado en el equipo de destino.
telegram to: ID de chat de grupo/canal negativo (-100…). allowList: IDs de usuario de Telegram. El bot debe ser miembro del grupo.
discord to: snowflake de canal (17 a 20 dígitos). allowList: snowflakes de usuario de Discord. Requiere URL de interacciones y clave pública.
dingtalk DingTalk siempre difunde al grupo del robot: delivery: "channel" se rechaza.
CardOverride
Campo Tipo Obligatorio Descripción
title string No Título opcional para la tarjeta de notificación o el embed.
description string No Texto opcional que se muestra en el cuerpo de la notificación o en la descripción del embed.
links string[] No URLs opcionales mostradas como botones de acción (p. ej. ver solicitud).
EmailData — usado cuando type = email
Campo Tipo Obligatorio Descripción
to string[] Lista de direcciones de correo de los aprobadores de este paso.
subject string Línea de asunto del correo de aprobación.
body string Mensaje en texto plano o HTML para el aprobador. object.title y object.description aparecen automáticamente en una tarjeta de resumen; los botones de aprobar/rechazar se añaden por ti.
cc string[] No Lista opcional de destinatarios en CC.
bcc string[] No Lista opcional de destinatarios en CCO.
isHtml boolean No Ponlo en true si el cuerpo contiene marcado HTML. Por defecto: false.
Variables del cuerpo del correo

Estos marcadores de posición se pueden usar en los campos de asunto y cuerpo.

Variable Descripción
${title} Título del objeto del flujo de trabajo (también se muestra en la tarjeta de resumen).
${description} Descripción del objeto del flujo de trabajo (también se muestra en la tarjeta de resumen).
${id} El UUID único del flujo de trabajo.
${user_email} Dirección de correo del destinatario.
${user_name} Nombre visible del destinatario, o la parte local del correo cuando no hay nombre visible definido.
SlackData — usado cuando type = slack
Campo Tipo Obligatorio Descripción
delivery string No Modo de entrega: omitir o «direct» (por defecto) envía un mensaje por destinatario; «channel» publica un único mensaje en un destino compartido con una lista de permitidos de decisores. Compatible con slack, ms-teams, telegram y discord.
allowList string[] No Cuando la entrega es «channel», lista de correos o IDs de usuario nativos del proveedor autorizados a hacer clic en Aprobar/Rechazar. Obligatoria en modo canal.
to string[] Modo directo: direcciones de correo del espacio de trabajo (un MD por destinatario). Modo canal: IDs de canal de Slack que empiezan por C.
card CardOverride No Anulación opcional por paso del título, la descripción y los enlaces de acción de la notificación. Cuando se omite, se usan los campos del objeto a nivel de flujo de trabajo.
Para la entrega por canal, configura el Signing Secret de Slack y la URL del webhook de Event Subscriptions en /integrations. Invita al bot al canal de destino.
MSTeamsData — usado cuando type = ms-teams
Campo Tipo Obligatorio Descripción
delivery string No Modo de entrega: omitir o «direct» (por defecto) envía un mensaje por destinatario; «channel» publica un único mensaje en un destino compartido con una lista de permitidos de decisores. Compatible con slack, ms-teams, telegram y discord.
allowList string[] No Cuando la entrega es «channel», lista de correos o IDs de usuario nativos del proveedor autorizados a hacer clic en Aprobar/Rechazar. Obligatoria en modo canal.
to string[] Modo directo: direcciones de correo de Azure AD. Modo canal: pares teamId/channelId (un mensaje por entrada).
card CardOverride No Anulación opcional por paso del título, la descripción y los enlaces de acción de la notificación. Cuando se omite, se usan los campos del objeto a nivel de flujo de trabajo.
La entrega por canal publica Adaptive Cards a través de Microsoft Graph (POST /teams/{teamId}/channels/{channelId}/messages). Esta es una API protegida: añade consentimiento específico de recurso en el manifiesto de tu app de Teams (p. ej. ChannelMessage.Send.All) u obtén la aprobación de Microsoft para permisos de aplicación. Instala la app de Apruvly en el equipo de destino y configura la entrega como canal con una allowList.
WhatsAppData — usado cuando type = whatsapp
Campo Tipo Obligatorio Descripción
to string[] Lista de números de teléfono de los aprobadores en formato E.164 (p. ej. +5511999999999).
card CardOverride No Anulación opcional por paso del título, la descripción y los enlaces de acción de la notificación. Cuando se omite, se usan los campos del objeto a nivel de flujo de trabajo.
Requiere que la integración con WhatsApp (Meta) esté configurada. Se contacta con los destinatarios mediante números de teléfono E.164.
TelegramData — usado cuando type = telegram
Campo Tipo Obligatorio Descripción
delivery string No Modo de entrega: omitir o «direct» (por defecto) envía un mensaje por destinatario; «channel» publica un único mensaje en un destino compartido con una lista de permitidos de decisores. Compatible con slack, ms-teams, telegram y discord.
allowList string[] No Cuando la entrega es «channel», lista de correos o IDs de usuario nativos del proveedor autorizados a hacer clic en Aprobar/Rechazar. Obligatoria en modo canal.
to string[] Modo directo: IDs de chat de usuario positivos (p. ej. 123456789). Modo canal: IDs de chat de grupo o canal negativos (p. ej. -1001234567890).
markdown boolean No Cuando es true, el mensaje se envía usando el formato MarkdownV2 de Telegram en lugar de HTML. El campo de descripción puede contener sintaxis MarkdownV2 (p. ej. *negrita*, _cursiva_, `código`). Por defecto: false.
card CardOverride No Anulación opcional por paso del título, la descripción y los enlaces de acción de la notificación. Cuando se omite, se usan los campos del objeto a nivel de flujo de trabajo.
Requiere que la integración con Telegram esté configurada en tu cuenta. Modo directo: los destinatarios deben haber iniciado una conversación con tu bot. Modo canal: el bot debe ser miembro del grupo de destino.
DiscordData — usado cuando type = discord
Campo Tipo Obligatorio Descripción
delivery string No Modo de entrega: omitir o «direct» (por defecto) envía un mensaje por destinatario; «channel» publica un único mensaje en un destino compartido con una lista de permitidos de decisores. Compatible con slack, ms-teams, telegram y discord.
allowList string[] No Cuando la entrega es «channel», lista de correos o IDs de usuario nativos del proveedor autorizados a hacer clic en Aprobar/Rechazar. Obligatoria en modo canal.
to string[] Modo directo: snowflakes de usuario de Discord (17 a 20 dígitos). Modo canal: snowflake de canal. El bot debe compartir un servidor con los destinatarios de MD.
card CardOverride No Anulación opcional por paso del título, la descripción y los enlaces de acción de la notificación. Cuando se omite, se usan los campos del objeto a nivel de flujo de trabajo.
Para la entrega por canal, configura la URL de interacciones y la clave pública de Discord en /integrations. El bot debe tener acceso al canal de destino.
DingTalkData — usado cuando type = dingtalk
Campo Tipo Obligatorio Descripción
to string[] No Números de móvil opcionales (E.164) para @mencionar en la ActionCard del grupo. DingTalk siempre publica en el grupo del robot configurado.
card CardOverride No Anulación opcional por paso del título, la descripción y los enlaces de acción de la notificación. Cuando se omite, se usan los campos del objeto a nivel de flujo de trabajo.
Requiere que la integración con DingTalk esté configurada. Los mensajes se difunden al grupo vinculado al webhook del robot; «to» enumera, de forma opcional, números de móvil para @menciones.
TwilioSMSData — usado cuando type = twilio-sms
Campo Tipo Obligatorio Descripción
to string[] Introduce números de teléfono en formato E.164 (p. ej. +5511999999999). Los destinatarios deben haber dado su consentimiento para recibir SMS.
card CardOverride No Anulación opcional por paso del título, la descripción y los enlaces de acción de la notificación. Cuando se omite, se usan los campos del objeto a nivel de flujo de trabajo.
Requiere que la integración con Twilio esté configurada en tu cuenta y que el plan permita Twilio. Se contacta con los aprobadores por SMS usando su número E.164.
TwilioWhatsAppData — usado cuando type = twilio-whatsapp
Campo Tipo Obligatorio Descripción
to string[] Número de teléfono del remitente de WhatsApp registrado con Twilio, en formato E.164 (sin el prefijo whatsapp:).
card CardOverride No Anulación opcional por paso del título, la descripción y los enlaces de acción de la notificación. Cuando se omite, se usan los campos del objeto a nivel de flujo de trabajo.
Escalation
Campo Tipo Obligatorio Descripción
type string Tipo de notificación para el escalado. Actualmente compatible: email, ms-teams, slack, whatsapp, telegram, dingtalk, discord, twilio-sms, twilio-whatsapp
after duration Cuánto tiempo esperar antes de disparar el escalado. Mínimo: 5m.
data EmailData | TelegramData | … Carga de notificación enviada a los destinatarios del escalado.
escalation Escalation No Escalado anidado opcional que se dispara si tampoco se responde a este nivel de escalado. Profundidad máxima: 5.
Decision — devuelto dentro de decisions[] en GET /workflow/{id}
Campo Tipo Descripción
user string Dirección de correo del aprobador que envió la decisión.
is_approved boolean true si se aprobó, false si se rechazó.
ip string Dirección IP desde la que se envió la decisión.
decisionAt RFC3339 Marca de tiempo RFC 3339 de cuándo se registró la decisión.
SMTP personalizado (integración de cuenta)

Los planes Business y Professional pueden enviar correos de aprobación a través de tu propio servidor SMTP en lugar del mensajero de la plataforma. Configúralo en Ajustes → Integraciones → SMTP personalizado (no en el JSON del flujo de trabajo).

  • Host, puerto, dirección De y, opcionalmente, usuario/contraseña. Usa Enviar correo de prueba antes de guardar flujos de trabajo de producción.
  • Puerto 587 con STARTTLS (interruptor TLS desactivado) o puerto 465 con TLS implícito (interruptor TLS activado). Se bloquean los destinos de IP privadas y reservadas.
  • Usa una dirección De que tu servidor tenga permiso para retransmitir (normalmente un buzón en un dominio que autenticas con SPF/DKIM).
  • Las credenciales se cifran en reposo (AES-256-GCM). Las conexiones salientes requieren TLS 1.2+. Los correos de prueba se envían solo al correo de tu cuenta.
  • La entrega, los rebotes y la alineación SPF/DKIM/DMARC los aplica tu servidor SMTP: Apruvly no verifica tu dominio de envío.
Reglas del identificador de paso

Las claves de paso (usadas en los campos start, approved y rejected, y como claves del mapa workflow) deben coincidir con el siguiente patrón: una letra minúscula seguida de letras minúsculas, dígitos, guiones o guiones bajos:

^[a-z][a-z0-9_-]+$
Formato de duración

Las duraciones se expresan como un número seguido de un sufijo de unidad:

30s — 30 segundos 15m — 15 minutos 2h — 2 horas 7d — 7 días 2w — 2 semanas

La caducidad del flujo de trabajo debe estar entre 5 minutos (mínimo) y 7 días (máximo).

Errores

La API usa códigos de estado HTTP estándar. Las respuestas de error incluyen un cuerpo JSON con los campos error y code.

Código de estado Significado
200 La solicitud se realizó correctamente.
202 Aceptada: el flujo de trabajo se creó y ya está en ejecución.
400 Solicitud incorrecta: el cuerpo o los parámetros de la solicitud no son válidos.
401 No autorizado: clave de API ausente o no válida.
402 Pago requerido: sin suscripción activa, créditos insuficientes o el plan actual no incluye la función solicitada.
403 Prohibido: la clave de API no tiene permiso para este recurso (p. ej. no eres el propietario del flujo de trabajo).
404 No encontrado: el flujo de trabajo o el recurso no existe.
406 No aceptable: la operación no se puede realizar en el estado actual del flujo de trabajo (p. ej. cancelar un flujo ya completado).
429 Demasiadas solicitudes: límite de tasa superado.
500 Error interno del servidor: algo salió mal de nuestro lado.
Cuerpo de la respuesta de error
{
  "success": false,
  "message": "Invalid workflow ID.",
  "data": {
    "field": "id",
    "value": "not-a-valid-uuid"
  }
}

Casos de uso comunes con descripciones amigables para ayudarte a empezar rápido.

01
Aprobación simple de un solo paso

El caso de uso más básico: una sola persona debe aprobar algo antes de que continúes. Ideal para aprobaciones de gastos, vistos buenos de contenido o cualquier escenario con un único responsable.

single approver expense beginner
02
Cadena de aprobación de varios niveles

Enruta una aprobación a través de varias personas en secuencia: Legal → Gerente → CEO. Cada paso debe aprobarse antes de que empiece el siguiente. Perfecto para firmas de contratos o aprobaciones de políticas.

multi-step contract sequential
03
Aprobación con escalado automático

Si el aprobador asignado no responde dentro de una ventana de tiempo establecida, notifica automáticamente a un contacto de respaldo. Mantiene los procesos en marcha sin seguimientos manuales.

escalation auto-escalate deadline
04
Voto en grupo (aprobación por quórum)

Requiere un número mínimo de aprobaciones de un grupo: cualquier N de M miembros pueden aprobar. Útil para decisiones de junta, aprobaciones de comité o revisiones entre pares.

quorum committee group vote
05
Notificación por webhook al completar

Haz POST automáticamente a tu backend cuando un flujo de trabajo llega a una decisión final. Activa la automatización posterior sin consultar la API.

webhook automation integration
06
Validar la carga antes de enviar

Comprueba que la configuración de tu flujo de trabajo es válida antes de crearlo. No necesita autenticación, no consume créditos: solo una rápida comprobación de sintaxis y lógica.

validate no auth dry run
07
Cadena de incorporación de empleados de RR. HH.

Enruta la aprobación de una nueva contratación a través de RR. HH., el responsable de contratación y el aprovisionamiento de TI en secuencia. Cada equipo recibe la solicitud solo después de completarse el paso anterior.

hr onboarding sequential
08
Solicitud de vacaciones con escalado

Una solicitud de vacaciones de un solo paso enviada al gerente directo. Si no hay respuesta en 24 horas, se notifica automáticamente a RR. HH. El webhook se dispara cuando se toma la decisión.

hr time-off simple
09
Aprobación de despliegue en producción

Protege una versión de producción tras tres aprobaciones secuenciales: revisión de código del líder técnico, visto bueno de QA y autorización de operaciones. Un webhook activa la canalización CI/CD al aprobar.

devops deployment webhook
10
Solicitud de presupuesto con doble escalado

Cadena de aprobación de dos niveles (gerente y luego director financiero), cada uno con su propia ruta de escalado. Si el gerente no responde, interviene el VP; si el director financiero se retrasa, se notifica al CEO. Los webhooks se encargan de la automatización financiera posterior.

budget escalation webhook multi-step
11
Aprobación por canal compartido de Slack

Publica un único mensaje de aprobación en un canal compartido de Slack. Configura delivery: "channel", el ID del canal en «to» y una allowList de usuarios autorizados a hacer clic en Aprobar/Rechazar.

slack channel delivery allow-list

Servidor MCP

Endpoint JSON-RPC 2.0 para agentes de IA y canalizaciones de automatización

El endpoint MCP sigue la especificación del Model Context Protocol usando JSON-RPC 2.0 sobre HTTP. Permite que los agentes de IA y las herramientas de automatización pausen la ejecución y soliciten aprobación humana antes de realizar acciones críticas.

Endpoint
POST https://mcp.apruvly.io/mcp
Autenticación Obligatorio
Authorization: Bearer wf_YOUR_API_KEY
Content-Type: application/json
Descubrimiento Opcional

Los clientes compatibles con MCP pueden obtener un documento de descubrimiento público en GET /.well-known/mcp para detectar automáticamente la URL del endpoint, los transportes y versiones de protocolo compatibles, el esquema de autenticación y el catálogo de herramientas disponibles. No requiere autenticación.

GET https://mcp.apruvly.io/.well-known/mcp
{
  "endpoint": "https://mcp.apruvly.io/mcp",
  "transports": ["streamable-http"],
  "protocolVersions": ["2025-03-26"],
  "auth": { "scheme": "bearer" },
  "tools": ["create_approval_request", "get_approval_status", "cancel_approval_request"]
}
Cómo funciona

Tu agente de IA llama a create_approval_request con un título, una descripción y los correos de los aprobadores.

Apruvly envía un correo de aprobación a cada aprobador con enlaces de aprobar/rechazar.

El agente consulta get_approval_status hasta que el estado cambie a approved, rejected o expired.

Integraciones

Ejemplos de configuración para herramientas de IA populares

Añade la siguiente entrada de servidor MCP al archivo .mcp.json de tu proyecto o a los ajustes globales:

{
  "mcpServers": {
    "apruvly": {
      "type": "streamable-http",
      "url": "https://mcp.apruvly.io/mcp",
      "headers": {
        "Authorization": "Bearer wf_YOUR_API_KEY"
      }
    }
  }
}

Añade lo siguiente a la sección mcpServers de tu archivo de configuración de Claude Desktop:

{
  "mcpServers": {
    "apruvly": {
      "url": "https://mcp.apruvly.io/mcp",
      "headers": {
        "Authorization": "Bearer wf_YOUR_API_KEY"
      }
    }
  }
}

Añade el servidor MCP en los ajustes de Cursor, en Features > MCP Servers, o añádelo a .cursor/mcp.json en tu proyecto:

{
  "mcpServers": {
    "apruvly": {
      "url": "https://mcp.apruvly.io/mcp",
      "headers": {
        "Authorization": "Bearer wf_YOUR_API_KEY"
      }
    }
  }
}

Añade la siguiente entrada de servidor MCP al archivo .mcp.json de tu proyecto o a los ajustes globales:

// .vscode/mcp.json
{
  "servers": {
    "apruvly": {
      "type": "http",
      "url": "https://mcp.apruvly.io/mcp",
      "headers": {
        "Authorization": "Bearer wf_YOUR_API_KEY"
      }
    }
  }
}

Cualquier cliente compatible con MCP puede conectarse al endpoint de Apruvly usando el transporte Streamable HTTP. Envía solicitudes JSON-RPC 2.0 directamente:

curl -X POST https://mcp.apruvly.io/mcp \
  -H "Authorization: Bearer wf_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2025-03-26",
      "clientInfo": {"name": "my-agent", "version": "1.0"},
      "capabilities": {}
    }
  }'

Herramientas

Herramientas disponibles que los agentes de IA pueden invocar mediante tools/call

create_approval_request

Crea una solicitud de aprobación humana y devuelve un workflow_id que se puede usar para consultar la decisión. La notificación se envía por el canal elegido en `channel` (por defecto email); los canales que no son de correo deben estar ya configurados para la cuenta.

Parámetros
Campo Tipo Descripción
title string Obligatorio Título corto (máx. 200 caracteres) que describe lo que requiere aprobación.
description string Opcional Descripción detallada de la acción que requiere aprobación humana (máx. 4000 caracteres).
channel string Opcional Canal de entrega. Por defecto «email». Permitidos: email, slack, ms-teams, whatsapp, telegram, dingtalk, discord, twilio-sms, twilio-whatsapp. Los canales que no son de correo requieren que la integración correspondiente esté configurada en /integrations.
recipients array Opcional Lista uniforme de destinatarios, una entrada por aprobador. Úsala para dirigirte a cualquier canal. El formato de la dirección depende del canal (email/slack/ms-teams = dirección de correo, whatsapp/twilio-sms/twilio-whatsapp = teléfono E.164, telegram = ID de chat numérico, discord = snowflake de usuario de 17 a 20 dígitos). Mutuamente excluyente con approvers y steps.
approvers array Opcional Aprobadores (correos separados por comas) — {"email":"…","name":"…"}. Email-only shortcut; for other channels use recipients.
steps array Opcional Cadena de aprobación secuencial opcional. Cada paso debe aprobarse antes de que se ejecute el siguiente; cualquier rechazo termina el flujo de trabajo. Requiere el plan Growth, Business o Professional. Mutuamente excluyente con recipients/approvers de nivel superior.
expires string Opcional Cadena de duración: «1h», «24h», «7d». Por defecto «24h». Mínimo: 5 minutos; los valores más cortos se rechazan antes de debitar ningún crédito.
links array Opcional Lista de URLs relacionadas (documentos, archivos, enlaces).
tags array Opcional Lista de etiquetas para filtrar y categorizar.
idempotency_key string Opcional Identificador opcional suministrado por el cliente (máx. 128 caracteres) que hace la llamada idempotente. Repetir la misma clave en 24h devuelve el workflow_id original sin recrear un flujo de trabajo ni cobrar créditos. Equivalente al encabezado HTTP Idempotency-Key.
callback_url string Opcional URL https opcional que recibe un POST firmado cuando el flujo de trabajo alcanza un estado terminal. Útil para agentes por lotes que no pueden mantener abierta una conexión de sondeo o SSE.
external_id string Opcional Id de correlación opcional suministrado por el llamante (máx. 128 caracteres): p. ej. run_id del agente, tool_call_id del sistema previo, id de ticket interno. Requiere el plan Growth o superior. Se persiste en la fila del flujo de trabajo y se devuelve desde get_approval_status.
Cuerpo de la solicitud
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "create_approval_request",
    "arguments": {
      "title": "Deploy to production",
      "description": "Requesting approval to deploy v2.5.0 to production.",
      "channel": "slack",
      "recipients": [
        { "address": "[email protected]" }
      ],
      "expires": "24h",
      "idempotency_key": "agent-run-2026-05-03-00042",
      "external_id": "deploy-pipeline-7831"
    }
  }
}
Respuesta 200
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [
      { "type": "text", "text": "Approval request created…" },
      { "type": "text", "text": "{\"workflow_id\":\"550e8400-…\",\"status\":\"pending\",\"expires_at\":\"2026-05-04T12:00:00Z\",\"external_id\":\"deploy-pipeline-7831\"}" }
    ],
    "structuredContent": {
      "workflow_id": "550e8400-e29b-41d4-a716-446655440000",
      "status": "pending",
      "expires_at": "2026-05-04T12:00:00Z",
      "external_id": "deploy-pipeline-7831"
    }
  }
}

Las respuestas de las herramientas también llevan un campo structuredContent que refleja la instantánea JSON del segundo elemento de contenido, declarado por el outputSchema de la herramienta para que los clientes compatibles con MCP puedan analizarlo de forma tipada sin escanear la carga de texto.

Ejemplo — multi-step + escalation

A two-step chain: the manager has 24h to approve before the request escalates to the director, and only after the manager approves does the VP get the second-level request.

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "create_approval_request",
    "arguments": {
      "title": "Vendor Contract – Novatek",
      "channel": "email",
      "steps": [
        {
          "name": "manager",
          "recipients": [{ "address": "[email protected]" }],
          "escalate_after": "24h",
          "escalate_to": [{ "address": "[email protected]" }]
        },
        {
          "name": "vp",
          "recipients": [{ "address": "[email protected]" }]
        }
      ],
      "expires": "7d"
    }
  }
}
get_approval_status

Devuelve el estado actual y las decisiones por paso de una solicitud de aprobación. Consúltalo después de create_approval_request hasta que el estado cambie a approved, rejected o expired.

Parámetros
Campo Tipo Descripción
workflow_id string Obligatorio El ID del flujo de trabajo devuelto cuando se creó el flujo.
wait string Opcional Duración de long-poll opcional (p. ej. «30s», «60s», «1m»). Cuando se establece, la llamada se bloquea hasta que el flujo de trabajo deja el estado pendiente o transcurre la duración, lo que ocurra primero. Limitado a 60s. Reduce el número de idas y vueltas de sondeo.
Cuerpo de la solicitud
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "get_approval_status",
    "arguments": {
      "workflow_id": "550e8400-e29b-41d4-a716-446655440000",
      "wait": "60s"
    }
  }
}
Respuesta 200
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      { "type": "text", "text": "Approval status retrieved." },
      { "type": "text", "text": "{\"workflow_id\":\"550e8400-…\",\"status\":\"approved\",\"current_step\":\"approval\",\"external_id\":\"deploy-pipeline-7831\",\"decisions\":[…]}" }
    ],
    "structuredContent": {
      "workflow_id": "550e8400-e29b-41d4-a716-446655440000",
      "status": "approved",
      "current_step": "approval",
      "created_at": "2026-05-03T11:00:00Z",
      "expires_at": "2026-05-04T12:00:00Z",
      "external_id": "deploy-pipeline-7831",
      "decisions": [{ "user": "[email protected]", "is_approved": true, "decided_at": "2026-05-03T11:42:18Z", "step": "manager" }]
    }
  }
}

Cada entrada de decisión puede incluir un campo step opcional que nombra el paso del flujo de trabajo en el momento de la decisión. Los flujos heredados de un solo paso pueden omitirlo.

cancel_approval_request

Cancela una solicitud de aprobación pendiente. Detiene los recordatorios, notifica a los aprobadores por cada canal configurado que la solicitud se canceló y marca el flujo de trabajo como cancelado de forma terminal. Idempotente: una segunda llamada sobre un flujo ya cancelado devuelve éxito con already_canceled=true.

Parámetros
Campo Tipo Descripción
workflow_id string Obligatorio El ID del flujo de trabajo devuelto cuando se creó el flujo.
reason string Opcional Motivo opcional de texto libre para la cancelación (máx. 500 caracteres). Se registra en el registro de actividad del flujo de trabajo para que el cliente pueda auditar por qué el agente retiró la solicitud.
Cuerpo de la solicitud
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "cancel_approval_request",
    "arguments": {
      "workflow_id": "550e8400-e29b-41d4-a716-446655440000",
      "reason": "agent retry resolved the action without human approval"
    }
  }
}
Respuesta 200
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      { "type": "text", "text": "Approval request canceled." },
      { "type": "text", "text": "{\"workflow_id\":\"550e8400-…\",\"status\":\"canceled\",\"already_canceled\":false,\"canceled_at\":\"2026-05-03T12:34:56Z\"}" }
    ],
    "structuredContent": {
      "workflow_id": "550e8400-e29b-41d4-a716-446655440000",
      "status": "canceled",
      "already_canceled": false,
      "canceled_at": "2026-05-03T12:34:56Z"
    }
  }
}

Referencia del protocolo

Métodos, handshake y códigos de error de JSON-RPC 2.0

Métodos
Método Descripción
initialize Inicializa una sesión MCP. Negocia la versión del protocolo (devuelve la versión del cliente cuando es compatible, la baja a la versión compatible más alta por debajo de ella o devuelve -32602 con la lista de versiones compatibles cuando no existe ninguna compatible) y devuelve la información del servidor más las capacidades.
ping Comprobación de salud. Devuelve un objeto de resultado vacío.
tools/list Devuelve la lista de herramientas disponibles, sus definiciones de entrada en JSON Schema y un outputSchema que describe el structuredContent que devuelve cada herramienta.
tools/call Invoca una herramienta por nombre con los argumentos proporcionados.
notifications/* Los métodos que empiezan por notifications/ se aceptan con HTTP 202 y sin cuerpo de respuesta, según exige la especificación. notifications/cancelled se respeta para abortar un tools/call en curso (ver «Notificaciones» abajo); el resto se descartan de forma silenciosa.
Ejemplo — initialize
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2025-03-26",
    "clientInfo": { "name": "my-agent", "version": "1.0" },
    "capabilities": {}
  }
}
Respuesta 200
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-03-26",
    "serverInfo": { "name": "apruvly", "version": "1.0.0" },
    "capabilities": { "tools": {} },
    "instructions": "Apruvly is a human-in-the-loop approval service…"
  }
}
Solicitudes por lotes

El endpoint acepta un array JSON de solicitudes en el cuerpo (máx. 50 elementos) y devuelve un array de respuestas. Los elementos se procesan secuencialmente; la espera de get_approval_status se limita a 5s dentro de un lote. Las entradas notifications/cancelled del mismo array se aplican antes de que se ejecute cualquier tools/call. Las notificaciones no producen ranura de respuesta; un array que solo contiene notificaciones devuelve 202 Accepted con un cuerpo vacío. Un array vacío se rechaza con -32600 Invalid Request.

Cuerpo de la solicitud
[
  { "jsonrpc": "2.0", "id": 1, "method": "ping" },
  { "jsonrpc": "2.0", "id": 2, "method": "tools/call",
    "params": { "name": "get_approval_status",
      "arguments": { "workflow_id": "550e8400-e29b-41d4-a716-446655440000" } } }
]
Respuesta 200
[
  { "jsonrpc": "2.0", "id": 1, "result": {} },
  { "jsonrpc": "2.0", "id": 2, "result": { "content": [ … ], "structuredContent": { … } } }
]
Notificaciones respetadas

notifications/cancelled aborta un tools/call en curso para que el agente pueda acortar un long-poll sin esperar a que se dispare su temporizador. Haz coincidir el campo requestId con el id de la solicitud que quieras cancelar; la llamada en ejecución devuelve su instantánea actual de inmediato. Dentro de un lote, incluye la notificación en el mismo array: se respeta antes de que se ejecuten los elementos tools/call. Para abortar un long-poll que ya está en curso en una conexión aparte, envía notifications/cancelled como un POST hermano. Cancelar un id de solicitud que no está actualmente en curso es una operación nula silenciosa.

Ejemplo — notifications/cancelled
{
  "jsonrpc": "2.0",
  "method": "notifications/cancelled",
  "params": {
    "requestId": 2,
    "reason": "agent changed its mind"
  }
}

Respuesta 202 Accepted — empty body, per the JSON-RPC notification convention. The matching tools/call wakes from its long-poll and returns its current snapshot to the original caller.

Códigos de error de JSON-RPC

Los errores a nivel de aplicación usan el código -32000 con un slug estable en data.code para que los agentes puedan bifurcar de forma programática sin analizar el texto del mensaje.

Código Significado
-32700 Parse error — invalid JSON body.
-32600 Invalid Request — missing jsonrpc or method.
-32601 Method not found.
-32602 Invalid params — missing or malformed arguments. Also returned by initialize when the client requests a protocol version older than anything the server supports (the response carries data.supported with the list of acceptable versions).
-32603 Internal error.
-32000 Application error — branch on the stable slug under data.code (see table below).
data.code slugs (application errors)
data.code Significado extra data fields
subscription_required The caller has no active subscription.
plan_feature_required The current plan does not include the requested feature (MCP access, multi-step approval, …). feature
integration_not_configured The chosen channel needs an integration that the tenant has not configured at /integrations. channel, integration
trial_expired Trial period has expired; upgrade to continue.
approver_limit_exceeded The workflow lists more approvers than the plan allows. max
escalation_limit_exceeded The escalation chain is deeper than the plan allows. max
concurrent_workflow_limit The plan's cap on simultaneously-pending workflows was reached. max
rate_limited Too many requests in the current window. Retry after retry_after_seconds. window, retry_after_seconds
insufficient_credits Account balance cannot cover the cost of the workflow.
workflow_not_found The workflow_id does not exist for the calling account. Cross-tenant lookups intentionally return the same slug to avoid leaking existence.
workflow_not_cancelable cancel_approval_request was called on a workflow already in a non-pending terminal state (approved, rejected, expired, error). status
Cuerpo de la respuesta de error
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "Rate limit exceeded, try again in a moment",
    "data": {
      "code": "rate_limited",
      "window": "minute",
      "retry_after_seconds": 60
    }
  }
}