FormRead 웹 API 통합 개발자 가이드

Oscar Munoz Oscar Munoz · · 5분 읽기

FormRead API 작동 방식

FormRead API는 두 부분으로 나뉩니다. 양식 관리(생성, 업데이트, 삭제, 데이터 저장)를 위한 REST API와 양식 편집 및 스캔한 문서 읽기를 위한 삽입 가능한 iframe입니다. API 자체는 양식을 처리하거나 읽지 않으며, 읽기는 전적으로 iframe을 통해 처리됩니다.

  • REST API (이 페이지): 양식 메타데이터를 생성, 업데이트, 삭제 및 검색하는 데 사용합니다. API는 양식 데이터를 저장하고 iframe을 삽입하는 데 필요한 토큰을 반환합니다.
  • Iframe (삽입 뷰어): 양식 템플릿 편집, 스캔한 문서 업로드, 결과 추출(OMR, OCR, BCR)에 사용합니다. 모든 양식 읽기 및 데이터 추출은 iframe 내에서 이루어집니다.

서버 간 처리 찾고 계신가요?

시각적 인터페이스가 필요하지 않고 이미지를 보내고 결과를 JSON으로 받기만 원한다면, 서버 측 처리 API를 확인하세요.

일반적인 통합 워크플로

  1. 대시보드에서 생성한 Bearer 토큰으로 인증합니다.
  2. POST /api/forms 엔드포인트를 사용하여 양식을 생성하고 iframe_token을 받습니다.
  3. 페이지에 iframe을 삽입할 때 iframe_token을 사용하여 사용자가 양식을 편집하고 문서를 스캔할 수 있도록 합니다.
  4. iframe 이벤트(editForm, getResults, rowResult)를 수신하여 양식 데이터와 추출된 결과를 받은 후 시스템에 저장합니다.

인증

엔터프라이즈 사용의 경우 Bearer Auth 토큰을 생성하여 API를 사용할 수 있습니다.

FormRead 대시보드에 로그인하여 API 토큰 옵션에 접근하세요:

API 토큰 옵션이 강조 표시된 FormRead 대시보드 메뉴

타사 서비스가 귀하를 대신하여 저희 애플리케이션에 인증할 수 있도록 API 토큰을 생성하세요:

권한 체크박스로 새 FormRead API 토큰 생성

생성된 토큰을 안전한 곳에 복사하세요 (한 번만 표시됩니다):

생성된 FormRead API Bearer 토큰은 한 번만 표시됩니다 - 복사하여 안전하게 보관하세요

새 양식 만들기

POST /api/forms

헤더

이름 값
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로 양식 가져오기

GET /api/forms/{form_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"
}

양식 편집

양식이 생성되거나 GET으로 가져온 후 응답으로 제공된 iframe_token을 사용하여 Iframe에 표시할 수 있습니다 (이 토큰은 변동되므로 iframe을 렌더링하기 전에 반드시 GET으로 양식을 확인하세요)

아래 예제와 같이 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 메서드를 통해 행별 결과를 얻을 수 있습니다.

양식 업데이트

PUT /api/forms/{form_id}

요청

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"
}

양식 삭제

DELETE /api/forms/{form_id}

요청

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 열기

백엔드가 read_only=0으로 설정된 FormRead iframe을 포함하는 페이지를 렌더링하면, 교사는 시트에 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 다시 열기

이번에는 URL 끝에 read_only=1을 추가하여 iframe을 다시 렌더링합니다. 이제 교사는 레이아웃을 편집할 수 없고, 스캔만 업로드할 수 있습니다. 브라우저는 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 엔드포인트로 전송하는 예시입니다.

[
  {
    "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"
  }
]

토큰은 서버에 보관하세요

베어러 토큰을 브라우저용 코드에 절대 노출하지 마십시오. FormRead API에 대한 모든 생성/업데이트/읽기 호출은 자체 백엔드를 통해 이루어집니다. 브라우저는 단일 양식으로 범위가 지정된 iframe_token만 볼 수 있습니다.

자주 묻는 질문

FormRead Iframe Integration API란 무엇인가요?

REST API와 포함 가능한 iframe으로 구성됩니다. 백엔드에서는 REST 엔드포인트를 통해 양식을 관리하고, iframe은 웹 앱 내에서 렌더링되므로 사용자가 인터페이스를 떠나지 않고 양식을 디자인하고 스캔을 업로드하고 결과를 검토할 수 있습니다.

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 토큰을 브라우저에 보관할 수 있나요?

아니요. 베어러 토큰은 서버에 보관해야 합니다. FormRead REST API에 대한 모든 생성, 업데이트 및 읽기 호출은 자체 백엔드를 통해 프록시되어야 합니다. 브라우저에는 단일 양식으로 범위가 지정된 iframe_token만 필요합니다.

스캔된 결과를 어떻게 받나요?

iframe은 window.postMessage를 통해 메시지를 게시합니다. method="getResults"를 수신하면 전체 결과 배열(스캔된 시트당 하나의 항목)을 받고, method="rowResult"를 수신하면 스캔 중 시트별 진행 상황을 표시합니다.

Postman 컬렉션 링크

Postman 컬렉션 열기

손으로 폼을 채점하는 것을 멈추세요.

지금 바로 FormRead를 사용하세요. 양식을 만들고, 첫 번째 시트를 스캔하여 몇 분 안에 구조화된 결과를 얻으세요.

지금 시작하세요 — 신용카드 불필요