Referencia completa de la API REST de Apruvly.
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).
https://api.apruvly.io/api/v1
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."
}
}
}
}'
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.
Authorization: Bearer wf_YOUR_API_KEY
Puedes generar una clave de API desde la sección Claves de API del panel.
/api/v1/workflow
Crea un nuevo flujo de aprobación e inicia de inmediato el primer paso.
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
object |
object | Sí | Metadatos sobre el elemento que se aprueba. |
object.title |
string | Sí | 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 | Sí | Cuánto tiempo permanece abierto el flujo de trabajo antes de caducar. Formato: 30s, 15m, 2h, 7d, 2w. |
start |
string | Sí | La clave del primer paso a ejecutar (debe coincidir con una clave en workflow). |
workflow |
map[string]Step | Sí | 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.
|
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."
}
}
}
}'
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"externalId": "CONTRACT-2025-0042"
}
}
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.
{
"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."
}
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."
}
}
}
}'
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"externalId": "CONTRACT-2025-0042"
}
}
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"
{
"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": []
}
}
curl -X DELETE https://api.apruvly.io/api/v1/workflow/external/CONTRACT-2025-0042 \
-H "Authorization: Bearer wf_YOUR_API_KEY"
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000"
}
}
curl "https://api.apruvly.io/api/v1/workflows/search?external_id=CONTRACT-2025-0042" \
-H "Authorization: Bearer wf_YOUR_API_KEY"
{
"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
}
]
}
/api/v1/workflow/validate
Valida la configuración de un flujo de trabajo sin crearlo. Útil para comprobar tu carga antes de enviarla.
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."
}
}
}
}'
{
"success": true
}
/api/v1/workflow/{id}
Recupera el estado completo de un flujo de trabajo, incluido su registro de actividad y su historial de decisiones.
| Campo | Tipo | Descripción |
|---|---|---|
id |
uuid | El ID del flujo de trabajo devuelto cuando se creó el flujo. |
curl https://api.apruvly.io/api/v1/workflow/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer wf_YOUR_API_KEY"
{
"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"
}
]
}
}
/api/v1/workflows/search
Devuelve una lista paginada de los flujos de trabajo que pertenecen al usuario autenticado.
| 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). |
curl "https://api.apruvly.io/api/v1/workflows/search?status=pending&query=contract" \
-H "Authorization: Bearer wf_YOUR_API_KEY"
{
"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
}
]
}
/api/v1/workflows/recent
Devuelve los flujos de trabajo creados más recientemente para el usuario autenticado.
curl "https://api.apruvly.io/api/v1/workflows/recent" \
-H "Authorization: Bearer wf_YOUR_API_KEY"
/api/v1/billing
Devuelve la suscripción, el plan, el saldo de créditos y el resumen de uso del usuario autenticado.
curl "https://api.apruvly.io/api/v1/billing" \
-H "Authorization: Bearer wf_YOUR_API_KEY"
/api/v1/integrations
Gestiona las credenciales de canales de terceros (Slack, MS Teams, Twilio, etc.) a través de la API REST.
| Método | Endpoint | Descripción |
|---|---|---|
| GET | /api/v1/integrations | Lista 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. |
/api/v1/workflow/{id}
Cancela un flujo de trabajo pendiente. Los flujos completados o caducados no se pueden cancelar.
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)
| Campo | Tipo | Descripción |
|---|---|---|
id |
uuid | El ID del flujo de trabajo devuelto cuando se creó el flujo. |
curl -X DELETE https://api.apruvly.io/api/v1/workflow/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer wf_YOUR_API_KEY"
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000"
}
}
/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.
| 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. |
# 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"
{
"success": true
}
/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.
| Método | Endpoint | Descripción |
|---|---|---|
| GET | /api/v1/directory/areas | Lista todas las áreas activas. |
| POST | /api/v1/directory/areas | Crea una nueva área. |
| POST | /api/v1/directory/areas/bulk | Crea hasta 100 áreas en una sola llamada. |
| PUT | /api/v1/directory/areas/bulk | Renombra 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). |
| Método | Endpoint | Descripció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/people | Crea una persona con pertenencias y contactos. |
| POST | /api/v1/directory/people/bulk | Crea hasta 1000 personas en una sola llamada (con sus pertenencias y contactos). |
| PUT | /api/v1/directory/people/bulk | Actualiza 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). |
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" }
]
}'
{
"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" }
]
}
}
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.
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" }
]
}
]
}'
{
"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.
Cada endpoint requiere el ámbito de clave de API correspondiente. Concede los ámbitos en Claves de API en la consola.
| Ámbitos | Descripción |
|---|---|
api:directory:list | API · Directorio · listar |
api:directory:read | API · Directorio · leer |
api:directory:write | API · Directorio · crear / actualizar |
api:directory:bulk | API · Directorio · operaciones masivas |
api:directory:delete | API · Directorio · eliminar |
Cada contacto es un par (proveedor, dirección). Solo se aceptan los proveedores configurados en /integrations (además del correo).
| Proveedor | Dirección |
|---|---|
email, slack, ms-teams | E-mail address |
twilio-sms, twilio-whatsapp, whatsapp | E.164 phone (e.g. +5511999999999) |
telegram | Numeric chat id |
discord | 17–20 digit snowflake |
Los robots de grupo de DingTalk no se almacenan en el directorio: difunden a un grupo, no a un contacto individual.
| Estado | Descripción |
|---|---|
| 400 | Falta un campo obligatorio o la dirección de contacto no es válida (p. ej. correo o teléfono mal formado). |
| 402 | El plan actual no incluye la función de directorio. |
| 409 | La función de directorio está desactivada: actívala primero en /directory en la consola web. |
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.
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" } }
]
}
}
| 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 | Sí | Debe ser «webhook». |
url |
string | Sí | 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[] | Sí | 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[] | Sí | Números de teléfono en formato E.164 (p. ej. +14155552671). Las entradas duplicadas y no válidas se rechazan. |
body |
string | Sí | Texto del mensaje (hasta 1600 caracteres). Admite interpolación de ${variable}. |
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). |
{
"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}"
}
}
}
]
}
}
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.
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.
Descripción detallada de todos los objetos de solicitud y respuesta.
Step| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
type |
string | Sí | 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 | Sí | 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[] | Sí | Lista de direcciones de correo de los aprobadores de este paso. |
subject |
string | Sí | Línea de asunto del correo de aprobación. |
body |
string | Sí | 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. |
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[] | Sí | 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. |
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[] | Sí | 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. |
WhatsAppData — usado cuando type = whatsapp
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
to |
string[] | Sí | 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. |
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[] | Sí | 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. |
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[] | Sí | 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. |
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. |
TwilioSMSData — usado cuando type = twilio-sms
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
to |
string[] | Sí | 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. |
TwilioWhatsAppData — usado cuando type = twilio-whatsapp
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
to |
string[] | Sí | 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 | Sí | Tipo de notificación para el escalado. Actualmente compatible: email, ms-teams, slack, whatsapp, telegram, dingtalk, discord, twilio-sms, twilio-whatsapp |
after |
duration | Sí | Cuánto tiempo esperar antes de disparar el escalado. Mínimo: 5m. |
data |
EmailData | TelegramData | … | Sí | 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. |
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).
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_-]+$
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).
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. |
{
"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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
POST https://mcp.apruvly.io/mcp
Authorization: Bearer wf_YOUR_API_KEY
Content-Type: application/json
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"]
}
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.
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 disponibles que los agentes de IA pueden invocar mediante tools/call
create_approval_requestCrea 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.
| 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. |
{
"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"
}
}
}
{
"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.
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_statusDevuelve 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.
| 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. |
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "get_approval_status",
"arguments": {
"workflow_id": "550e8400-e29b-41d4-a716-446655440000",
"wait": "60s"
}
}
}
{
"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_requestCancela 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.
| 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. |
{
"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"
}
}
}
{
"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"
}
}
}
Métodos, handshake y códigos de error de JSON-RPC 2.0
| 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. |
initialize{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"clientInfo": { "name": "my-agent", "version": "1.0" },
"capabilities": {}
}
}
{
"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…"
}
}
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.
[
{ "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" } } }
]
[
{ "jsonrpc": "2.0", "id": 1, "result": {} },
{ "jsonrpc": "2.0", "id": 2, "result": { "content": [ … ], "structuredContent": { … } } }
]
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.
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.
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 |
{
"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
}
}
}