Skip to main content

REST API

본인인증 API

기관의 데이터를 본인 명의로 조회하는 API 입니다. 대부분 비동기로 동작합니다. 요청을 제출하면 본인이 휴대폰에서 승인하고, 결과는 폴링으로 가져옵니다.

개요

이 API 들의 요청은 202 로 접수된 뒤 나중에 끝날 수 있습니다. 일부 인증서 경로는 200 으로 바로 끝나므로 어느 한쪽을 가정하지 말고 응답 코드로 분기하세요.

text호출 흐름
POST /api/v1/proxy/{slug}
  -> 202 accepted  (job_id, poll_url)
GET  /api/v1/jobs/{job_id}   repeat every retry_after_ms
  -> 200 running | 200 done | 422 failed | 410 expired | 504 timeout

입력

지원하는 auth 값은 API 마다 다릅니다. 카탈로그 Endpoints 탭의 auth enum 을 확인하세요. 누락된 입력은 접수 전에 400 INVALID_PARAMETER 로 실패하며 과금되지 않습니다. 주민등록번호와 인증서는 암호화해 저장하고 로그에서는 마스킹합니다.

필드
설명
auth"quick"(휴대폰 승인) 또는 "pki"(인증서). API 마다 받는 값이 다릅니다.
ownerNamequick. 필수. 본인 성명.
phoneNoquick. 필수. 휴대폰 번호, 숫자만(01012345678).
birthdayquick. YYYYMMDD. birthday 와 identity 중 하나는 필수.
identity주민등록번호 13자리, 하이픈 없음. birthday 를 대체합니다. 필수인 API 도 있습니다.
authProviderquick. API 가 받을 때만. 기본값 kakao.
certpki. certContent·keyContent 는 파일의 base64 내용이며 certPassword 가 함께 필요합니다.
jsonquick 본문
{
  "auth": "quick",
  "ownerName": "홍길동",
  "phoneNo": "01012345678",
  "birthday": "19900101"
}
jsonpki 본문
{
  "auth": "pki",
  "cert": {
    "certContent": "<base64 of the certificate file>",
    "keyContent": "<base64 of the private key file>",
    "certPassword": "<certificate password>"
  }
}

제출

X-Idempotency-Key 를 보내세요. 같은 키로 다시 제출하면 같은 job_id 가 재생되고 이중 차감되지 않습니다. poll_url 은 /api 기준 상대경로이므로 전체 URL 은 https://apitree.ai/api/v1/jobs/{job_id} 입니다.

bash제출
curl -X POST https://apitree.ai/api/v1/proxy/{slug} \
  -H "Authorization: Bearer nxs_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "X-Idempotency-Key: <unique-id>" \
  -d '{"auth":"quick","ownerName":"홍길동","phoneNo":"01012345678","birthday":"19900101"}'
202접수됨
{
  "job_id": "job_abc123",
  "status": "accepted",
  "poll_url": "/v1/jobs/job_abc123",
  "request_id": "req_abc123",
  "message": "Scraper job accepted. Poll poll_url for the result."
}

폴링

202 를 받은 뒤 3초를 기다리고, 이후에는 매 응답의 retry_after_ms(현재 3000) 만큼 기다립니다. expires_at 이후에는 폴링을 멈추세요. 같은 job 을 병렬로 폴링하지 마세요. 응답에 추가 필드가 붙을 수 있으니 모르는 키는 무시하세요.

본인 승인 대기 시간은 약 2분입니다. 늦게 승인하면 AT-2001(시간 초과, 과금 없음)로 끝나므로 다시 제출하세요. 기관에 따라 승인을 두 번 요구하기도 합니다.

200진행 중
{
  "job_id": "job_abc123",
  "status": "running",
  "request_id": "req_abc123",
  "poll_url": "/v1/jobs/job_abc123",
  "retry_after_ms": 3000,
  "expires_at": "2026-11-03T05:08:00.000Z"
}
200완료
{
  "status": "done",
  "data": { "result": { "lists": [ { "...": "..." } ] } },
  "meta": {
    "cached": false,
    "latency_ms": 41250,
    "credits_used": 60,
    "request_id": "req_abc123",
    "provider": "apitree-scraper"
  }
}
422실패
{
  "status": "failed",
  "error": "AT-2001",
  "http_status": 422,
  "message": "<customer message>",
  "recovery_action": "<what to do next>",
  "docs_url": "https://apitree.ai/docs/errors",
  "request_id": "req_abc123",
  "error_category": "network",
  "billable": false
}

