Skip to content

추출 실행

개요

추출 엔드포인트는 문서(base64 인코딩)를 받아 사용자가 정의한 템플릿을 통해 처리하고, 템플릿의 변수와 일치하는 구조화된 데이터를 반환합니다. 단일 API 호출로 업로드, AI 처리, 구조화된 출력까지 전체 파이프라인을 처리합니다.

모든 추출 요청은 POST /v1/extractions/run을 통해 이루어집니다.

문서 준비

문서를 API로 전송하기 전에 파일 내용을 base64로 인코딩해야 합니다.

제약 조건:

  • 최대 요청 본문 크기: 15 MB
  • 지원되는 MIME 타입:
    • application/pdf (PDF)
    • application/vnd.openxmlformats-officedocument.wordprocessingml.document (DOCX)
bash
# Base64-encode a PDF file
base64 -i invoice.pdf -o invoice_b64.txt

# Or inline (macOS / Linux)
PDF_BASE64=$(base64 -w 0 invoice.pdf)
typescript
import { readFileSync } from "fs";

const pdfBuffer = readFileSync("invoice.pdf");
const pdfBase64 = pdfBuffer.toString("base64");
python
import base64

with open("invoice.pdf", "rb") as f:
    pdf_base64 = base64.b64encode(f.read()).decode("utf-8")

WARNING

Base64 인코딩은 파일 크기를 약 33% 증가시킵니다. 10 MB PDF는 인코딩 후 약 13.3 MB가 되므로, 15 MB 요청 제한을 준수하려면 원본 파일을 ~11 MB 이하로 유지하세요.

요청 보내기

다음 JSON 본문으로 /v1/extractions/runPOST 요청을 전송합니다:

필드타입필수설명
templateIdstring추출에 사용할 템플릿의 ID
fileNamestring원본 파일명 (예: "invoice.pdf")
pdfBase64stringBase64 인코딩된 파일 내용
mimeTypestring파일의 MIME 타입
runIdstring아니오여러 추출을 배치로 그룹화하기 위한 선택적 식별자
bash
curl -X POST https://api.docmap.io/v1/extractions/run \
  -H "Authorization: Bearer dm_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "templateId": "tmpl_abc123",
    "fileName": "invoice.pdf",
    "pdfBase64": "JVBERi0xLjQKJeLj...",
    "mimeType": "application/pdf"
  }'
typescript
const response = await fetch("https://api.docmap.io/v1/extractions/run", {
  method: "POST",
  headers: {
    Authorization: "Bearer dm_live_your_api_key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    templateId: "tmpl_abc123",
    fileName: "invoice.pdf",
    pdfBase64: pdfBase64,
    mimeType: "application/pdf",
  }),
});

const { data } = await response.json();
console.log(data.extractedData);
python
import requests

response = requests.post(
    "https://api.docmap.io/v1/extractions/run",
    headers={
        "Authorization": "Bearer dm_live_your_api_key",
        "Content-Type": "application/json",
    },
    json={
        "templateId": "tmpl_abc123",
        "fileName": "invoice.pdf",
        "pdfBase64": pdf_base64,
        "mimeType": "application/pdf",
    },
)

data = response.json()["data"]
print(data["extractedData"])

응답 이해하기

성공적인 추출은 data 객체로 감싸진 응답을 반환합니다:

