Saltar al contenido principal

Formato de formularios

Para desarrolladores

Un formulario completo se puede describir como un solo documento JSON: qué pregunta y en qué orden, qué dice su página, cómo se ve, qué correos envía, adónde van sus envíos y a quién se le avisa de cada uno. Es el documento que un asistente de IA escribe, conectado por MCP o con el texto que copia el panel.

La especificación nombra los campos, los valores y los códigos tal como los escribe y los devuelve la plataforma.

El formato del documento de formulario​

Un formulario de la plataforma como un solo documento JSON: qué pregunta y en qué orden, qué dice su página, cómo se ve, qué correos envía, adónde van sus envíos y a quién se le avisa de cada uno. Junto con este texto, el formato se entrega como un JSON Schema (draft 2020-12), json_schema: la estructura de cada objeto, el tipo y las restricciones de cada valor, y lo que vale cada uno cuando falta.

El documento es el formulario completo​

Un documento es el estado completo de un formulario. Crear un formulario guarda todo lo que el documento define. Reescribirlo deja el formulario exactamente como lo define el documento, así que lo que el documento omite se quita: un documento sin dataset deja de alimentar el dataset, y uno sin notifications deja de enviar avisos. Para cambiar un valor, lea el documento del formulario, cámbielo y envíe el documento completo.

El formato es cerrado: una clave que el schema no declara es un error, en cualquier nivel.

Estructura resumida del documento (las anotaciones a la derecha no forman parte del JSON):

{ "version": 1,
"name": "…", único entre los formularios de la instancia
"type": "registration",
"items": [ … ], lo que muestra el formulario, de arriba hacia abajo
"texts": { … }, los textos de la página pública
"required_marker": "required",
"design": { … }, colores, logo y CSS
"sender": { "email": "…" },
"double_opt_in": { "enabled", "template" },
"auto_reply": { "enabled", "template" },
"dataset": { "name" | "id" },
"notifications": { "emails", "routing" },
"allowed_origins": [ … ] }

version, name e items son obligatorios. Todo valor con default en el schema puede omitirse; la plataforma lo escribe, y lo que devuelve es el documento con cada valor por defecto escrito (normalizado), con las claves en el orden de arriba.

  • Un formulario pide datos de contacto, consentimiento o ambos: sus ítems dicen cuáles. Un ítem de consentimiento necesita el módulo de gestión de consentimiento en el plan de la instancia.
  • type: siempre registration, un link abierto que crea o actualiza un contacto con cada envío.

Ítems​

Cada ítem tiene un kind, y cada tipo es cerrado sobre sus propias claves.

kindClavesMuestra
fieldfield_key (obligatoria), required (false), width (full), new_fielduna pregunta, respondida con un campo del catálogo
consentterm (obligatoria), required (false)una casilla para un término de consentimiento
textcontent (obligatoria, hasta 2.000 caracteres)un párrafo; se conservan los saltos de línea
dividerningunauna línea horizontal
  • Un formulario no debe preguntar dos veces el mismo campo, ni dos veces el mismo término de consentimiento.
  • width: half pone en una fila dos campos consecutivos de medio ancho.
  • Un ítem de consentimiento muestra la versión vigente del término, la que sea cuando un visitante abre el formulario; el documento nombra el término, nunca una versión.
  • Cada canal que un término de consentimiento autoriza necesita el campo que identifica al contacto en ese canal: mail necesita EMAIL; sms, wsp y call necesitan PHONE.
  • El consentimiento se pide solo con un ítem consent que nombra uno de los términos de la instancia. Un campo no debe reemplazarlo: un boolean que dice «Acepto…» es un valor como cualquier otro, y no deja evidencia, ni una regla por finalidad y canal, ni nada que el envío revise. Cuando ningún término de la instancia sirve, el formulario no puede pedir ese consentimiento hasta que se cree el término (en el panel, Privacidad → Consentimiento): un agente al que se le pide uno lo dice en una frase en vez de escribir un documento.

Un campo que el catálogo todavía no tiene​

Un ítem de campo nombra un campo del catálogo por su clave. Cuando la clave no está en el catálogo, el ítem debe declarar el campo en new_field, y escribir el documento lo crea:

