Ir al contenido

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.

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" } }
}
}
PropiedadQué es
schemaSiempre 2.
title, descriptionOpcionales.
inputsLas entradas: clave → declaración (ver abajo).
sectionsLista de secciones: id, title (opcional), description, columns (1 a 4), collapsible, visibleWhen e items ({ "field": "<clave>", "span": 1-4 }).
fieldsLos campos: clave → definición. La clave es ^[a-z][a-z0-9_]{0,59}$ y única en todo el formulario.

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.

GrupoPropiedades
Comuneslabel, 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)
TextominLength, 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 fechamin, max (en fechas, "AAAA-MM-DD" o { "today": n }), minRef, maxRef, decimals (0 a 6), step, currency (COP, USD, EUR)
Selecciónoptions (textos o { "value", "label" }), optionsFrom (una entrada de tipo lista), minItems, maxItems, requiredTrue (casilla)
TeléfonodefaultCountry
Archivoaccept (pdf, imagen, office, csv, texto), maxFiles, maxSizeMb
Tablacolumns (clave → definición de columna), columnOrder, minRows, maxRows
Presentacióntext (en info), value y format (en display)

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, empty y truthy.
  • Rutas: campos.<clave>, entradas.<clave>, fila.<columna> (dentro de una tabla, solo columnas de la misma fila) y decision (solo en requiredWhen).

Un campo oculto cuenta como vacío. Una comparación entre tipos que no encajan no se cumple.

ExpresiónResultado
{ "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.

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 como true o false.
{ "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.

QuéTope
Definición128 KB; 150 campos (contando columnas); 30 secciones; 4 columnas por sección
Tablas10 por formulario; 20 columnas; 200 filas
Opciones200 por campo, de hasta 200 caracteres; opción única, hasta 8
Reglas y cálculos400 comparaciones y 4 niveles; un cálculo, 60 nodos y 8 niveles
TextoHasta 10.000 caracteres (por defecto 500 en texto y 4.000 en área de texto); correo 254; comentario 4.000
Entradas50; 64 KB por valor y 256 KB en total
Respuesta128 KB
Archivos10 por campo, hasta 25 MB cada uno; 30 archivos y 100 MB por tarea
OtrosClave 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.

LlamadaPermisoPara qué
GET /forms?status=active|archived|all&search=&limit=&offset=form:listListar.
POST /formsform:manageCrear: { "name", "description", "draft" }.
GET /forms/:idform:listLeer, con su ETag.
PUT /forms/:id/draftform:manageGuardar el borrador: { "draft", "revision" }, con la cabecera If-Match (sin ella, 428).
PATCH /forms/:idform:manageCambiar nombre o descripción.
POST /forms/:id/publishform:managePublicar: { "revision", "notes", "confirmIncompatible" }.
POST /forms/:id/duplicateform:manageDuplicar.
POST /forms/:id/archive, POST /forms/:id/unarchiveform:manageArchivar y restaurar.
GET /forms/:id/versions, GET /forms/:id/versions/:vform:listVersiones publicadas.
GET /forms/:id/export?version=form:listExportar a JSON (para importar en otro ambiente).
GET /forms/:id/usageform:listDónde se usa.
GET /forms/catalogform:listLos formularios publicados, para elegirlos.
POST /forms/validateform: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/checkigual 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.

  • Crear: POST /human-tasks (permiso human_task:manage) con form_ref: { "name" | "id", "version" } y form_inputs, o con un formulario propio en form: { "schema": 2, … } y form_inputs.
  • Adjuntos de la respuesta: POST /human-tasks/:id/uploads (multipart, con field) y DELETE /human-tasks/:id/uploads/:uploadId, con permiso para decidir la tarea. GET /human-tasks/:id/files/:fileId/url da un enlace para abrir un archivo.
  • Responder: POST /human-tasks/:id/complete, igual que siempre, con los campos en fields. Si la respuesta no pasa las reglas: 422 con FORM_INVALID, el mensaje «Revisa los campos marcados.» y un error por campo (field, y row y column en una tabla).
  • Datos sensibles: POST /human-tasks/:id/sensitive/reveal devuelve 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.

CódigoCuándo
400 FORM_NOT_FOUND, FORM_ARCHIVED, FORM_VERSION_NOT_FOUNDEl formulario o la versión pedida no existe o está archivado.
403 PLAN_FEATURE_MISSINGTu plan no incluye el diseño de formularios.
403 SENSITIVE_FORBIDDENNo puedes ver los datos sensibles de esa tarea.
404 FORMS_DISABLEDLos formularios aún no están disponibles en tu Zoan Cloud.
409 DRAFT_REVISION_CONFLICTOtra persona guardó el borrador antes.
409 NO_CHANGESNo hay cambios para publicar.
409 FORM_INCOMPATIBLEEl cambio es incompatible y no se confirmó.
413 DRAFT_TOO_LARGE, PAYLOAD_TOO_LARGEEl borrador o la petición superan el tamaño permitido.
422 FORM_INVALIDLa definición o la respuesta no son válidas; trae el detalle.
429 max_formsSe alcanzó el límite de formularios activos del plan.
503 FORMS_TASKS_DISABLEDLas tareas con formulario aún no están disponibles en tu Zoan Cloud.