개발자
Formalini API
문서와 추출된 필드를 조회하고, 자체 시스템에서 문서를 등록하며, 값을 수정하고, 변경 사항 발생 시 서명된 웹훅을 수신할 수 있습니다. 아래의 모든 예제는 curl, JavaScript, Python, PHP, C#으로 제공됩니다.
기본 URL
모든 엔드포인트는 이 기본 URL 아래에 위치합니다. JSON 형식으로 송수신합니다.
https://api.formalini.com/api/public/v1단축 주소인 api.formalini.com이 현재 운영 중이며, 위에 표시된 주소입니다.
인증
앱의 '연동(Integrations)' 메뉴에서 API 키를 생성한 후, 모든 요청에 Bearer 토큰으로 전송하세요. 키는 하나의 워크스페이스에 속하며 해당 워크스페이스의 데이터만 접근할 수 있습니다.
documents.read— 문서 및 필드 조회documents.write— 문서 생성 및 필드 수정workflows.run— 필요 시 웹훅으로 이벤트 전송
각 키에는 분당 요청 한도가 적용됩니다(기본값 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
페이지 이미지를 전송하면 동일한 응답에서 구조화된 데이터를 바로 반환합니다. 문서는 다른 스캔과 마찬가지로 워크벤치 받은편지함에 표시되며, 페이지당 AI 크레딧 1개가 차감되고 완료 시 웹훅을 트리거합니다.
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 형식을 지원하며 페이지당 최대 100MB입니다. 페이지 분석에는 몇 초가 걸리므로 넉넉한 타임아웃을 설정하거나 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로 설정하면 해당 웹훅도 트리거됩니다.
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 }웹훅 트리거
POST /workflows/dispatch — workflows.run
구독 중인 모든 활성 웹훅으로 이벤트를 전송하여 필요할 때 다른 시스템을 실행할 수 있습니다. 허용 이벤트: 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…" }웹훅
앱에서 웹훅 URL을 등록하고 수신할 이벤트를 선택하세요. 각 요청은 JSON 본문과 웹훅 시크릿으로 서명된 서명 헤더를 포함한 POST 방식으로 전송됩니다.
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": { … } }전송 실패 시 대기 시간을 늘려가며 최대 5회 재시도되며, 앱에서 언제든지 전송을 재실행할 수 있습니다.
요청을 신뢰하기 전에 원본 요청 본문(raw request body)을 기준으로 서명을 검증하세요.
// 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— 서버 측 오류가 발생했습니다. 응답 메시지를 확인하세요