상태별 다음 행동

응답
다음 행동
202접수됨. 3초 뒤 폴링하세요.
200 runningretry_after_ms 만큼 기다린 뒤 다시 폴링하세요.
200 donedata 를 사용하세요. 종료.
422 failedrecovery_action 을 따르세요. billable 이 true 면 같은 입력으로 재시도해도 과금됩니다.
410 JOB_EXPIRED중단하고 다시 제출하세요. 끝나지 않은 job 이면 환불됩니다. 끝난 job 의 결과 보관 시간(15분)이 지나 받은 410 이면 기존 과금이 유지됩니다.
504 JOB_TIMEOUT중단하고 다시 제출하세요.
404 JOB_NOT_FOUNDjob_id 를 확인하세요.
403 FORBIDDEN같은 조직의 키로 폴링하세요.
502 SCRAPER_UNREACHABLE / SCRAPER_MALFORMED폴링 단계. 일시 장애입니다. 계속 폴링하세요.
503 SCRAPER_UNAVAILABLE나중에 다시 시도하세요.
400 INVALID_PARAMETER / VARIANT_UNAVAILABLE제출 단계. 입력을 고치세요. 과금 없음.
402 INSUFFICIENT_CREDITS제출 단계. 크레딧을 충전하세요.
403 ORG_CONTEXT_REQUIRED제출 단계. 조직 키를 사용하세요.
502 SCRAPER_UNREACHABLE제출 단계. 예약된 크레딧은 환불됩니다. 다시 시도하세요.
502 JOB_CREATE_FAILED제출 단계. 예약된 크레딧은 환불됩니다. 다시 시도하세요.

과금

접수(202) 시점에 단가만큼 예약 차감합니다(잔액이 부족하면 402). done 으로 성공하면 과금이 확정되며 다시 폴링해도 한 번만 청구됩니다. billable 이 true 인 422 는 기관이 확정 답을 준 경우라 과금됩니다. 그 밖의 422 와 504 는 환불됩니다. 410 은 job 이 끝나기 전에 만료된 경우 환불됩니다. 끝난 job 의 결과 보관 시간(15분)이 지난 뒤 받은 410 은 결과가 이미 전달되어 과금된 건이므로 기존 과금이 유지됩니다.

제출 후 8분 안에 끝나지 않은 job 은 폴링 여부와 무관하게 정리 작업이 만료 처리하고 환불하며, 결과는 회수할 수 없습니다. 바로 폴링하고, done 이 되면 즉시 결과를 받으세요. 오류 코드를 참고하세요.

만료와 시간 초과

이미 끝난 job 을 다시 폴링하면 이미 종료되었다는 문구로 응답합니다. 아래 두 응답은 모두 최종 상태이며 원래 요청을 다시 제출해야 합니다.

410JOB_EXPIRED
{
  "error": "JOB_EXPIRED",
  "http_status": 410,
  "message": "Result expired (15min TTL). Resubmit the request.",
  "recovery_action": "The async job result is no longer available (expired, or already delivered on a prior poll). Re-submit the original request to get a fresh job_id.",
  "docs_url": "https://apitree.ai/docs/errors#job-expired",
  "request_id": "req_abc123"
}
504JOB_TIMEOUT
{
  "error": "JOB_TIMEOUT",
  "http_status": 504,
  "message": "Job did not finish within 8 minutes. Resubmit the request.",
  "recovery_action": "Stop polling this job_id and resubmit the original request to create a new job. If this recurs, the institution site may be slow or the worker degraded.",
  "docs_url": "https://apitree.ai/docs/errors#job-timeout",
  "request_id": "req_abc123"
}

SDK 와 MCP

TypeScript SDK 는 202 를 받으면 알아서 폴링합니다. 서버리스 함수에서는 waitForAuth: false 를 주고 나중에 waitForJob 을 호출하세요. MCP 에서는 call_api 가 auth_pending 과 job_id 를 돌려주며 poll_job 으로 폴링합니다.

tsSDK
const result = await apitree.call("{slug}", body, {
  method: "POST",
  pollTimeoutMs: 300_000, // the SDK polls for you after a 202
});
textMCP
call_api  -> status: "auth_pending" + job_id
poll_job  -> call every 3-5 s until status is no longer "running"
에피트리(apitree) · AI-Native API Marketplace