REST API
본인인증 API
개요
이 API 들의 요청은 202 로 접수된 뒤 나중에 끝날 수 있습니다. 일부 인증서 경로는 200 으로 바로 끝나므로 어느 한쪽을 가정하지 말고 응답 코드로 분기하세요.
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 가 함께 필요합니다.{ "auth": "quick", "ownerName": "홍길동", "phoneNo": "01012345678", "birthday": "19900101" }
{ "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} 입니다.
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"}'
{ "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(시간 초과, 과금 없음)로 끝나므로 다시 제출하세요. 기관에 따라 승인을 두 번 요구하기도 합니다.
{ "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" }
{ "status": "done", "data": { "result": { "lists": [ { "...": "..." } ] } }, "meta": { "cached": false, "latency_ms": 41250, "credits_used": 60, "request_id": "req_abc123", "provider": "apitree-scraper" } }
{ "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 을 다시 폴링하면 이미 종료되었다는 문구로 응답합니다. 아래 두 응답은 모두 최종 상태이며 원래 요청을 다시 제출해야 합니다.
{ "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" }
{ "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 으로 폴링합니다.
const result = await apitree.call("{slug}", body, { method: "POST", pollTimeoutMs: 300_000, // the SDK polls for you after a 202 });
call_api -> status: "auth_pending" + job_id
poll_job -> call every 3-5 s until status is no longer "running"