{ "kind": "field", "field_key": "AREA_INTERES", "required": true,
"new_field": { "name": "Área de interés", "type": "select",
"config": { "oneOf": [ { "const": "VENTAS", "title": "Ventas" },
{ "const": "SOPORTE", "title": "Soporte" } ] } } }
  • type es uno de text, textarea, url, address, email, phone, number, date, boolean, select, multiselect.
  • config son las reglas del campo, en el vocabulario del contrato de configuración de campos (GET /v1/fields/format): las opciones como {const, title} en oneOf (selección única) o en items.anyOf (selección múltiple), minLength/maxLength, minimum/maximum, formatMinimum/formatMaximum, y un pattern o un patrón predefinido por su nombre (x-patternPreset). Un campo de selección única o múltiple debe declarar sus opciones. Los campos nuevos de un documento declaran a lo más 2.500 opciones entre todos; un campo que el catálogo ya tiene no cuenta.
  • La clave de un campo son letras mayúsculas, dígitos y guion bajo, hasta 64 caracteres. Las claves que empiezan con FIDE_ son de la plataforma, y la clave de un campo eliminado no se puede volver a usar.
  • Declarar un campo nuevo requiere el permiso de gestionar el catálogo de campos, que gestionar formularios no da.
  • Un ítem para una clave que el catálogo tiene no debe llevar new_field: el formulario usa el campo del catálogo tal como está. Cambiar un campo del catálogo lo cambia para todos los formularios y datasets que lo usan, así que se hace en el catálogo, no desde un formulario.

Referencias​

Un término de consentimiento, una plantilla de correo y un dataset ya existen en la instancia; el documento los nombra y nunca los crea. Una referencia es un objeto con name, id o ambos:

{ "name": "Confirmación de suscripción" }
{ "id": 12 }
{ "name": "Confirmación de suscripción", "id": 12 }
  • Por nombre, como lo muestra el panel; no distingue mayúsculas.
  • Por id: un id solo significa algo en la instancia de donde viene. Copiado de otra instancia o de otro entorno, nombra otra fila allá, o ninguna.
  • Ambos: deben nombrar al mismo. Cuando no, el hallazgo dice el id que tiene en esta instancia el nombrado.

Se dé lo que se dé, el plan muestra el nombre y el id a los que resolvió cada referencia, antes de escribir nada. Lo que la plataforma devuelve nombra cada referencia por ambos.

El remitente se nombra por su dirección: { "email": "[email protected]" }. Debe ser un remitente transaccional: el correo de un formulario es la confirmación y la respuesta que un visitante está esperando.

