Referencia del esquema y de la API
Esta página es para quien quiere ver o escribir un formulario en JSON (con Editar como JSON, Importar o la API) o integrarlo desde una aplicación propia. Para diseñar con el ratón, ver Diseñar un formulario.
Esquema 2
Sección titulada «Esquema 2»Un formulario es un JSON con schema: 2. Las claves técnicas van en inglés; los textos que ve una persona, en tu idioma.
{ "schema": 2, "title": "Ítems con total", "description": "Opcional", "inputs": { "solicitante": { "type": "string", "required": true, "label": "Solicitante" } }, "sections": [ { "id": "s_items", "title": "Ítems", "columns": 1, "items": [ { "field": "items" }, { "field": "total" }, { "field": "motivo_rechazo" } ] } ], "fields": { "items": { "type": "table", "label": "Ítems", "minRows": 1, "maxRows": 50, "columns": { "concepto": { "type": "text", "label": "Concepto", "required": true }, "cantidad": { "type": "number", "label": "Cantidad", "required": true, "min": 1, "decimals": 0 }, "valor": { "type": "currency", "label": "Valor unitario", "currency": "COP", "required": true }, "subtotal": { "type": "currency", "label": "Subtotal", "currency": "COP", "calc": { "op": "mul", "args": [ { "ref": "fila.cantidad" }, { "ref": "fila.valor" } ] } } }, "columnOrder": ["concepto", "cantidad", "valor", "subtotal"] }, "total": { "type": "currency", "label": "Total", "currency": "COP", "calc": { "op": "sum", "table": "items", "column": "subtotal" } }, "motivo_rechazo": { "type": "textarea", "label": "Motivo del rechazo", "requiredWhen": { "var": "decision", "op": "eq", "value": "Rechazar" } } }}| Propiedad | Qué es |
|---|---|
schema | Siempre 2. |
title, description | Opcionales. |
inputs | Las entradas: clave → declaración (ver abajo). |
sections | Lista de secciones: id, title (opcional), description, columns (1 a 4), collapsible, visibleWhen e items ({ "field": "<clave>", "span": 1-4 }). |
fields | Los campos: clave → definición. La clave es ^[a-z][a-z0-9_]{0,59}$ y única en todo el formulario. |
Entradas
Sección titulada «Entradas»type (string, number, integer, boolean, date, datetime, object, array o file), required, label, description, sensitive, mask ("last4") y, en listas, items, minItems y maxItems.
type es uno de: text, textarea, number, currency, email, phone, select, multiselect, radio, checkbox, date, datetime, file, table, info y display. Cada tipo admite solo sus propiedades; una propiedad que el tipo no admite es un error.
| Grupo | Propiedades |
|---|---|
| Comunes | label, help, placeholder, required, requiredWhen, visibleWhen, readOnly, readOnlyWhen, calc, default (un valor o {{entradas.<clave>}}), sensitive, mask, messages (mensajes propios por validación, hasta 300 caracteres) |
| Texto | minLength, maxLength, pattern ({ "name": "cedula_co" | "nit_co" | "placa_co" | "solo_digitos" | "alfanumerico" } o { "custom": "<expresión regular>" }, que debe cubrir todo el valor), rows |
| Número, moneda y fecha | min, max (en fechas, "AAAA-MM-DD" o { "today": n }), minRef, maxRef, decimals (0 a 6), step, currency (COP, USD, EUR) |
| Selección | options (textos o { "value", "label" }), optionsFrom (una entrada de tipo lista), minItems, maxItems, requiredTrue (casilla) |
| Teléfono | defaultCountry |
| Archivo | accept (pdf, imagen, office, csv, texto), maxFiles, maxSizeMb |
| Tabla | columns (clave → definición de columna), columnOrder, minRows, maxRows |
| Presentación | text (en info), value y format (en display) |
Condiciones
Sección titulada «Condiciones»Las reglas (visibleWhen, requiredWhen, readOnlyWhen y el when de un cálculo) usan condiciones:
- Hoja:
{ "var": "<ruta>", "op": "<comparación>", "value": … }o, para comparar con otro campo,{ "var": "<ruta>", "op": "<comparación>", "ref": "<otra ruta>" }. - Grupos:
{ "all": [ … ] }(todas),{ "any": [ … ] }(basta una) y{ "not": … }(no se cumple). Hasta 4 niveles. - Comparaciones:
eq,neq,gt,gte,lt,lte,contains,in,exists,emptyytruthy. - Rutas:
campos.<clave>,entradas.<clave>,fila.<columna>(dentro de una tabla, solo columnas de la misma fila) ydecision(solo enrequiredWhen).
Un campo oculto cuenta como vacío. Una comparación entre tipos que no encajan no se cumple.
Cálculos
Sección titulada «Cálculos»| Expresión | Resultado |
|---|---|
{ "const": 100 }, { "ref": "campos.valor" } | Un valor fijo o el de otro campo. |
{ "op": "add" | "sub" | "mul" | "min" | "max", "args": [ … ] } | Suma, resta, multiplicación, mínimo o máximo (2 a 10 argumentos). |
{ "op": "div", "args": [a, b], "decimals": 2 } | División; entre 0, queda vacío. |
{ "op": "round", "arg": …, "decimals": 0 } | Redondeo (las mitades se alejan de cero). |
{ "op": "sum", "table": "items", "column": "subtotal" } | Suma de una columna (vacíos y ocultos cuentan 0). |
{ "op": "count", "table": "items" } | Cantidad de filas. |
{ "op": "if", "when": <condición>, "then": …, "else": … } | Uno u otro valor según una condición. |
{ "op": "concat", "args": [ … ] } | Une textos. |
{ "op": "days", "from": …, "to": … } | Días entre dos fechas. |
{ "op": "coalesce", "args": [ … ] } | El primer valor que no esté vacío. |
Las cuentas son decimales exactas. Un operando vacío deja vacío el resultado, salvo en sum, count, concat y coalesce. Un campo calculado siempre es de solo lectura y Zoan Cloud lo recalcula al recibir la respuesta.
Formato de los valores
Sección titulada «Formato de los valores»Moneda y números como número JSON; fecha "AAAA-MM-DD"; fecha y hora en ISO con zona horaria; teléfono en formato internacional (+573001234567); archivo como [{ "id": "…" }], que Zoan Cloud completa con bucket, name, content_type y size. La respuesta de una tarea tiene la forma { "decision", "comment", "fields" }.
fields siempre trae las mismas claves, así un robot o un paso del flujo las lee sin comprobar antes si existen:
- Cada campo del formulario aparece en
fields(salvo los de texto informativo y valor de solo lectura, que solo se muestran). - Cada fila de una tabla trae todas sus columnas, en el orden del formulario.
- Lo que no tiene valor llega como
null, sea cual sea el tipo: un campo opcional sin llenar, una celda vacía, un campo oculto por una regla o uno que no aplica a la decisión elegida. Una casilla visible llega comotrueofalse.
{ "decision": "Aprobar", "comment": "ok", "fields": { "nota": null, "productos": [ { "sku": "P-1", "rotacion_mensual": 12 }, { "sku": "P-2", "rotacion_mensual": null } ] } }En un formulario de inicio, un campo en null no se pasa al caso: la variable conserva su valor por defecto.
Límites
Sección titulada «Límites»| Qué | Tope |
|---|---|
| Definición | 128 KB; 150 campos (contando columnas); 30 secciones; 4 columnas por sección |
| Tablas | 10 por formulario; 20 columnas; 200 filas |
| Opciones | 200 por campo, de hasta 200 caracteres; opción única, hasta 8 |
| Reglas y cálculos | 400 comparaciones y 4 niveles; un cálculo, 60 nodos y 8 niveles |
| Texto | Hasta 10.000 caracteres (por defecto 500 en texto y 4.000 en área de texto); correo 254; comentario 4.000 |
| Entradas | 50; 64 KB por valor y 256 KB en total |
| Respuesta | 128 KB |
| Archivos | 10 por campo, hasta 25 MB cada uno; 30 archivos y 100 MB por tarea |
| Otros | Clave 60 caracteres; etiqueta 200; ayuda 1.000; texto informativo 5.000; patrón propio 200; fechas relativas ±3.650 días |
Las llamadas van con la sesión de una persona (Authorization: Bearer <token-de-sesion>) y bajo el ambiente: https://<tu-api>/environments/<ambiente>/…. El cuerpo admite hasta 600 KB.
Biblioteca
Sección titulada «Biblioteca»| Llamada | Permiso | Para qué |
|---|---|---|
GET /forms?status=active|archived|all&search=&limit=&offset= | form:list | Listar. |
POST /forms | form:manage | Crear: { "name", "description", "draft" }. |
GET /forms/:id | form:list | Leer, con su ETag. |
PUT /forms/:id/draft | form:manage | Guardar el borrador: { "draft", "revision" }, con la cabecera If-Match (sin ella, 428). |
PATCH /forms/:id | form:manage | Cambiar nombre o descripción. |
POST /forms/:id/publish | form:manage | Publicar: { "revision", "notes", "confirmIncompatible" }. |
POST /forms/:id/duplicate | form:manage | Duplicar. |
POST /forms/:id/archive, POST /forms/:id/unarchive | form:manage | Archivar y restaurar. |
GET /forms/:id/versions, GET /forms/:id/versions/:v | form:list | Versiones publicadas. |
GET /forms/:id/export?version= | form:list | Exportar a JSON (para importar en otro ambiente). |
GET /forms/:id/usage | form:list | Dónde se usa. |
GET /forms/catalog | form:list | Los formularios publicados, para elegirlos. |
POST /forms/validate | form:list (o diseñar flujos o asistentes) | Revisar una definición: errores, avisos, decisiones que usa, campos sensibles y la forma de la respuesta. |
POST /forms/check | igual que validate | «Probar envío»: { "definition", "decision", "comment", "inputs", "fields" }. Responde { ok, stage, outcome | errors, clock } sin crear nada. |
Para publicar un cambio incompatible, confirmIncompatible debe ser el número de la versión vigente; sin él, la respuesta es 409 FORM_INCOMPATIBLE con los cambios, los robots que lo usan y quién tiene fijada otra versión.
Tareas con formulario
Sección titulada «Tareas con formulario»- Crear:
POST /human-tasks(permisohuman_task:manage) conform_ref: { "name" | "id", "version" }yform_inputs, o con un formulario propio enform: { "schema": 2, … }yform_inputs. - Adjuntos de la respuesta:
POST /human-tasks/:id/uploads(multipart, confield) yDELETE /human-tasks/:id/uploads/:uploadId, con permiso para decidir la tarea.GET /human-tasks/:id/files/:fileId/urlda un enlace para abrir un archivo. - Responder:
POST /human-tasks/:id/complete, igual que siempre, con los campos enfields. Si la respuesta no pasa las reglas:422conFORM_INVALID, el mensaje «Revisa los campos marcados.» y un error por campo (field, yrowycolumnen una tabla). - Datos sensibles:
POST /human-tasks/:id/sensitive/revealdevuelve los valores en claro a quien puede verlos, y queda en la auditoría.
En la lista de tareas y en los avisos en vivo, las respuestas de formulario no traen los valores de los campos (fields_omitted: true): se leen en el detalle.
Errores
Sección titulada «Errores»| Código | Cuándo |
|---|---|
400 FORM_NOT_FOUND, FORM_ARCHIVED, FORM_VERSION_NOT_FOUND | El formulario o la versión pedida no existe o está archivado. |
403 PLAN_FEATURE_MISSING | Tu plan no incluye el diseño de formularios. |
403 SENSITIVE_FORBIDDEN | No puedes ver los datos sensibles de esa tarea. |
404 FORMS_DISABLED | Los formularios aún no están disponibles en tu Zoan Cloud. |
409 DRAFT_REVISION_CONFLICT | Otra persona guardó el borrador antes. |
409 NO_CHANGES | No hay cambios para publicar. |
409 FORM_INCOMPATIBLE | El cambio es incompatible y no se confirmó. |
413 DRAFT_TOO_LARGE, PAYLOAD_TOO_LARGE | El borrador o la petición superan el tamaño permitido. |
422 FORM_INVALID | La definición o la respuesta no son válidas; trae el detalle. |
429 max_forms | Se alcanzó el límite de formularios activos del plan. |
503 FORMS_TASKS_DISABLED | Las tareas con formulario aún no están disponibles en tu Zoan Cloud. |