Solicitudes
Crear una solicitud
Dos llamadas a la API: pregunta al formulario qué se le puede indicar, y luego asígnalo a una persona con los valores que ya conoces.
Empieza en la hoja de compartir

Abre tu formulario publicado, haz clic en Compartir y elige la pestaña Solicitudes. La tarjeta que aparece ahí te da todo lo que necesitas para hacer la primera llamada:
El id del formulario, con un botón de copiar.
Un fragmento de curl y un prompt de MCP, ambos construidos con las claves de campo reales de tu formulario — así el ejemplo ya se dirige a los campos que este formulario tiene de verdad.
Una pestaña Manual que crea una solicitud a mano, y Pruébalo tú mismo, que convierte lo que rellenaste ahí en una solicitud en modo de prueba y te da su enlace.
Un enlace directo a la página de Solicitudes, filtrado a este formulario.
Publica primero
Un formulario sin publicar no puede recibir solicitudes, y los fragmentos de código permanecen desactivados hasta que lo publiques. Las
claves de campo se congelan en la primera publicación — eso es lo que permite que tu automatización siga dirigiéndose a
company_name un año después. Consulta Claves de campo.
Paso 1 — Descubre los campos
fields.list devuelve todos los campos de la versión publicada actual del formulario, con la clave para dirigirte a cada uno,
la forma de valor que espera y a qué grupo pertenece.
curl -X POST https://api.formbase.so/api/v1 \
-H "Authorization: Bearer $FORMBASE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"method":"fields.list","params":{"formId":"j57..."}}'{
"ok": true,
"data": {
"published": true,
"items": [
{ "key": "company_name", "type": "text", "title": "Company", "required": true, "prefillable": true },
{
"key": "company_size", "type": "select", "title": "Company size", "required": false, "prefillable": true,
"options": [
{ "key": "1_50", "label": "1–50" },
{ "key": "51_200", "label": "51–200" }
]
},
{ "key": "case_id", "type": "hidden", "title": "Case", "required": false, "prefillable": false, "context": true },
{ "key": "total", "type": "number", "title": "Total", "required": false, "prefillable": false, "calculated": true },
{ "key": "signature", "type": "signature", "title": "Sign here", "required": true, "prefillable": false }
],
"hasMore": false
}
}context: truemarca un campo oculto. Su valor va encontext, nunca enprefill; la clave de un campo oculto enprefillse rechaza conUNKNOWN_FIELD_KEY.calculated: truemarca un campo calculado. El formulario calcula su valor, así que nadie puede enviarlo; lo lees de vuelta bajo su clave enanswers.prefillable: falsemarca un campo para el que nadie puede suministrar un valor: subida de archivo, firma, pago, reserva de cita y bloques de Documentos. Las preguntas las rellena el propio destinatario. Los campos ocultos y los campos calculados también muestranprefillable: false: los campos ocultos reciben su valor mediantecontext, y los campos calculados no reciben nada.optionslista las opciones de una pregunta de elección. Envía la clave de la opción, no su etiqueta; la etiqueta solo está ahí para que puedas relacionar la opción que conoces con su clave. Una matriz lista susrowsycolumnsde la misma forma.Los grupos repetibles vuelven como una única entrada con
type: “group”,repeating: truey una lista demembers.
Paso 2 — Crea la solicitud
curl -X POST https://api.formbase.so/api/v1 \
-H "Authorization: Bearer $FORMBASE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"method":"requests.create","params":{
"formId":"j57...",
"recipient":{"email":"ada@acme.com","name":"Ada"},
"context":{"case_id":"CASE-9"},
"prefill":{"company_name":"Acme","company_size":"51_200"},
"readonly":["company_name"],
"delivery":"email",
"externalId":"run-42",
"callbackUrl":"https://automation.example/webhook/resume-abc",
"idempotencyKey":"run-42"}}'{
"ok": true,
"data": {
"id": "kd7...",
"status": "pending",
"url": "https://form.formbase.so/r/rq_...",
"deliveryStatus": "queued",
"expiresAt": 1794787200000,
"createdAt": 1789379200000,
"externalId": "run-42",
"deduplicated": false
}
}deliveryStatus es “queued” cuando formbase envía la invitación por email, y “not_requested” cuando
entregas el enlace tú mismo.
Precompletado, campos bloqueados y contexto
Hay tres cosas distintas que se pueden adjuntar a una solicitud, y confundirlas es el error inicial más habitual.
| Va en | El destinatario… | Vuelve en el callback | |
|---|---|---|---|
| Precompletado | prefill | Lo ve y puede cambiarlo | Sí, como una respuesta |
| Campo bloqueado | prefill + readonly | Lo ve, no puede cambiarlo | Sí, como una respuesta |
| Contexto | context | No puede cambiarlo; lo ve solo donde lo menciones | Sí, en el bloque de la solicitud y como una respuesta |
| Metadatos | metadata | Nunca lo ve, y el formulario tampoco | Sí, en el bloque de la solicitud |
Precompletado
Respuestas iniciales para las preguntas visibles, para que el destinatario revise y corrija en lugar de escribir desde cero. Todo lo que ya sepas sobre esa persona pertenece aquí — el nombre de la empresa desde tu CRM, el importe de la factura, las respuestas del año pasado.
Campos bloqueados
Incluye una clave precompletada en readonly y el destinatario verá el valor pero no podrá cambiarlo. Úsalo para los datos que
está confirmando en lugar de proporcionando — el número de contrato, el precio acordado. El bloqueo es por solicitud: el formulario en sí
no se toca, y el mismo campo queda libremente editable en la siguiente solicitud.
Toda clave bloqueada también debe estar precompletada, y un campo bloqueado obligatorio debe precompletarse con algo no vacío — de lo contrario el destinatario se enfrentaría a un formulario que nunca podría enviar, y formbase rechaza la llamada en lugar de crear esa trampa.
Contexto
Valores de confianza para los campos ocultos del formulario — un número de caso, un id de ejecución de flujo, un importe. El contexto alimenta variables, lógica condicional, campos calculados y copys de correo, vuelve sin cambios en el callback, y el destinatario no puede alterarlo. Esa última parte es la diferencia frente a sembrar un campo oculto mediante una URL en un enlace público, donde cualquiera puede editar la cadena de consulta; los enlaces de solicitud ignoran por completo los parámetros de consulta de la URL. Los valores de contexto deben ser una cadena, un número o un booleano.
El contexto no es de formato libre: cada clave debe ser un campo oculto en la versión publicada del formulario, y cualquier otra clave se
rechaza con UNKNOWN_FIELD_KEY. La contabilidad interna que no tiene un campo oculto, como un id de ejecución, pertenece a
metadata.
Los campos ocultos no se muestran en el formulario, pero un valor de contexto no es secreto para el destinatario. Lo ve donde sea que el
formulario o la invitación lo muestren: una mención en el contenido del formulario o en el
texto del correo, o una pregunta visible que usa ese campo oculto como su
valor predeterminado. En ese último caso, el destinatario ve el valor
de contexto precompletado en esa pregunta y puede editar la respuesta. El valor de contexto en sí permanece sin cambios. Un
prefill para la clave propia de esa pregunta tiene prioridad sobre el valor predeterminado.
Metadatos
Tu propia contabilidad interna — un id de ejecución, un id de registro del CRM. Nunca llega al formulario, así que no se puede insertar en el texto ni leer por la lógica; solo viaja junto a la solicitud y vuelve en cada callback y lectura de estado.
Formas de valor
Envía los valores en la forma que pida el type de fields.list. Una forma incorrecta vuelve como un error de
validación que nombra la clave, el tipo esperado y — para preguntas de elección — los valores que se habrían aceptado.
| Tipo | Envía |
|---|---|
| text, email, phone, url, textarea | Una cadena de texto |
| number, rating, scale | Un número |
| switch | true o false |
| date | "2026-03-04" |
| time | "09:30" o "09:30:00" |
| radio, select | La clave de la opción, no su etiqueta |
| checkbox, ranking, picture-choice | Un array de claves de opción |
| matrix | Un objeto de clave de fila a clave de columna: { "row_key": "column_key" } |
| group (repetible) | Un array de instancias, como máximo 100: [{ "member_key": value }, …] |
| file, signature, payment, schedule-appointment | Nada — los suministra el destinatario |
| cualquier campo con calculated: true | Nada — el formulario lo calcula |
| documents | Nada en el precompletado — usa la opción documents de abajo |
Documentos
Un bloque de documentos le entrega archivos al respondente. Sus documentos creados por ti son los mismos para todos y siempre permanecen; una solicitud añade archivos para su único destinatario debajo de ellos — el propio contrato de alquiler del cliente, una copia del DNI para revisar. Los bytes nunca viajan por la propia llamada a la API: primero se sube, y luego se referencia.
- 1
Reserva la subida
Llama a documents.create con formId, name (1–200 caracteres), contentType (PDF o imagen), el tamaño exacto en bytes y, opcionalmente, un sha256 del archivo (64 caracteres hexadecimales). Recibes de vuelta un id y una uploadUrl válida durante una hora.
- 2
Sube los bytes
Haz un PUT del archivo a uploadUrl con el mismo Content-Type. Todavía no se verifica nada.
- 3
Referéncialo en la solicitud
Pasa documents: [{ documentId, name? }] en requests.create. formbase comprueba el objeto subido (tamaño, firma del archivo, sha256 si enviaste uno) antes de crear la solicitud, y el destinatario ve el archivo en el bloque.
"documents": [
{ "documentId": "kn7...", "name": "Your lease contract" },
{ "documentId": "kn8..." }
]name sustituye el nombre visible guardado con la subida. Si el formulario tiene más de un bloque de documentos, indica el
destino con field, la clave de campo del bloque (fields.list la muestra, junto con los documentos de autor que
ya reciben todos los encuestados). Los archivos aparecen debajo de esos documentos de autor: una solicitud añade archivos, nunca sustituye
ninguno. Una misma subida se puede referenciar desde tantas solicitudes como quieras — una lista de precios subida una vez sirve a
quinientas solicitudes.
Límites: solo PDF e imágenes, 25 MB por documento, 100 MB por solicitud (DOCUMENTS_TOO_LARGE), y como máximo 20 documentos
por bloque contando los documentos de autor (DOCUMENTS_TOO_MANY). Los archivos cuentan contra el almacenamiento de tu espacio
de trabajo y se liberan en cuanto las solicitudes que los referencian salen de la ventana de retención del formulario. La respuesta
registra la lista que vio el destinatario bajo la clave de campo del bloque, así que el callback te dice exactamente qué archivos recibió
esa persona.
El resto de las opciones
| Opción | Qué hace |
|---|---|
| language | El idioma en el que se abre el formulario y en el que está redactada la invitación; uno de los idiomas publicados del formulario. Si se omite, usa el idioma predeterminado del formulario. El destinatario puede seguir cambiando de idioma, igual que en un enlace público. |
| delivery | "email" envía la invitación por ti y requiere un email de destinatario y un plan Pro o Business, o una de las 10 invitaciones gratis de una cuenta Free; "none" (el valor predeterminado) significa que tú entregas el enlace. |
| reminders | Sustituye el calendario de recordatorios del formulario solo para esta solicitud con hasta cinco retrasos de inactividad como ["2d", "12h", "30m"], o pasa una lista vacía para desactivar los recordatorios en ella. Un calendario personalizado requiere un email de destinatario y un plan Pro o Business; sin un email de destinatario, el calendario propio del formulario simplemente no se ejecuta. |
| expiresAt | Cuándo deja de funcionar el enlace, como marca de tiempo Unix en milisegundos. Por defecto 30 días; 365 días es el máximo. |
| externalId | Tu propio id para esta solicitud. Puedes filtrar por él más tarde. |
| idempotencyKey | Hace que una ejecución reintentada reutilice la solicitud en lugar de crear una segunda. |
| callbackUrl | Adónde envía formbase el callback por POST cuando la solicitud termina. Solo HTTPS. |
| domainId | Genera el enlace en uno de tus dominios personalizados, en lugar del dominio en el que el formulario ya está publicado. |
| test | Una prueba en seco: no se envía nada, el callback dice test, y la respuesta no cuenta en ningún sitio. Ver más abajo. |
Modo de prueba
Pasa test: true para poner a prueba todo el circuito antes de una ejecución real. Una solicitud de prueba es real en todo lo
que importa para la integración: el enlace se abre y se puede completar, el callback se dispara como
siempre, y requests.get devuelve las respuestas. Lo que nunca hace es llegar a nadie ni a nada que después tengas que
limpiar:
No se envía ninguna invitación ni ningún recordatorio, sea lo que sea lo que diga
delivery. Enviar recordatorio se rechaza en ella, y no gasta nada de tu asignación mensual.El callback lleva
“test”: true, para que tu flujo de trabajo pueda bifurcar o ignorar el evento.La respuesta se almacena pero no cuenta: ni contra tu cuota mensual (una prueba se completa incluso con la cuota agotada), y nunca aparece en los recuentos de respuestas del formulario, en la pestaña de respuestas, en las exportaciones, ni en tus integraciones. Nadie recibe notificación.
La solicitud queda oculta en la página de Solicitudes detrás de Mostrar solicitudes de prueba, se deja fuera del embudo de solicitudes en Analytics, y se deja fuera de
requests.listsalvo que pasesincludeTest: true.El enlace se cierra en un plazo de 24 horas, incluso cuando
expiresAtpide más; elexpiresAtde la respuesta indica cuándo. En Free, un workspace puede crear 10 solicitudes de prueba al día. La siguiente falla conRATE_LIMITEDy el motivoTEST_REQUEST_LIMIT_REACHED, yretryAfterMsindica cuándo puedes volver a intentarlo. Pro y Business no tienen límite diario.
Pruébalo tú mismo en la hoja de compartir es este modo con un solo clic: toma el borrador de la pestaña Manual, deja fuera el destinatario y la entrega, y te da el enlace para abrirlo tú mismo.
Lo que cuesta una solicitud
Todo plan tiene una asignación mensual compartida por ambos canales: un envío por enlace público gasta una unidad, y
también lo hace cada solicitud que creas — la responda el destinatario, la ignore, o la cancele tú. La respuesta que recopila una
solicitud ya está pagada y no cuenta en ningún sitio. Free incluye 1.000 unidades al mes, Pro y Business 50.000; el contador se reinicia
el día 1 de cada mes, UTC. Al llegar al tope, requests.create falla con UPGRADE_REQUIRED y motivo
MONTHLY_ALLOWANCE_REACHED; las solicitudes que ya habías creado siguen pudiéndose responder.
En Free, una solicitud creada con “delivery”: “email” también gasta una de las
10 invitaciones gratis de la cuenta. No se reinician nunca; cuando
se agotan, el envío por correo falla con UPGRADE_REQUIRED y motivo FREE_INVITATIONS_USED.
Idempotencia
Pasa la misma idempotencyKey con el mismo cuerpo y recibes la solicitud original de vuelta, con
deduplicated: true y el enlace original — sin segunda solicitud, sin segundo correo. Reutiliza la clave con un cuerpo
distinto y formbase lo rechaza con IDEMPOTENCY_CONFLICT en lugar de adivinar cuál querías. Las claves están
limitadas al espacio de trabajo y se respetan durante 30 días; pasado ese tiempo, la misma clave inicia una solicitud nueva.
En una herramienta de flujos de trabajo, el id de ejecución es la clave natural: una ejecución reintentada tras un fallo de red recupera la solicitud que ya había creado.
Límite de frecuencia
requests.create y documents.create comparten un presupuesto de 60 llamadas por minuto, contado
por token de API (o por usuario, para una llamada hecha sin uno). Un backlog que estás vaciando debería ir a su propio ritmo; una ráfaga
que supere el presupuesto se rechaza y se puede reintentar.
Dominios personalizados
Si el formulario ya está publicado en uno de tus dominios personalizados, los enlaces de
solicitud se generan ahí automáticamente — https://forms.tuempresa.com/r/rq_…. Especifica domainId
explícitamente cuando el formulario esté publicado en más de uno. El dominio debe pertenecer al mismo espacio de trabajo que el
formulario.
Lo que ve el destinatario
Exactamente el formulario que tú creaste — mismo tema, mismo logo, mismo idioma — con sus valores en su sitio, los campos bloqueados en solo lectura, y sin captcha que resolver. Cuando lo envía, ve tu página de agradecimiento. Si vuelve al enlace después, ve la página de resultado en lugar de un formulario en blanco.
No hay ningún mensaje de tu automatización en la página. Todo lo que el destinatario necesite saber debe ir en el propio formulario, donde puedes personalizarlo mencionando un valor de contexto o un campo precompletado.
Un agente de IA ejecuta los mismos dos pasos que fields_list y request_create, con las mismas opciones —
documents y domainId incluidos. Consulta Solicitudes en el servidor MCP.