Guía para desarrolladores de integración de la API web de FormRead
Cómo funciona la API de FormRead
La API de FormRead se divide en dos partes: una API REST para gestionar formularios (crear, actualizar, eliminar y almacenar datos) y un iframe integrable para editar formularios y leer documentos escaneados. La API por sí sola no procesa ni lee formularios — la lectura se realiza completamente a través del iframe.
- API REST (esta página): Úsela para crear, actualizar, eliminar y obtener metadatos de formularios. La API almacena los datos de su formulario y devuelve los tokens necesarios para integrar el iframe.
- Iframe (visor integrado): Úselo para editar plantillas de formularios, cargar documentos escaneados y extraer resultados (OMR, OCR, BCR). Toda la lectura de formularios y extracción de datos ocurre dentro del iframe.
Si no necesitas una interfaz visual y solo quieres enviar imágenes y recibir resultados como JSON, consulta la API de procesamiento del lado del servidor.
- Autentíquese con un token Bearer (generado desde el panel de control).
- Use el endpoint
POST /api/formspara crear un formulario y obtener eliframe_token. - Integre el iframe en su página usando el
iframe_tokenpara permitir a los usuarios editar formularios y escanear documentos. - Escuche los eventos del iframe (
editForm,getResults,rowResult) para recibir los datos del formulario y los resultados extraídos, luego almacénelos en su sistema.
Autenticación
Para usos empresariales, la API se puede usar generando un token de autenticación "Bearer".
Inicie sesión en el panel de FormRead, y acceda a la opción API Token:
Cree los tokens de API para permitir que los servicios de terceros se autentiquen con nuestra aplicación en su nombre:
Copie el token generado en un lugar seguro (solo se mostrará una vez):
Crear nuevo formulario
Headers
| Name | Value |
|---|---|
Authorization |
Bearer YOUR_API_TOKEN |
Accept |
application/json |
Request
curl --location --request POST 'https://formread.org/api/forms' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_API_TOKEN' \
--form 'form_name="new form"' \
--form 'custom_css="{ingest custom css to edit FormRead View}"'
Response
{
"id": 8,
"form_name": "new form",
"iframe_token": "6ifvCyEcjB3D5SGqtFmJ5eg0sPYNQfLoWCEgv7bb",
"created_at": "2022-02-28T21:22:55.000000Z",
"updated_at": "2022-02-28T21:22:55.000000Z"
}
La variable custom_css permitirá ingresar reglas CSS para editar la apariencia de la vista FormRead y agregar texto personalizado, como por ejemplo:
#app-title::after{
content: 'Your Tittle';
color: white;
}
#app-subtitle::after{
content: 'Your Custom sub-tittle Your Custom sub-tittle Your Custom sub-tittle';
color: white;
}
#upload-from-cam{
display: none;
}
#upload-from-system{
background: lightblue;
}
#upload-from-csv{
display: none;
}
#app > div.bg-gray-50.h-screen.overflow-auto > div > div{
background-color: black;
}
Obtener formulario por ID
Request
curl --location --request GET 'https://formread.org/api/forms/8' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_API_TOKEN'
Response
{
"id": 8,
"form_name": "adsf",
"iframe_token": "po75a0pqut4fa16XWgdEP2qRDwnhgfiqP3H0Dij6",
"created_at": "2022-02-28T21:22:55.000000Z",
"updated_at": "2022-03-01T01:40:19.000000Z"
}
Editar un formulario
Después de que un formulario es Creado o traido (GET) se puede mostrar en un Iframe usando el iframe_token proporcionado en la respuesta (este token varía, así que asegúrese de Traer (GET) su formulario antes de renderizar el iframe)
Cree también un script que escuche los eventos del iframe como en el siguiente ejemplo:
<!DOCTYPE html>
<html style="height: 100%">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body style="height: 100%">
<iframe src="https://formread.org/{lang}/api/forms/{form_id}/edit/{iframe_token}/{read_only}"
style="height: 100%; width: 100%"></iframe>
<script>
window.addEventListener('message', function (e) {
// if (e.origin !== 'https://formread.org') return;
console.log(e.data.method)
if (e.data.method === "editForm") {
let formData = e.data.formData // data used to saved your form
let schema = JSON.parse(e.data.schema)
console.log(schema)
console.log(formData)
}
if (e.data.method === "getResults") {
let results = JSON.parse(e.data.results)
console.log(results)
}
if (e.data.method === "rowResult") {
let rowResult = JSON.parse(e.data.rowResult)
console.log(rowResult)
}
});
</script>
</body>
</html>
Parámetros de URL del iframe
| Parámetro | Descripción |
|---|---|
lang |
Configure la variable lang para mostrar los comandos de la aplicación en el idioma deseado. Actualmente, admitimos inglés (en), francés (fr), español (es), portugués brasileño (pt) o kazajo (kk) |
read_only |
Variable read_only se puede configurar en 1 para deshabilitar la edición de formularios o 0 para permitir la edición de formularios |
Eventos del iframe
Cuando los usuarios hacen clic en el botón Guardar, el <code class="language-plaintext">editForm</code> se activará el método, allí tiene acceso a 2 variables:
- La variable
formDatacontendrá los atributos de formulario codificados que se pueden enviar utilizando el Actualizarpara guardar los cambios realizados en su formulario: -
La variable
schemale permitirá conocer los campos creados hasta el momento:{ "file_name": { "type": "text" }, "BCR-0": { "type": "text" }, "OCR-1": { "type": "text" }, "OMR-2-0": { "type": "select", "options": ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], "questionIndex": "0" }, "OMR-2-1": { "type": "select", "options": ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], "questionIndex": "1" }, "OMR-2-2": { "type": "select", "options": ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], "questionIndex": "2" } }La variable
schemaestá destinada solo para que muestre, si asi lo desea, algunas alertas a sus usuarios en caso de que requiera que se creen campos de área obligatorios:
Cuando un usuario hace clic en los resultados de la descarga, el metodo getResults se activará, allí obtendrá los resultados en un formato JSON para que pueda almacenar luego en su sistema
Además, puede obtener los resultados fila por fila con el metodo rowResult, que se activará cada vez que se procese una página
Guardar Formulario
Request
curl --location --request POST 'https://formread.org/api/forms/8?_method=PUT' \
--header 'Authorization: Bearer YOUR_API_TOKEN' \
--form 'form_data="eyJ2dWV4X3N0YXRlIjp7ImZvcm1OYW1lIjoiYWRzZiIsImZvcm1zIjp7f
Swic2VsZWN0ZWRGb3JtSWQiOiIiLCJmb3JtUmVhZEFyZWFzIjp7IkJDUi
0wIjp7ImNvbHVtblBvc2l0aW9uIjoxLCJ3aWR0aCI6MC4xMTQ5NTA0NTM
0MDUzNTE2NCwiaGVpZ2h0IjowL...' \
--form 'custom_css="{ingest custom css to edit FormRead View}"'
Response
{
"id": 8,
"form_name": "adsf",
"iframe_token": "po75a0pqut4fa16XWgdEP2qRDwnhgfiqP3H0Dij6",
"created_at": "2022-02-28T21:22:55.000000Z",
"updated_at": "2022-03-01T02:30:14.000000Z"
}
Eliminar formulario
Request
curl --location --request DELETE 'https://formread.org/api/forms/8' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_API_TOKEN'
Response
1
Ejemplo completo: integrando el flujo de calificación
Este es un ejemplo de extremo a extremo que muestra cómo un profesor puede diseñar un formulario, escanear exámenes y enviar los resultados calificados a tu propio backend, todo desde una sola página que integra el iframe de FormRead.
Un profesor abre tu aplicación, diseña una hoja de respuestas "Matemáticas 101 - Examen parcial", la imprime, escanea los exámenes completados y hace clic en "Descargar resultados". Tu página escucha los eventos del iframe, guarda el diseño y publica las respuestas calificadas en tu sistema.
Paso 1 — Crear el formulario desde tu servidor
En tu backend, crea un formulario para el profesor. Recibirás un id y un iframe_token — son los valores que pasarás a la URL del iframe en el siguiente paso.
# From YOUR backend (never from the browser)
curl --location --request POST 'https://formread.org/api/forms' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_API_TOKEN' \
--form 'form_name="Math 101 - Midterm"'
{
"id": 42,
"form_name": "Math 101 - Midterm",
"iframe_token": "6ifvCyEcjB3D5SGqtFmJ5eg0sPYNQfLoWCEgv7bb",
"created_at": "2026-04-20T10:00:00.000000Z",
"updated_at": "2026-04-20T10:00:00.000000Z"
}
Guarda el id y el iframe_token asociados al registro del profesor en tu propia base de datos. Los usarás para mostrar el iframe editable en el paso 2.
Paso 2 — Abrir el iframe en modo edición
Tu backend muestra una página que contiene el iframe de FormRead con read_only=0, para que el profesor pueda dibujar burbujas OMR, áreas OCR y códigos de barras en la hoja. Cuando hace clic en "Guardar" dentro del iframe, se dispara el evento editForm — el navegador reenvía el formData en bruto a tu propio backend. El navegador nunca llama directamente a FormRead.
<!-- /design-form page rendered by YOUR backend.
read_only = 0 → editable mode -->
<iframe id="formread-frame"
src="https://formread.org/en/api/forms/42/edit/6ifvCyEcjB3D5SGqtFmJ5eg0sPYNQfLoWCEgv7bb/0"
style="width:100%; height:100vh; border:0"></iframe>
<script>
// The browser ONLY talks to your own backend. Never to FormRead.
const FORM_ID = 42;
window.addEventListener('message', async function (e) {
if (e.origin !== 'https://formread.org') return;
// Teacher clicked "Save" inside the iframe
if (e.data.method === 'editForm') {
await fetch(`/api/forms/${FORM_ID}/layout`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ form_data: e.data.formData })
});
}
});
</script>
Paso 3 — Persistir el diseño desde tu backend
Tu backend recibe la cadena formData y la reenvía a FormRead con un PUT usando tu token Bearer (que nunca sale del servidor). Esto es lo que guarda permanentemente la configuración del formulario para que el mismo pueda reutilizarse después para escanear los exámenes.
# Inside your backend handler for POST /api/forms/42/layout
# $formData is the raw string your browser posted.
curl --location --request POST 'https://formread.org/api/forms/42?_method=PUT' \
--header 'Authorization: Bearer YOUR_API_TOKEN' \
--form "form_data=${formData}"
{
"id": 42,
"form_name": "Math 101 - Midterm",
"iframe_token": "po75a0pqut4fa16XWgdEP2qRDwnhgfiqP3H0Dij6",
"created_at": "2026-04-20T10:00:00.000000Z",
"updated_at": "2026-04-20T10:15:42.000000Z"
}
Cada actualización de un formulario devuelve un nuevo iframe_token. Siempre obtén el más reciente desde tu backend justo antes de mostrar el iframe — no lo codifiques ni lo caches a largo plazo.
Paso 4 — Obtener el iframe_token actual
Más adelante, cuando el profesor esté listo para escanear los exámenes, tu backend consulta el formulario por id para obtener el iframe_token más reciente.
# From YOUR backend, right before rendering the scan page
curl --location --request GET 'https://formread.org/api/forms/42' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_API_TOKEN'
{
"id": 42,
"form_name": "Math 101 - Midterm",
"iframe_token": "po75a0pqut4fa16XWgdEP2qRDwnhgfiqP3H0Dij6",
"created_at": "2026-04-20T10:00:00.000000Z",
"updated_at": "2026-04-20T10:15:42.000000Z"
}
Paso 5 — Reabrir el iframe en modo solo lectura para escanear
Muestra el iframe nuevamente — esta vez con read_only=1 al final de la URL. El profesor ya no puede editar el diseño, solo cargar escaneos. El navegador reenvía rowResult (progreso por hoja) y getResults (descarga final) a tu backend.
<!-- /scan-exams page. Note read_only = 1 at the end of the URL. -->
<iframe id="formread-frame"
src="https://formread.org/en/api/forms/42/edit/po75a0pqut4fa16XWgdEP2qRDwnhgfiqP3H0Dij6/1"
style="width:100%; height:100vh; border:0"></iframe>
<script>
const FORM_ID = 42;
window.addEventListener('message', async function (e) {
if (e.origin !== 'https://formread.org') return;
// Live progress while each sheet is processed
if (e.data.method === 'rowResult') {
const row = JSON.parse(e.data.rowResult);
console.log('Processed', row.file_name);
}
// Teacher clicked "Download results"
if (e.data.method === 'getResults') {
const results = JSON.parse(e.data.results);
await fetch('/api/grades/bulk', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ form_id: FORM_ID, results })
});
}
});
</script>
Paso 6 — Manejar los resultados en tu backend
El evento getResults entrega un arreglo con una entrada por cada examen procesado. Las claves siguen el patrón {TipoÁrea}-{ÍndiceÁrea}[-{ÍndicePregunta}]. A continuación lo que el navegador enviaría a tu endpoint /api/grades/bulk:
[
{
"file_name": "student_001.jpg",
"BCR-0": "20260420-001",
"OCR-1": "Alice Johnson",
"OMR-2-0": "3",
"OMR-2-1": "7",
"OMR-2-2": "9"
},
{
"file_name": "student_002.jpg",
"BCR-0": "20260420-002",
"OCR-1": "Ben Carter",
"OMR-2-0": "3",
"OMR-2-1": "6",
"OMR-2-2": "9"
}
]
Nunca expongas tu token Bearer en código visible desde el navegador. Todas las llamadas de creación, actualización y lectura a la API de FormRead pasan por tu propio backend — el navegador solo ve el iframe_token, que está limitado a un único formulario.
Preguntas frecuentes
¿Qué es la API de integración por iframe de FormRead?
Es una API REST más un iframe integrable. Tu backend gestiona los formularios con los endpoints REST; el iframe se muestra dentro de tu aplicación web para que los usuarios puedan diseñar formularios, subir escaneos y revisar resultados sin salir de tu interfaz.
¿El iframe_token caduca o cambia?
El iframe_token se regenera cada vez que el formulario se actualiza. Obtén siempre el valor más reciente desde tu backend (GET /api/forms/{id}) justo antes de mostrar el iframe — no lo caches a largo plazo.
¿Cuál es la diferencia entre read_only=0 y read_only=1?
read_only=0 abre el iframe en modo edición para que el usuario diseñe el formulario (colocar burbujas OMR, áreas OCR y códigos de barras). read_only=1 lo abre solo en modo escaneo — el usuario puede subir hojas completadas y descargar resultados, pero no puede modificar el diseño.
¿Puedo tener mi token de API en el navegador?
No. El token Bearer debe permanecer en tu servidor. Todas las llamadas de creación, actualización y lectura a la API REST de FormRead deben pasar por tu propio backend. El navegador solo necesita el iframe_token, que está limitado a un único formulario.
¿Cómo recibo los resultados escaneados?
El iframe envía mensajes con window.postMessage. Escucha method="getResults" para recibir el arreglo completo de resultados (una entrada por hoja escaneada) y method="rowResult" para mostrar el progreso por hoja durante el escaneo.
Enlace de Postman
¿Listo para probar FormRead?
¡Cree, lea y procese formularios OMR con facilidad. Comience a extraer datos de sus formularios hoy mismo!
No se requiere tarjeta de crédito para comenzar