API pública de formularios
Los cinco endpoints sin autenticación que usa el formulario insertado en tu web: configuración, envío, vistas y errores, con sus límites y respuestas.
Actualizado el . 8 min de lectura
Incluido en los planes Profesional y Avanzado. Ver precios
Cuando insertas un formulario de captación en tu web, el script del formulario habla con cinco endpoints públicos de UTILIA OS: uno para descargarse, otro para leer la configuración del formulario, otro para enviar las respuestas y dos de estadística. Esta página los documenta por si quieres entender qué pasa por debajo o construir tu propio formulario sobre ellos.
No llevan clave de API ni sesión: cada formulario se identifica por su slug, que es único en toda la plataforma. Todos cuelgan de /api/v1/forms.
| Endpoint | Para qué sirve |
|---|---|
GET /api/v1/forms/widget.js | Descarga el script del formulario. |
GET /api/v1/forms/:slug/config | Devuelve la configuración pública del formulario. |
POST /api/v1/forms/:slug/submit | Envía las respuestas al CRM. 10 envíos por minuto y dirección IP. |
POST /api/v1/forms/:slug/view | Suma una vista al formulario. Responde 204. |
POST /api/v1/forms/:slug/error | Suma un error al formulario. Responde 204. |
Lo que protege el envío es el límite por dirección IP, el consentimiento obligatorio y que el formulario esté publicado. Los orígenes permitidos (CORS) solo los aplica el navegador y no frenan envíos automatizados: está explicado en Insertar un formulario en tu web.
Script del formulario
/api/v1/forms/widget.jsScript JavaScript del formulario
Es el archivo que carga el código de inserción. El navegador lo guarda 24 horas (Cache-Control: public, max-age=86400). Al cargarse, busca en la página los elementos con el atributo data-utilia-form, pide la configuración de cada formulario y lo pinta según su tipo y sus estilos.
Configuración del formulario
/api/v1/forms/:slug/configConfiguración pública del formulario
Devuelve lo necesario para pintar el formulario: campos, estilos, tipo, disparador y textos. No incluye la clave de API, las estadísticas, el propietario ni el identificador de la organización.
El servidor guarda esta respuesta 5 minutos, así que un cambio en el formulario puede tardar ese tiempo en verse en tu web.
Respuesta (200):
{
"slug": "a1b2c3d4e5",
"name": "Formulario de contacto",
"description": "Formulario principal de la web",
"fields": [
{
"id": "field_email",
"type": "email",
"label": "Correo electrónico",
"required": true,
"order": 0,
"leadField": "email"
}
],
"styling": {
"primaryColor": "#2563EB",
"backgroundColor": "#FFFFFF",
"textColor": "#111827",
"fontFamily": "Inter",
"borderRadius": 8
},
"widgetType": "POPUP",
"widgetPosition": "center",
"widgetTrigger": "button",
"triggerDelay": 5,
"triggerScroll": 50,
"showOnMobile": true,
"showBranding": true,
"submitButtonText": "Enviar",
"successTitle": "Gracias",
"successMessage": "Hemos recibido tu información correctamente.",
"privacyText": "Al enviar aceptas nuestra política de privacidad.",
"privacyUrl": "https://tuempresa.com/privacidad",
"requiredConsentVersion": 2,
"captureUtm": true,
"utmPersistence": "NONE"
}requiredConsentVersiones la versión vigente de la cláusula informativa de protección de datos del formulario, y queda en el justificante de consentimiento de cada lead. Los formularios nuevos nacen con la versión 2, que informa también de la medición del origen; los anteriores conservan la suya.captureUtmyutmPersistencele dicen al script si debe recoger las etiquetas de origen de la visita y si puede recordarlas entre páginas.
Errores:
| Código | Cuándo |
|---|---|
| 400 | El formulario existe pero no está publicado. |
| 404 | El slug no existe. |
| 404 | El plan de la organización dueña ya no incluye los formularios de captación. |
Si un formulario que funcionaba empieza a dar 404
Cuando el plan de la organización dueña deja de incluir el aplicativo CRM o la capacidad de leads (crm.leads), la configuración y el envío responden 404 con el mismo cuerpo que un slug inexistente, no 403. Es deliberado: el formulario deja de captar sin contar el motivo comercial a un visitante anónimo, y se comprueba también con la configuración en caché. Antes de buscar un fallo en tu web, comprueba el plan. Contexto en Errores de plan.
Enviar el formulario
/api/v1/forms/:slug/submitEnvía las respuestas al CRM
Recibe las respuestas y crea un lead nuevo en el CRM de la organización dueña del formulario o, si el correo ya es de un lead, añade el envío a su ficha. Admite 10 envíos por minuto por dirección IP; al superarlo responde 429. El servidor toma la IP real del visitante aunque haya proxies por medio.
Cuerpo de la petición
Un objeto con el valor de cada campo, usando su id como clave, más tres campos opcionales de medición: _pageUrl (la página desde la que se envía), _utm (de dónde vino la visita) y _ur (el identificador firmado del destinatario de una campaña de correo, si el enlace lo traía).
{
"field_email": "juan@empresa.com",
"field_nombre": "Juan Pérez",
"field_telefono": "+34 612 345 678",
"art13_consent": true,
"_pageUrl": "https://tuempresa.com/servicios",
"_utm": {
"source": "email",
"medium": "campaign",
"campaign": "boletin-agosto"
},
"_ur": "r1.eyJ2IjoxLCJvIjoi..."
}Todo formulario lleva un campo de consentimiento informativo obligatorio (artículo 13 del RGPD). Si el formulario no define uno propio, el servidor añade el campo por defecto con el identificador art13_consent. Para que el envío se procese, su valor tiene que ser true o "true".
Medición del origen: _utm y _ur
Solo se tienen en cuenta si el formulario tiene encendida la captura del origen (captureUtm, encendida por defecto).
_utmadmite cinco claves (source,medium,campaign,termycontent); cada valor se recorta a 200 caracteres. Se guardan enmetadata.tracking.utmdel lead, que es lo que leen la analítica de orígenes y la tarjeta «Origen del lead» del CRM._ures una cadena de hasta 1.024 caracteres. Con ella, el lead se atribuye siempre a la campaña, y al envío concreto solo si el correo escrito en el formulario es el mismo al que se envió la campaña. Si no coincide (alguien reenvió el correo), se guarda solo la campaña: guardar el envío metería en la ficha de un tercero el dato de otra persona._urno rellena ningún campo del formulario, precisamente para que un correo reenviado no filtre la dirección de quien lo recibió.- Si el formulario tiene configurado su propio origen de lead, ese sigue mandando en el campo
source; los datos de medición se guardan aparte.
Lo que no encaja (claves desconocidas, un _ur estropeado, caducado o de otra organización) se descarta en silencio y el formulario se envía igual: la medición nunca es motivo para perder un contacto.
Qué hace el servidor con el envío
Qué hace el servidor con un envío
Comprueba los consentimientos
Todos los campos de consentimiento obligatorios tienen que valer true o "true".Si no: 400 CONSENT_REQUIRED y no se crea nada.
Asigna cada campo al lead
Los campos con leadField van a esa propiedad; los de correo, a la suya aunque no lo tengan; el resto, a metadata.Si no: 400 si falta el correo principal o no es válido.
Calcula la puntuación
La fija del formulario o, si no tiene, 25 puntos más 10 por teléfono, 15 por empresa, 10 por cargo y 5 por sitio web.Crea el lead y el justificante
Asignado a quien creó el formulario, con el origen y las etiquetas por defecto y el justificante de consentimiento.
El justificante guarda la versión de la cláusula, el texto aceptado, los enlaces, la fecha, la IP, el navegador, los correos aportados (contactPointsConsented) y todas las casillas de consentimiento marcadas.
Después, el lead se comporta como cualquier otro: avisa a las personas configuradas, dispara las automatizaciones y los avisos a tu servidor del evento de lead creado y aparece al momento en la lista de leads del CRM. Si quien creó el formulario ya no está activo, el lead entra sin asignar.
Si el correo principal o el secundario ya son de un lead no archivado de la organización, no se crea otro ni se cambian sus datos: el envío se añade a la ficha de ese lead como una interacción (una por formulario y día, con lo que escribió la persona y su justificante de consentimiento), y la respuesta es la misma que la de un lead nuevo, para que nadie pueda averiguar desde fuera qué correos tienes en el CRM.
Respuesta (201)
{
"success": true,
"lead": {
"email": "juan@empresa.com",
"fullName": "Juan Pérez"
}
}email y fullName son los que se acaban de enviar. La respuesta es idéntica tanto si se crea un lead como si el correo ya tenía uno, y por eso no incluye el identificador del lead.
Errores
| Código | Motivo |
|---|---|
400 CONSENT_REQUIRED | No se aceptó un consentimiento obligatorio. El cuerpo trae message y el fieldId del campo. |
400 INVALID_EMAIL_FORMAT | Un campo de correo no tiene formato válido. El cuerpo trae message y fieldId. |
| 400 | Falta el correo principal, el principal y el secundario coinciden, un campo supera su longitud máxima o no es un valor de texto, el formulario no está publicado o su clave de API está desactivada. |
| 404 | El slug no existe, o el plan de la organización dueña ya no incluye los formularios de captación (mismo cuerpo en los dos casos). |
| 429 | Se superaron los 10 envíos por minuto desde esa dirección IP. |
{
"code": "CONSENT_REQUIRED",
"message": "Debes aceptar la información del tratamiento de datos para enviar el formulario.",
"fieldId": "art13_consent"
}Registrar una vista
/api/v1/forms/:slug/viewSuma una vista al formulario
El script lo llama cuando carga el formulario en la página, una sola vez por sesión del navegador, aunque se trate de una ventana emergente que todavía no se ha abierto. No lleva cuerpo y responde 204 sin contenido. Las vistas son la base de la tasa de conversión (envíos entre vistas). Si el slug no existe, no hace nada y responde igual.
Registrar un error
/api/v1/forms/:slug/errorSuma un error al formulario
El script lo llama cuando un envío falla. Responde 204 sin contenido; el servidor solo suma uno al contador de errores del formulario e ignora el cuerpo.
¿Formulario o API de leads?
Formulario (POST /api/v1/forms/:slug/submit) | API de leads (POST /api/v1/leads) | |
|---|---|---|
| Autenticación | Ninguna: el slug del formulario | Cabecera X-API-Key |
| Campos | Los del formulario | Libres, los que envíes |
| Consentimiento | Campo obligatorio validado en el servidor | Responsabilidad tuya |
| Puntuación | Fija del formulario o calculada | Calculada |
| Límite | 10 envíos por minuto por IP | El de la clave, por hora |
| Fuera de plan | 404, igual que un slug inexistente | 403 con MODULE_NOT_ENABLED o CAPABILITY_NOT_ENABLED |
| Para qué | Captar desde el navegador de tus visitantes | Integraciones de servidor a servidor |
Ambos tienen además un tope general de 600 peticiones por minuto por dirección IP.