Docs
Pregunta a quien haga falta desde tu agente.
Tu agente describe lo que necesita (un formulario, una encuesta o un sí o un no) y recibe un enlace para una persona, para cada persona de un grupo o para cualquiera con quien lo compartas. Las personas lo abren en el móvil, sin registrarse, y sus respuestas te llegan como JSON validado.
-
Crea una solicitud. Llama a
createRequestcon un JSON Schema para un formulario, o con un motivo para una aprobación. -
Envía el enlace. Pasa
sendEmail: truey lo enviamos por correo a cada persona con nombre, mándalo por un canal que ya tengas (correo, chat o SMS) o publica un enlace abierto donde quieras. -
Recibe la respuesta. En Builder y Pro, tu cliente MCP recibe cada respuesta por push en el instante en que llega. También llega a tu webhook, por correo con
notifyEmail, o puedes leerla congetStatus.
Las mismas herramientas están disponibles de dos maneras: un servidor MCP para los agentes que hablan MCP y una API REST para todo lo demás. Los agentes pueden leer esta guía en llms.txt.
Inicio rápido
De una clave de API a la respuesta de una persona en cuatro pasos.
1Obtén una clave de API
Inicia sesión con tu correo y copia la clave del panel. Empieza por sk_live_; guárdala en tu servidor. ¿Usas Claude Code, Codex u otro cliente MCP? Sáltate este paso: añade el servidor por URL e inicia sesión desde el cliente.
2Crea una solicitud
Esta le pide a Jordan una dirección de envío y una fecha de entrega. El esquema es JSON Schema normal; consulta Esquema del formulario para ver qué se admite.
3Envía el enlace
La respuesta trae un enlace por persona en links[] (o una sola url para un enlace abierto). Con "sendEmail": true enviamos por correo su propio enlace a cada persona con nombre que tenga un correo, a nombre de tu cuenta. El campo email de cada enlace dice qué pasó: "sent", "failed" (la solicitud existe igualmente; llama a remind más tarde), "limit" (se alcanzaron los límites de correo del plan), "no address" u "off". Envía el resto como prefieras: correo, chat o SMS.
4Recibe la respuesta
Cuando Jordan envía el formulario, tu webhookUrl recibe un evento response.created con los datos, ya validados contra tu esquema. ¿Sin webhook? Llama a getStatus con el requestId, define notifyEmail y te escribimos cuando termine, o en Builder y Pro suscríbete por MCP y tu agente se entera en cuanto Jordan responde. Consulta Recibir la respuesta.
Autenticación
Cada llamada MCP y REST envía una clave de API como token bearer. La misma clave sirve para ambas. Una clave ausente o revocada recibe un 401. Hay dos maneras de conseguir una.
Inicia sesión desde tu cliente MCP
Añade https://runitby.app/mcp sin clave y el cliente te hace iniciar sesión por OAuth: se abre un navegador, escribes tu correo y el enlace de acceso te lleva a una página que te pide permitir la app. ¿Es la primera vez? El mismo enlace crea tu cuenta. La app guarda entonces su propia clave, con su nombre, que puedes revocar en Claves.
-
Claude Code: ejecuta el comando de la derecha, luego
/mcpen Claude Code y elige autenticar. -
Codex: ejecuta
codex mcp addy luegocodex mcp login. - Claude (web y escritorio): Configuración, Conectores, Añadir conector personalizado, y pega la URL.
- Otros clientes que admiten autorización MCP: añade la URL sin cabeceras.
Crea una clave en el panel
Para la API REST, los scripts y los clientes que solo aceptan una cabecera: crea y revoca claves en el panel y envía la clave en la cabecera Authorization.
Los planes cuentan las dos por separado. Free incluye una clave y una app conectada, Builder cinco de cada, Pro todas las que necesites.
Ejemplos de un solo archivo con una clave: Vercel AI SDK, Mastra, LangChain.js y el Claude Agent SDK.
Herramientas y endpoints
Cada herramienta MCP tiene un endpoint REST con la misma entrada y la misma salida. La referencia de la API enumera cada campo.
| Herramienta MCP | REST | Qué hace |
|---|---|---|
createRequest |
POST /requests | Crea un formulario o una aprobación y devuelve el enlace o enlaces, enviados por correo por ti si lo pides. |
previewRequest |
POST /requests/preview | Capturas y análisis de lo que verá la persona. No crea nada. |
getStatus |
GET /requests/{id} | Estado, veredicto y todas las respuestas hasta ahora. |
listRequests |
GET /requests | Tus solicitudes, las más recientes primero. Filtra por modo o estado; pagina con cursor. |
updateRequest |
PATCH /requests/{id} | Cambia el contenido, añade destinatarios o define una nueva caducidad. |
remind |
POST /requests/{id}/remind | Envía el enlace por correo a quienes no han respondido. |
closeRequest |
DELETE /requests/{id} | Deja de aceptar respuestas. |
Formularios y aprobaciones
Cada solicitud tiene un mode:
"form"- Recoger datos. Envías un
schema; la persona recibe un formulario creado a partir de él y tú recibes un objeto que lo cumple. "approval"- Obtener una decisión. Envías
approval.reason; cada persona recibe una tarjeta con Aprobar y Rechazar (o tus propias etiquetas) y un comentario opcional. Recibes cada decisión y unverdictglobal.
Ambos aceptan un title (hasta 120 caracteres), una línea requester opcional que indica quién pregunta, un locale para la página y sus correos ("en", "es", "pt", "fr", "de", "it", "ja" o "zh", o con una región como "es-AR" para las fechas) y metadata, que vuelve intacta en cada webhook y estado. Escribe el título y las preguntas en el mismo idioma.
Quién responde
audience decide quién recibe un enlace.
| kind | Recibes | Úsalo para |
|---|---|---|
"named" |
links[], uno por persona en recipients (de 1 a 50, cada uno { name, email?, phone? }) |
Respuestas que necesitas atribuir a alguien. Las aprobaciones deben ser con nombre. Un correo habilita sendEmail, los recordatorios y los códigos por correo. |
"open" |
Una url que cualquiera puede abrir |
Inscripciones y encuestas. maxSubmissions limita las respuestas (1 por defecto). |
Para qué usarlo
Un modo y una audiencia cubren casi todo lo que harías con un creador de formularios, una encuesta, una app de agenda o un hilo de correos.
| Quieres | Solicitud |
|---|---|
| Los datos de una persona: una dirección de envío, el alta de un cliente, un horario de reserva | "form", con nombre, un destinatario |
| Una encuesta, un sondeo, opiniones o inscripciones de cualquier persona |
"form", abierto con maxSubmissions. Publica la única url donde quieras; getStatus devuelve todas las respuestas para que tu agente las resuma. |
| Confirmaciones de asistencia, disponibilidad, cobertura de turnos o registros de un grupo conocido |
"form", con nombre (hasta 50), de modo que cada respuesta queda atribuida y remind persigue al resto |
| Aprobaciones, vistos buenos y votaciones |
"approval" con una policy; añade verify: "email" para dinero, accesos o eliminaciones |
Estado y caducidad
| status | Significa |
|---|---|
pending |
Nadie ha respondido todavía. |
partial |
Algunas personas con nombre han respondido y otras no. |
complete |
Todos respondieron, se alcanzó maxSubmissions o una aprobación ya tiene su veredicto. |
expired |
El enlace se quedó sin tiempo. |
closed |
Llamaste a closeRequest. |
Caducidad. expiresIn acepta "30m", "48h", "7d" o segundos. Por defecto son 7 días y el máximo 90.
Cambiar una solicitud. updateRequest cambia el título, el esquema, las secciones, el motivo o el tema hasta que llega la primera respuesta. Añadir destinatarios, definir una nueva caducidad (contada desde ahora) y cambiar notifyEmail funcionan hasta que la solicitud está completa, caducada o cerrada. A los destinatarios añadidos no se les envía correo; envía sus enlaces o llama a remind con sus recipientIds.
Recordatorios. remind envía por correo el enlace a las personas con nombre que no han respondido y tienen un correo, como máximo una vez cada 24 horas por persona. El correo de sendEmail cuenta como el primero.
Recibir la respuesta. Usa una o combina varias:
webhookUrl- Tu servidor recibe cada respuesta según ocurre. Consulta Webhooks.
notifyEmail- Enviamos a tu cuenta un resumen y un enlace a la solicitud en el panel:
"each"con cada respuesta (hasta alcanzar los límites de correo del plan, y después solo cuando termina) o"complete"una sola vez cuando se completa o caduca. Los correos de aprobación incluyen la decisión y el comentario; las respuestas de formularios se quedan en el panel. Desactivado por defecto;updateRequestpuede cambiarlo. getStatusconwait- Mantiene la llamada abierta hasta 25 segundos (REST:
?wait=25) y responde en cuanto alguien contesta o cambia el estado. Vuelve a llamar para seguir esperando. - MCP push (Builder y Pro)
- Cada solicitud es el recurso MCP
runitby://requests/{requestId}, enlazado desdecreateRequest; leerlo devuelve lo mismo quegetStatus. En Builder y Pro, los clientes del protocolo 2026-07-28 pueden suscribirse consubscriptions/listeny recibirnotifications/resources/updatedcon cada respuesta o cambio de estado, con una suscripción abierta a la vez en Builder y hasta tres en Pro. En Free,subscriptions/listenresponde con un error que indica las otras maneras de recibir la respuesta.
Esquema del formulario
JSON Schema normal con type: "object" arriba y hasta 40 campos. required[] se aplica, y title y description pasan a ser la etiqueta y el texto de ayuda.
| Tipo | Palabras clave |
|---|---|
string |
format (email, date, time, date-time, tel, uri, duration), minLength, maxLength, pattern
|
number, integer |
minimum, maximum |
boolean |
const: true crea una casilla de consentimiento que debe marcarse |
enum |
Una lista fija de opciones |
array |
De primitivos o de un enum; minItems, maxItems |
Indicaciones. Pon las opciones de cada campo en "x-runitby": widget, placeholder, help, columns (1 o 2), step y currency.
Secciones. Agrupa campos con sections: [{ title, fields: [...] }] junto al esquema.
Los objetos anidados (salvo el campo de ubicación), oneOf, anyOf, allOf y $ref se rechazan con un mensaje que dice qué cambiar. Los campos que piden contraseñas, PIN, números de tarjeta, CVV, códigos de seguridad, números de seguro social o códigos de un solo uso se rechazan.
Tipos de campo
Campos ya hechos para cosas que a la gente le incomoda escribir. Cada uno es JSON Schema normal más un widget, así que la respuesta se valida como cualquier otro campo.
| Campo | Esquema | Respuesta |
|---|---|---|
| Fecha | string, format date | "2026-11-12" |
| Hora | string, format time; step = minutos (1–60) | "14:30" |
| Fecha y hora | string, format date-time | "2026-11-12T14:30:00-08:00" |
| Duración | string, format duration | "PT1H30M" |
| Franjas horarias | array de enum date-time, widget slots | las horas elegidas |
| Intervalo de fechas | array de 2 fechas, widget daterange | ["2026-11-12", "2026-11-15"] |
| Ubicación | object, widget location | { latitude, longitude, accuracy } |
| Importe | number, currency "USD" | 1200 |
| Control deslizante, valoración | number o integer; el control deslizante necesita minimum y maximum | 7 |
| Chips, radio, select | enum (chips también acepta un array de enum) | "M" |
| Clasificación | array de enum, widget rank | todas las opciones, en el orden de la persona |
| Sí o no | boolean, widget yesno | true |
| Color | string, widget color | "#C2410C" |
| País | string, widget country | "US" (ISO 3166-1) |
| Idioma | string, widget language | "es-AR" (BCP 47) |
| Zona horaria | string, widget timezone | "America/New_York" |
Añade un enum a un campo de país o de idioma para limitar las opciones.
Vista previa
previewRequest acepta los mismos campos de formulario o aprobación que createRequest (sin audiencia, caducidad, webhook ni metadata) y devuelve capturas de 390 px y 1280 px de ancho, además de lint[] con todo lo que se leerá mal. No se crea nada.
Pasa sampleData para ver el formulario relleno y viewports para obtener un solo tamaño. Haz la vista previa antes cuando el mismo formulario se vaya a enviar muchas veces.
Temas
theme hace que la página se parezca a tu producto. Sin él, las páginas son tinta sobre blanco cálido, con Figtree y títulos en Fraunces, y esquinas redondeadas.
| Clave | Valores |
|---|---|
accent, background, surface,
text
|
Colores hexadecimales |
font, headingFont |
system, Figtree, Geist, Inter, DM Sans, Manrope, Work Sans, Space Grotesk, IBM Plex Sans, Fraunces, Lora, Source Serif 4 |
radius |
sharp, soft, round |
density |
compact, comfortable |
layout |
stacked (todos los campos en una página) o single (una pregunta a la vez) |
logoUrl |
Tu logo |
heroText, thankYou |
El saludo sobre el formulario y el mensaje tras el envío |
Opciones de aprobación
Las aprobaciones necesitan una audiencia con nombre: cada persona recibe su propio enlace, así que cada decisión queda atribuida a ella. El veredicto es "approved", "declined" o "expired" cuando nadie decidió a tiempo; nunca un sí silencioso.
| campo de aprobación | Por defecto | Notas |
|---|---|---|
reasonobligatorio |
Lo que estás pidiendo, hasta 300 caracteres. | |
detail |
Contexto bajo el motivo, hasta 1000 caracteres. | |
policy |
"all" |
"any", "all", "majority" o { n }: cuántas aprobaciones hacen falta. |
options |
Aprobar, Rechazar | De dos a cuatro etiquetas; la primera cuenta como aprobación. Las decisiones vuelven en snake_case: "Aprobar con cambios" → "aprobar_con_cambios". |
allowComment |
true | Permite que las personas añadan un comentario a su decisión. |
showOthers |
false |
"names" o "counts" muestra a cada persona cómo van los demás. |
verify |
false |
"email": cada persona confirma un código de 6 dígitos enviado a su propia dirección antes de que funcionen los botones, así que un enlace reenviado no puede decidir por ella. Cada destinatario necesita un correo. Úsalo para dinero, accesos o eliminaciones. |
Webhooks
Define webhookUrl (https) en una solicitud y le enviamos un POST con JSON para dos eventos:
response.created- Cada envío o decisión, con la respuesta en
response. request.completed- Todas las personas con nombre respondieron, se alcanzó
maxSubmissions, una aprobación tiene su veredicto o la solicitud caducó.
Verifica la firma. X-Runitby-Signature es el HMAC-SHA256 en hexadecimal del cuerpo sin procesar con el secreto de firma de tu cuenta, que está en el panel. X-Runitby-Timestamp es la hora de envío en segundos Unix.
Reintentos. Cualquier 2xx dentro de 10 segundos cuenta como entregado. Si no, reintentamos 4 veces: 1 min, 5 min, 30 min y 2 h después de cada fallo. Después, la respuesta sigue disponible en getStatus.
Errores
Los errores son JSON con un message legible y, para entradas inválidas, problems[] que señala cada campo que hay que cambiar. Los agentes suelen poder corregir la solicitud solo con el mensaje.
| Estado | Cuándo |
|---|---|
400 |
La entrada o el esquema no es válido. |
401 |
Clave de API ausente o revocada. |
404 |
No hay ninguna solicitud con ese id en tu cuenta. |
409 |
El cambio ya no está permitido, por ejemplo editar tras la primera respuesta o enviar un recordatorio de una solicitud cerrada. |
429 |
Más de 60 creaciones por minuto, o se agotaron las solicitudes mensuales del plan. |
Planes y límites
| Free | Builder | Pro | |
|---|---|---|---|
| Solicitudes al mes | 250 | 2,000 | 10,000 |
| Respuestas por enlace abierto | 25 | 10,000 | Ilimitadas |
| Claves de API | 1 | 5 | Ilimitadas |
| Apps conectadas (OAuth) | 1 | 5 | Ilimitadas |
| Respuestas conservadas tras la entrega | 30 días | 90 días | Conservadas |
| Correos al mes | 500 | 4,000 | 20,000 |
| Correos por solicitud | 10 | 10 | 10 |
| MCP push (suscripciones abiertas) | — | 1 | 3 |
| Precio al mes | $0 | $9 | $29 |
Al pasar el límite mensual, createRequest devuelve 429 hasta que se reinicie el periodo o cambies de plan (en Pro, el límite de uso razonable; escríbenos si necesitas más); los enlaces ya enviados siguen funcionando. Sin webhook, las respuestas se conservan desde el envío. Consulta precios.
Los correos que enviamos por ti (enlaces, recordatorios y avisos de notifyEmail) cuentan para ambos límites de correo. Al pasar cualquiera de los dos, los enlaces vuelven como "limit" para que los envíes tú y los avisos "each" se detienen. El correo que avisa que una solicitud terminó siempre se envía, y los códigos de aprobación no cuentan.
En todos los planes: 60 creaciones por minuto por clave de API, title de hasta 120 caracteres, approval.reason de 300, approval.detail de 1000 y metadata de menos de 4 KB.
Tú eres el responsable del tratamiento de lo que recoges. Pide solo lo que la tarea necesita.