json
{
  "data": {
    "id": "ext_abc123def456",
    "userId": "user_789",
    "templateId": "tmpl_abc123",
    "templateName": "Invoice Parser",
    "fileName": "invoice.pdf",
    "status": "completed",
    "extractedData": {
      "vendor_name": "Acme Corp",
      "invoice_number": "INV-2024-001",
      "total_amount": 1250.00,
      "line_items": [
        { "description": "Widget A", "quantity": 10, "unit_price": 125.00 }
      ]
    },
    "error": null,
    "variables": [
      { "name": "vendor_name", "type": "string", "description": "Company name of the vendor" },
      { "name": "invoice_number", "type": "string", "description": "Invoice reference number" },
      { "name": "total_amount", "type": "number", "description": "Total invoice amount" },
      { "name": "line_items", "type": "array", "description": "List of line items" }
    ],
    "source": "api",
    "runId": null,
    "processingTimeMs": 3420,
    "createdAt": "2025-07-15T10:30:00.000Z"
  }
}
필드설명
id고유 추출 ID (ext_ 접두사)
status실행 중이면 (비동기 모드) "processing", 데이터가 성공적으로 추출되면 "completed", 처리 중 오류가 발생하면 "failed"
extractedData키가 템플릿의 변수 이름과 일치하는 객체. 추출 실패 시 null
error추출 실패 시 오류 메시지 문자열. 성공 시 null
processingTimeMsAI가 문서를 처리하는 데 걸린 시간(밀리초)
sourceAPI 키를 통해 트리거된 경우 "api", 웹 UI에서 트리거된 경우 "dashboard"
variables이 추출에 사용된 템플릿 변수 정의
runId제공한 배치 식별자, 또는 지정되지 않은 경우 null
templateName사용된 템플릿의 사람이 읽을 수 있는 이름
createdAt추출이 생성된 ISO 8601 타임스탬프

TIP

extractedData에 접근하기 전에 항상 status 필드를 확인하세요. status"failed"인 경우 error 필드에 무엇이 잘못되었는지에 대한 설명이 포함됩니다.

배치 추출

여러 파일을 논리적 배치로 처리하려면 각 추출 요청에 동일한 runId를 전달합니다. 이는 문서 처리 방식을 변경하지 않으며 -- 각 파일은 여전히 독립적으로 추출됩니다 -- 배치의 모든 결과를 함께 조회할 수 있습니다.

typescript
const runId = "batch-invoices-2025-07";
const files = ["invoice-001.pdf", "invoice-002.pdf", "invoice-003.pdf"];

// Process each file with the same runId
const results = await Promise.all(
  files.map(async (fileName) => {
    const pdfBase64 = readFileSync(fileName).toString("base64");

    const response = await fetch("https://api.docmap.io/v1/extractions/run", {
      method: "POST",
      headers: {
        Authorization: "Bearer dm_live_your_api_key",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        templateId: "tmpl_abc123",
        fileName,
        pdfBase64,
        mimeType: "application/pdf",
        runId,
      }),
    });

    return response.json();
  })
);

그런 다음 배치의 모든 추출을 조회합니다:

bash
curl "https://api.docmap.io/v1/extractions?runId=batch-invoices-2025-07" \
  -H "Authorization: Bearer dm_live_your_api_key"
typescript
const response = await fetch(
  "https://api.docmap.io/v1/extractions?runId=batch-invoices-2025-07",
  {
    headers: { Authorization: "Bearer dm_live_your_api_key" },
  }
);

const { data } = await response.json();
console.log(`Batch contains ${data.length} extractions`);
python
response = requests.get(
    "https://api.docmap.io/v1/extractions",
    params={"runId": "batch-invoices-2025-07"},
    headers={"Authorization": "Bearer dm_live_your_api_key"},
)

data = response.json()["data"]
print(f"Batch contains {len(data)} extractions")

TIP

목록 엔드포인트는 templateId 필터링과 limit 파라미터 (1--100, 기본값 50)도 지원합니다. 필터를 조합할 수 있습니다: ?runId=batch-001&templateId=tmpl_abc123&limit=100.

비동기 워크플로

기본적으로 추출 요청은 동기 방식입니다 -- API는 처리가 완료될 때까지 차단됩니다. 장시간 실행되는 추출이나 HTTP 타임아웃을 피하고 싶을 때는 URL에 ?async=true를 추가하여 비동기 모드를 사용하세요. API는 "processing" 상태로 즉시 반환하며, 결과가 준비될 때까지 별도의 엔드포인트를 폴링합니다.

제출 + 폴링 패턴

typescript
import { readFileSync } from "fs";

const API_BASE = "https://api.docmap.io";
const API_KEY = process.env.DOCMAP_API_KEY!;

// 1. Submit the extraction asynchronously
const submitResponse = await fetch(`${API_BASE}/v1/extractions/run?async=true`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    templateId: "tmpl_abc123",
    fileName: "invoice.pdf",
    pdfBase64: readFileSync("invoice.pdf").toString("base64"),
    mimeType: "application/pdf",
  }),
});

