FormRead Web API 集成开发人员指南
FormRead API 如何工作
FormRead API 分为两部分:用于管理表单(创建、更新、删除和存储数据)的 REST API,以及用于表单编辑和读取扫描文档的可嵌入 iframe。仅 API 本身不处理或读取表单——读取完全通过 iframe 完成。
- REST API(本页): 用于创建、更新、删除和检索表单元数据。API 存储您的表单数据,并返回嵌入 iframe 所需的令牌。
- iframe(嵌入式查看器): 用于编辑表单模板、上传扫描文档和提取结果(OMR、OCR、BCR)。所有表单读取和数据提取都在 iframe 内完成。
正在寻找服务器到服务器处理?
如果您不需要可视化界面,只想发送图像并以JSON格式获取结果,请查看服务器端处理API。
典型集成工作流程
- 使用 Bearer 令牌(从仪表板生成)进行身份验证。
- 使用
POST /api/forms端点创建表单并获取iframe_token。 - 使用
iframe_token将 iframe 嵌入到您的页面中,以便用户编辑表单和扫描文档。 - 监听 iframe 事件(
editForm、getResults、rowResult)以接收表单数据和提取结果,然后将它们存储到您的系统中。
身份验证
对于企业用途,通过生成 Bearer Auth token 即可使用 API。
登录 FormRead 仪表盘 并访问 API Token 选项:
创建 API 令牌,以允许第三方服务代表您与我们的应用程序进行身份验证:
将生成的令牌复制到安全的地方(它只会显示一次):
创建新表单
标题
| 名称 | 值 |
|---|---|
Authorization |
Bearer YOUR_API_TOKEN |
Accept |
application/json |
请求
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}"'
回答
{
"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"
}
变量 custom_css 将允许引入 CSS 规则来编辑 FormRead 的外观并添加自定义文本,例如:
#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;
}
按 ID 获取表单
请求
curl --location --request GET 'https://formread.org/api/forms/8' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_API_TOKEN'
回答
{
"id": 8,
"form_name": "adsf",
"iframe_token": "po75a0pqut4fa16XWgdEP2qRDwnhgfiqP3H0Dij6",
"created_at": "2022-02-28T21:22:55.000000Z",
"updated_at": "2022-03-01T01:40:19.000000Z"
}
编辑表单
在表单 创建 或 获取 之后,可以使用响应中提供的 iframe_token 在 Iframe 中显示它(此令牌会变化,因此请确保在渲染 iframe 之前 获取 您的表单)
还要创建一个脚本,像下面的示例一样监听 iframe 的事件:
<!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>
Iframe URL 参数
| 参数 | 描述 |
|---|---|
lang |
设置 lang 变量以显示所需语言的应用程序命令。目前,我们支持英语(en)、法语(fr)、西班牙语(es)、巴西葡萄牙语(pt)或印地语(hi)。 |
read_only |
变量 read_only 可以设置为 1 以禁用表单编辑,或 0 以允许表单编辑 |
Iframe 事件
当用户点击保存按钮时,将触发 <code class="language-plaintext">editForm</code> 方法,此时您可以访问 2 个变量:
formData变量将包含编码的表单属性,可以使用 更新 来保存对表单所做的更改:-
schema变量将让您了解到目前为止创建的字段:{ "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" } }schema变量仅用于在您要求创建必填区域字段时向用户显示一些警报:
当用户点击下载结果时,将触发 getResults 方法,您将获得 JSON 格式的结果数据,以便您可以将其存储到您的系统中
此外,您可以使用 rowResult 方法逐行获取结果,该方法将在每次处理页面时触发
更新表单
请求
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}"'
回答
{
"id": 8,
"form_name": "adsf",
"iframe_token": "po75a0pqut4fa16XWgdEP2qRDwnhgfiqP3H0Dij6",
"created_at": "2022-02-28T21:22:55.000000Z",
"updated_at": "2022-03-01T02:30:14.000000Z"
}
删除表单
请求
curl --location --request DELETE 'https://formread.org/api/forms/8' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer YOUR_API_TOKEN'
回答
1
完整示例:嵌入评分工作流
这是一个端到端示例,展示了教师如何设计表单、扫描试卷,并将批改结果推送到您自己的后端——所有这些都可以在嵌入 FormRead iframe 的单个页面中完成。
场景
教师打开您的应用,设计一张“数学101 - 期中考试”答题卡,打印出来,扫描已填写的试卷,然后点击“下载结果”。您的页面监听 iframe 事件,保存布局,并将批改后的答案发布到您的评分系统。
第1步 - 从您的服务器创建表单
在您的后端,为教师创建一个表单。您会得到一个 id 和一个 iframe_token - 这些是您将在下一步中传递给 iframe URL 的内容。
# 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"
}
将 id 和 iframe_token 保存到您自己数据库中教师的记录中。您将在第2步中使用它们来渲染可编辑的 iframe。
第2步 - 以可编辑模式打开 iframe
您的后端渲染一个包含 FormRead iframe 的页面,其中 read_only=0,这样教师可以在答题卡上绘制 OMR 气泡、OCR 区域和条形码。当他们在 iframe 内点击“保存”时,editForm 事件触发 - 浏览器将原始 formData 转发到您自己的后端。浏览器永远不会直接调用 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>
第3步 - 从您的后端持久化布局
您的后端接收 formData 字符串,并使用您的 Bearer 令牌(永远不会离开服务器)通过 PUT 将其转发给 FormRead。这样就能永久保存表单配置,以便以后重用同一表单来扫描试卷。
# 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"
}
iframe_token 会轮换
每次更新表单都会返回一个新的 iframe_token。始终在渲染 iframe 之前从您的后端获取最新的令牌 - 不要硬编码或长期缓存它。
第4步 - 获取当前的 iframe_token
之后,当教师准备扫描试卷时,您的后端通过 id 读取表单以获取最新的 iframe_token。
# 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"
}
第5步 - 以只读模式重新打开 iframe 进行扫描
再次渲染 iframe - 这次在 URL 末尾加上 read_only=1。教师无法再编辑布局,只能上传扫描件。浏览器将 rowResult(每张表的进度)和 getResults(最终下载)转发到您的后端。
<!-- /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>
第6步 - 在您的后端处理结果
getResults 事件会传递一个数组,每个已处理的考试对应一个条目。键遵循模式 {AreaType}-{AreaIndex}[-{QuestionIndex}]。以下是浏览器将发布到您的 /api/grades/bulk 端点(endpoint)的内容:
[
{
"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"
}
]
将您的令牌保存在服务器上
切勿在面向浏览器的代码中暴露您的 Bearer token。对 FormRead API 的所有创建/更新/读取调用都应通过您自己的后端进行——浏览器只会看到 iframe_token,该 token 仅限于单个表单。
常见问题解答
什么是 FormRead Iframe 集成 API?
它是一个 REST API 外加一个可嵌入的 iframe。您的后端通过 REST 端点管理表单;iframe 在您的 Web 应用内渲染,用户无需离开您的界面即可设计表单、上传扫描件和查看结果。
iframe_token 会过期或更改吗?
iframe_token 在表单每次更新时都会重新生成。在渲染 iframe 之前,务必从您的后端通过 FormRead REST API(GET /api/forms/{id})获取最新值——不要长期缓存它。
read_only=0 和 read_only=1 有什么区别?
read_only=0 以可编辑模式打开 iframe,以便用户设计表单(放置 OMR 气泡、OCR、条码区域)。read_only=1 仅以扫描模式打开——用户可以上传已填写的表格并下载结果,但不能更改布局。
我可以将 API token 保存在浏览器中吗?
不可以。Bearer token 必须保存在您的服务器上。对 FormRead REST API 的所有创建、更新和读取调用都应通过您自己的后端进行代理。浏览器只需要 iframe_token,该 token 仅限于单个表单。
如何接收扫描结果?
iframe 通过 window.postMessage 发布消息。监听 method="getResults" 以接收完整的结果数组(每张扫描表对应一个条目),并监听 method="rowResult" 以在扫描时显示每张表的进度。