La página​

  • texts: title (hasta 255 caracteres; si falta, el nombre del formulario), header y footer (hasta 1.000), submit_label y submit_pending_label (hasta 60), success_message y pending_message (hasta 300). Un texto omitido muestra la redacción propia de la plataforma.
  • required_marker: required marca los ítems obligatorios con *; optional marca con (opcional) los que no lo son.
  • design: primary_color y secondary_color (hexadecimal en minúsculas, #1d4ed8), logo_url (http o https) y custom_css.

Estilos con custom_css​

custom_css se aplica bajo la raíz del formulario, .fd-form, y en ningún otro lugar: una regla no puede alcanzar la página que inserta el formulario. Sus reglas quedan anidadas dentro de .fd-form { … }, así que se escriben como se escribirían ahí: .fd-submit { … } da estilo al botón, y una declaración suelta o & { … } da estilo a la raíz. Un selector no debe empezar con la raíz (.fd-form, o su id): anidado, la busca dentro de sí misma y no aplica a nada. Tiene a lo más 16 KB, sus llaves deben estar balanceadas, y no debe contener </style, <script, @import, expression(, url( ni image-set(, leído con sus escapes de CSS decodificados, como lo lee el navegador: u\72l( es url(.

Las clases de abajo, y el atributo data-field, son el contrato en el que una hoja de estilos puede apoyarse. Cualquier otra clase de la página es de maquetación y puede cambiar sin aviso.

SelectorElemento
.fd-formla raíz del formulario
.fd-form-logoel logo (en la página propia del formulario; el componente inline no muestra logo)
.fd-form-titleel título
.fd-form-textel header, el pie y cada ítem de texto
.fd-form-fieldsel contenedor de los ítems
.fd-fielduna pregunta, con su etiqueta y su campo
.fd-field[data-field="EMAIL"]la pregunta de una clave de campo dada
.fd-labella etiqueta de una pregunta
.fd-inputel campo, la lista, el área de texto o el grupo de casillas de una pregunta
.fd-hintel ejemplo o el rango bajo una pregunta
.fd-optional-markerla marca (opcional)
.fd-consentun ítem de consentimiento
.fd-divideruna línea divisoria
.fd-submitel botón de envío
.fd-message-success, .fd-message-pendingel mensaje después de un envío
.fd-errorun mensaje de error

Correos​

  • double_opt_in: con enabled: true, un envío queda pendiente hasta que el contacto sigue el enlace de un correo de confirmación. template es obligatorio y debe llevar el enlace fide:confirm. La doble confirmación necesita EMAIL como ítem obligatorio: es adonde se envía el enlace.
  • auto_reply: con enabled: true, un correo que se le envía al contacto después de cada envío confirmado. template es obligatorio.
  • sender es obligatorio cuando cualquiera de los dos está activo, ya que es el remitente de ambos correos.

Dataset​

dataset nombra el dataset en que se guarda cada envío confirmado. El formulario debe preguntar, como ítems obligatorios, todas las columnas que el dataset exige, su campo identificador entre ellas.

Avisos​

notifications dice quién recibe un correo con cada envío confirmado. Estas direcciones reciben los datos personales que el formulario recoge.

  • emails: hasta 10 direcciones que reciben el aviso de cada envío. Con routing, reciben solo los envíos cuya respuesta no está en map.
  • routing: destinatarios según la respuesta a un campo de selección única del formulario. field_key lo nombra, y map lleva la clave de cada opción a hasta 10 direcciones. Un envío cuya respuesta está en map va a esas direcciones en lugar de a emails; cualquier otro va a emails. Cada clave de map debe ser una opción del campo.

Orígenes permitidos​

allowed_origins lista los sitios que pueden insertar el formulario, como orígenes simples (https://www.example.com): hasta 10, y 255 caracteres unidos por , . Cada sitio se nombra por separado: un comodín como https://*.example.com se rechaza, así que liste cada subdominio. Vacío, cualquier sitio puede mostrar el formulario en un iframe, y el componente en línea, que lo dibuja dentro de la página del sitio, se rechaza: solo carga en un sitio que esta lista nombra.

Validar, el plan y la huella​

Un formulario cambia lo que ve un visitante y quién recibe sus datos, así que una escritura sigue a un plan que la persona que pidió el cambio vio.

  1. Valide el documento. La respuesta son todos los hallazgos y, cuando ninguno es un error, el plan y su huella (fingerprint).
  2. Muestre el plan a la persona, completo, y espere su confirmación explícita.
  3. Escriba el documento con la huella del plan.

La huella ata la escritura al plan: un documento que cambió después de validarse, un formulario que alguien cambió entretanto, o un término, una plantilla, un remitente o un dataset que el documento nombra y que cambió desde entonces, tienen otra huella y la escritura se rechaza (document_fingerprint_mismatch). Valide de nuevo y confirme el plan nuevo. La huella prueba que lo escrito es el plan; no prueba que alguien lo haya visto, que es el paso 2 de quien llama.

Un hallazgo tiene un level (error impide la escritura, warning no), un code, el pointer JSON del valor al que se refiere, un message y un fix. Corrija el documento y valídelo de nuevo. Vuelven a lo más 100 hallazgos; pasados esos, uno document_findings_truncated dice cuántos más hay.

Una solicitud que incluye un documento puede pesar como máximo 1 MB; si lo supera, se rechaza con un error 413 aunque cada clave respete su propio límite.

El plan​

El plan describe la configuración completa que la escritura dejaría en el formulario, sin omitir ni abreviar ningún elemento: lista cada ítem en orden, cada campo que el documento crea con su configuración completa, cada consentimiento con su término, su versión vigente, sus canales, sus finalidades y el campo que identifica al contacto en cada canal, el dataset, el remitente y las plantillas, los textos y el CSS literales, cada sitio que puede insertar el formulario y cada dirección que recibe los envíos, opción por opción del ruteo: una opción sin direcciones propias muestra que va a emails.

Un formulario nuevo se crea inactivo; empieza a recibir envíos cuando se activa.

Reescribir un formulario​

Reescribir compara los ítems por lo que los identifica, nunca por su posición: un campo por su clave, un consentimiento por su término. Un ítem que se queda conserva su identidad, así que los envíos ya guardados lo siguen apuntando; uno que sale se quita y uno que llega se agrega. El plan de una reescritura es una diferencia. Cada ítem trae un status: kept (se queda, con sus cambios y si se movió), added (se agrega) o written (textos y separadores, que no identifican nada y se escriben de nuevo). Trae además los ítems quitados y cada ajuste con su valor antes y después.

  • Una reescritura de un formulario activo se ve de inmediato en su enlace público y en cada sitio que lo inserta; el plan lo dice.
  • Un formulario activo debe seguir siendo válido: una reescritura que rompe una regla que su activación comprueba es un error. En un formulario inactivo, la misma regla es una advertencia, que vuelve a aparecer al activarlo.
  • Quitar un campo mientras hay envíos esperando su doble confirmación es una advertencia: una vez confirmados, ya no llevan esa respuesta al dataset ni al ruteo.

Códigos​

CódigoQué significa
document_key_unknownuna clave que el objeto no admite
document_value_missingfalta una clave obligatoria
document_value_invalidun valor fuera de su tipo, rango, largo o patrón
document_options_too_manylos campos nuevos declaran más de 2.500 opciones
document_findings_truncatedmás de 100 hallazgos; el resto no se muestra
document_version_unsupportedversion no es 1
item_kind_unknownel kind de un ítem no es field, consent, text ni divider
item_field_duplicatedel formulario pregunta dos veces un campo
item_term_duplicatedel formulario pregunta dos veces un término de consentimiento
field_not_founduna clave de campo que el catálogo no tiene, sin new_field
field_inactiveel campo del catálogo está inactivo
new_field_existsnew_field para una clave que el catálogo tiene
field_key_system_prefixla clave de un campo nuevo empieza con FIDE_
field_key_reservedla clave de un campo nuevo fue de un campo eliminado
field_name_takenel nombre de un campo nuevo es el de otro campo del catálogo
field_config_*, option_*, pattern_*la configuración de un campo nuevo, como la informa el contrato de configuración de campos
reference_emptyuna referencia sin nombre ni id
reference_id_mismatchel id dado no es el del nombrado
term_not_found, template_not_found, dataset_not_foundnada con ese nombre o id
sender_not_foundningún remitente envía desde esa dirección
sender_is_bulkel remitente es masivo
consent_module_not_in_planel plan no incluye gestión de consentimiento
consent_term_inactiveel término está inactivo
consent_term_no_current_versionel término no tiene versión vigente
consent_channel_not_coveredun canal del término no tiene campo identificador en el formulario
confirmation_requires_emaildoble confirmación sin un EMAIL obligatorio
confirmation_link_missingla plantilla de confirmación no tiene el enlace fide:confirm
form_dataset_columns_not_collecteduna columna que el dataset exige no se pregunta como obligatoria
routing_field_not_on_formel ruteo lee un campo que el formulario no pregunta
routing_field_not_selectel campo del ruteo no es de selección única
routing_option_unknownuna clave del ruteo que no es una opción del campo
custom_css_forbiddenel CSS usa un fragmento prohibido
custom_css_too_largeel CSS pasa de 16 KB
custom_css_unbalanceduna { que no cierra, o una } que no cierra nada
custom_css_root_prefixun selector que empieza con la raíz (.fd-form, o su id)
allowed_origin_invalidun sitio que no es un origen simple: con ruta, credenciales o comodín
allowed_origins_too_longlos sitios no caben en 255 caracteres
form_name_takenotro formulario tiene ese nombre
pending_submissions_lose_removed_answers(warning) campos quitados y confirmaciones pendientes
document_fingerprint_mismatchel documento o el formulario cambiaron después del plan

Dónde seguir​