const { data: submitted } = await submitResponse.json();
console.log(`Extraction ${submitted.id} submitted, status: ${submitted.status}`);

// 2. Poll until complete
async function poll(extractionId: string): Promise<any> {
  for (let i = 0; i < 30; i++) {
    const res = await fetch(`${API_BASE}/v1/extractions/${extractionId}`, {
      headers: { Authorization: `Bearer ${API_KEY}` },
    });
    const { data } = await res.json();
    if (data.status !== "processing") return data;
    await new Promise((r) => setTimeout(r, 2000));
  }
  throw new Error("Extraction timed out");
}

const result = await poll(submitted.id);
console.log(`Final status: ${result.status}`);
console.log("Extracted data:", result.extractedData);
python
import base64
import time
import requests

API_BASE = "https://api.docmap.io"
API_KEY = "dm_live_your_api_key"
headers = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}

# 1. Submit the extraction asynchronously
with open("invoice.pdf", "rb") as f:
    pdf_base64 = base64.b64encode(f.read()).decode("utf-8")

submit_response = requests.post(
    f"{API_BASE}/v1/extractions/run?async=true",
    headers=headers,
    json={
        "templateId": "tmpl_abc123",
        "fileName": "invoice.pdf",
        "pdfBase64": pdf_base64,
        "mimeType": "application/pdf",
    },
)

submitted = submit_response.json()["data"]
print(f"Extraction {submitted['id']} submitted, status: {submitted['status']}")

# 2. Poll until complete
def poll(extraction_id: str):
    for _ in range(30):
        res = requests.get(
            f"{API_BASE}/v1/extractions/{extraction_id}",
            headers={"Authorization": f"Bearer {API_KEY}"},
        )
        data = res.json()["data"]
        if data["status"] != "processing":
            return data
        time.sleep(2)
    raise TimeoutError("Extraction timed out")

result = poll(submitted["id"])
print(f"Final status: {result['status']}")
print("Extracted data:", result["extractedData"])

비동기 모드를 사용해야 할 때

대용량 문서를 처리할 때, HTTP 클라이언트의 타임아웃이 짧을 때, 또는 여러 추출을 제출하고 나중에 결과를 수집하려는 경우 비동기 모드를 사용하세요. 대부분의 단일 문서 추출의 경우 동기 모드가 더 간단합니다.

전체 워크플로 예제

다음은 디스크에서 PDF를 읽고, 추출을 실행하고, 성공과 실패를 모두 처리하는 TypeScript의 전체 엔드투엔드 예제입니다:

typescript
import { readFileSync } from "fs";

const API_BASE = "https://api.docmap.io";
const API_KEY = process.env.DOCMAP_API_KEY!;

async function extractInvoice(filePath: string) {
  // 1. Read and encode the PDF
  const pdfBuffer = readFileSync(filePath);
  const pdfBase64 = pdfBuffer.toString("base64");
  const fileName = filePath.split("/").pop()!;

  console.log(`Processing ${fileName} (${(pdfBuffer.length / 1024).toFixed(0)} KB)...`);

  // 2. Run the extraction
  const response = await fetch(`${API_BASE}/v1/extractions/run`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      templateId: "tmpl_invoice_parser",
      fileName,
      pdfBase64,
      mimeType: "application/pdf",
    }),
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(`API error ${response.status}: ${error.error.message}`);
  }

  const { data } = await response.json();

  // 3. Check the extraction result
  if (data.status === "failed") {
    console.error(`Extraction failed: ${data.error}`);
    return null;
  }

  console.log(`Extraction completed in ${data.processingTimeMs}ms`);
  console.log("Extracted data:", JSON.stringify(data.extractedData, null, 2));

  return data.extractedData;
}

// Run it
extractInvoice("./invoices/invoice-001.pdf")
  .then((result) => {
    if (result) {
      console.log(`Vendor: ${result.vendor_name}`);
      console.log(`Total: $${result.total_amount}`);
    }
  })
  .catch(console.error);

DocMap API 문서