开发者
Formalini API
读取文档及其提取的字段、从您的自有系统推送文档、更正数值,并在内容发生变化时接收签名 Webhook。以下每个示例均提供 curl、JavaScript、Python、PHP 和 C# 版本。
Base URL
所有端点均位于此 Base URL 下。以 JSON 格式发送和接收数据。
https://api.formalini.com/api/public/v1短地址 api.formalini.com 已上线;即上方显示的地址。
身份验证
在应用的“集成”下创建 API 密钥,然后在每次请求中将其作为 Bearer Token 发送。密钥归属于单个工作区,且仅能访问该工作区的数据。
documents.read— 读取文档及其字段documents.write— 创建文档并更正字段workflows.run— 按需向您的 Webhook 发送事件
每个密钥都有每分钟请求数限制(默认 60 次)。响应头包含 X-RateLimit-Limit 和 X-RateLimit-Remaining;超出限制将返回附带 Retry-After 的 429 错误。
获取文档列表
GET /documents?limit=25&status=approved — documents.read
按最新优先排序。limit 接受 1–100(默认 25),status 可按 queued、processing、review、approved、exported 或 failed 过滤。
curl -X GET "https://api.formalini.com/api/public/v1/documents?limit=25&status=approved" \
-H "Authorization: Bearer pf_live_your_key"{
"documents": [
{
"id": "b0f1c8d2-5a71-4c0e-9f2a-1d4b6e8c3a90",
"name": "Job sheet 4821.jpg",
"status": "approved",
"average_confidence": 0.94,
"source": "upload",
"created_at": "2026-09-11T09:12:04.000Z",
"fields": [
{ "name": "engineer", "value": "M. Byrne", "type": "text",
"confidence": 0.97, "page": 1, "valid": true }
]
}
]
}更正后的值会替换原始识别结果,因此 value 始终是您应当使用的有效值。
获取单个文档
GET /documents/{id} — documents.read
返回包含类别、供应商、金额、日期以及每个字段的完整文档信息。
curl -X GET "https://api.formalini.com/api/public/v1/documents/b0f1c8d2-5a71-4c0e-9f2a-1d4b6e8c3a90" \
-H "Authorization: Bearer pf_live_your_key"上传文件并获取数据
POST /documents/upload — documents.write
发送单页图像,并在同一次响应中直接返回结构化数据。该文档会像普通扫描件一样出现在工作台收件箱中,每页消耗 1 点 AI 额度,并在处理完成后触发您的 Webhook。
file— 单页图像;对于多页文档,请为每页重复此字段(最多 25 页)name— 可选文档名称;留空时将使用文件名template_id— 可选模板 ID,以便字段以您的自定义名称返回async— 设置为 true 可立即获得 202 响应,并通过轮询 GET /documents/{id} 获取结果
curl -X POST "https://api.formalini.com/api/public/v1/documents/upload" \
-H "Authorization: Bearer pf_live_your_key" \
-F "file=@invoice-page-1.jpg" \
-F "file=@invoice-page-2.jpg" \
-F "name=Invoice 2026-0041"{
"document": {
"id": "8c2a1f76-4d33-4a1e-8f10-72b9e5c4a118",
"name": "Invoice 2026-0041",
"status": "review",
"average_confidence": 0.93,
"vendor": "Northbridge Supplies",
"amount": 1249.5,
"currency": "EUR",
"document_date": "2026-09-14",
"pages": 2,
"credits_spent": 2,
"fields": [
{ "name": "invoice_number", "value": "2026-0041", "type": "string",
"confidence": 0.98, "page": 1, "valid": true }
]
}
}支持 JPEG、PNG、WebP 和 HEIC 格式,每页最高 100 MB。单页识别需要数秒,请设置充足的超时时间或使用 async=true。402 错误表示工作区的额度、存储空间或每日配额已耗尽,响应中会指明具体原因。
此处暂不支持直接上传 PDF:请将每页渲染为 JPEG 或 PNG,并通过多个重复的 file 字段发送。应用内仍支持上传 PDF,因为页面会在您的浏览器中完成渲染。
创建文档
POST /documents — documents.write
推送您已有数据的文档。name 为必填项;fields 为选填项,最多包含 400 个条目。包含 fields 的文档将进入 review 状态,未包含的将进入 queue 状态。
curl -X POST "https://api.formalini.com/api/public/v1/documents" \
-H "Authorization: Bearer pf_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Invoice 2026-0041.pdf",
"category": "invoice",
"vendor": "Northbridge Supplies",
"amount": 1249.5,
"document_date": "2026-09-14",
"fields": [
{
"name": "invoice_number",
"value": "2026-0041",
"type": "text",
"confidence": 0.99,
"page": 1
},
{
"name": "total",
"value": "1249.50",
"type": "number",
"confidence": 0.96,
"page": 1
}
]
}'{
"document": {
"id": "8c2a…",
"name": "Invoice 2026-0041.pdf",
"status": "review",
"created_at": "2026-09-18T10:02:11.000Z",
"fields": 2
}
}更新文档
PATCH /documents/{id} — documents.write
更改状态或按名称更正字段值。将状态设为 approved、exported 或 review 还会触发相应的 Webhook。
curl -X PATCH "https://api.formalini.com/api/public/v1/documents/b0f1c8d2-5a71-4c0e-9f2a-1d4b6e8c3a90" \
-H "Authorization: Bearer pf_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"status": "approved",
"fields": [
{
"name": "total",
"value": "1249.50"
}
]
}'{ "ok": true, "updated_fields": 1 }触发 Webhook
POST /workflows/dispatch — workflows.run
向订阅了该事件的所有活跃 Webhook 发送事件,以便按需启动下游系统。支持的事件:document.processed、document.needs_review、document.approved、document.exported。
curl -X POST "https://api.formalini.com/api/public/v1/workflows/dispatch" \
-H "Authorization: Bearer pf_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"event": "document.approved",
"document_id": "b0f1c8d2-5a71-4c0e-9f2a-1d4b6e8c3a90",
"payload": {
"target": "erp"
}
}'{ "ok": true, "event": "document.approved", "document_id": "b0f1…" }Webhooks
在应用中添加 Webhook URL 并选择所需的事件。每次投递均为包含 JSON 请求体和签名标头的 POST 请求,使用您的 Webhook 密钥进行签名。
POST https://your-app.example.com/hooks/formalini
Content-Type: application/json
X-Paperflow-Signature: sha256=<hex hmac of the raw body>
{ "event": "document.processed", "document_id": "b0f1…", "payload": { … } }投递失败最多会自动重试五次(延迟递增),您也可以在应用中手动重放任何投递记录。
在信任投递内容之前,请对照原始请求体验证签名:
// Node.js
import crypto from "node:crypto";
function verify(rawBody, header, secret) {
const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
const got = (header || "").replace(/^sha256=/, "");
return got.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(got), Buffer.from(expected));
}
# Python
import hmac, hashlib
def verify(raw_body: bytes, header: str, secret: str) -> bool:
expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, (header or "").removeprefix("sha256="))
// PHP
$expected = hash_hmac('sha256', $rawBody, $secret);
$got = str_replace('sha256=', '', $_SERVER['HTTP_X_PAPERFLOW_SIGNATURE'] ?? '');
$ok = hash_equals($expected, $got);
// C#
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
var expected = Convert.ToHexString(hmac.ComputeHash(rawBodyBytes)).ToLowerInvariant();
var ok = CryptographicOperations.FixedTimeEquals(
Encoding.UTF8.GetBytes(expected),
Encoding.UTF8.GetBytes(header.Replace("sha256=", "")));错误码
400— 请求体不是合法的 JSON,或者缺少必填值/包含无效值401— 缺少密钥,或密钥已被撤销/已过期403— 密钥缺少此端点所需的权限404— 此工作区中不存在具有该 ID 的文档429— 已达每分钟请求上限——请稍后重试500— 服务端发生错误;响应中会提供具体信息