# headless — Full Reference > 외부 개발자·AI 에이전트가 headless Open API 를 통해 한국 금융기관의 입출금/세금계산서/현금영수증 > 데이터를 가져갈 때 참조하는 합본. `/llms.txt` 의 전체 풀어쓰기. ## 운영 인스트럭션 (LLM 에이전트용) - 외부 클라이언트가 호출하는 면은 둘뿐이다. - **콘솔 웹** (`https://h6s.ai/console`): 사용자가 브라우저로 접속. 가입·로그인·디바이스 승인은 모두 여기서. **에이전트는 사용자에게 이 URL 만 안내한다.** - **Open API** (`https://api.h6s.ai/api/v1`): 데이터 호출 + Device Flow 두 endpoint. API Key (`Authorization: Bearer h6s_live_...`) 인증. Device Flow 두 endpoint 만 인증 불필요. - 모든 시각은 ISO 8601 + offset (`2026-04-21T14:30:00+09:00`). 서버 내부 처리는 UTC. - 응답 페이로드는 sealed `ContractRecord`. JSON 본문 최상위 `schema` 필드가 discriminator. - 데이터 수집은 비동기. `POST /api/v1/data-jobs` (본문에 `credentialId` + `schema` + `params`) → 즉시 Job id 반환 → `GET /api/v1/data-jobs/{id}` 으로 status (`PENDING`/`RUNNING`/`COMPLETED`/`FAILED`) 폴링 → `GET /api/v1/data-jobs/{id}/results` 로 결과 페이지네이션. - 폴링·청킹 전략은 응답 본문이 자체적으로 알려준다. - `data-jobs` 응답의 `suggestedPollIntervalMs` 와 `maxWaitSeconds` 를 그대로 따른다 (기본 5000ms / 1800s). - 사용자가 요청한 기간이 스키마의 `maxRangeDays` 를 넘으면 클라이언트가 `chunkSizeDays` 단위로 분할해 수집 요청을 여러 개 생성한다. - HTTP 5xx / `retryable: true` 표시된 에러는 지수 백오프 (1s → 2s → 4s, 최대 3회). 그래도 실패면 사용자에게 보고. - API Key prefix `h6s_live_`. Device Flow 의 token 폴링 응답에서 평문이 1회만 노출되니 즉시 `Authorization: Bearer ...` 로 보관·사용한다. DB·로그 어디에도 평문이 남지 않는다. - 워크스페이스는 API Key 에서 자동 해석. Open API 호출 시 `workspaceId` 파라미터를 보내지 않는다. - `POST /api/v1/credentials` 의 `credentials` map 키는 **추측하지 말 것**. 항상 `GET /api/v1/providers/{code}/credential-schema` 로 받아온 `fieldKey` 를 그대로 사용. ## Authentication — Device Authorization Grant (RFC 8628) CLI / Claude Code 같은 native 클라이언트가 사용자에게 콘솔 가입·승인을 위임하고 그 자리에서 API key 평문을 직접 받는 OAuth 2.0 표준 플로우. 사용자는 콘솔 웹에서 가입·승인만 하면 되며 API key 발급 메뉴를 별도로 거치지 않는다. ```bash # Step 1: device + user code 발급 (인증 불필요) curl -X POST https://api.h6s.ai/api/v1/auth/device # 응답: # { # "deviceCode": "<랜덤 base64>", # 폴링용. 사용자에게 노출 금지 # "userCode": "HXPMZK74", # 8자 영문 대문자, 사용자가 콘솔 웹에서 입력/확인 # "verificationUri": "https://h6s.ai/console/activate", # "verificationUriComplete": "https://h6s.ai/console/activate?code=HXPMZK74", # "expiresInSeconds": 600, # "pollIntervalSeconds": 5 # } # Step 2: 사용자에게 verificationUriComplete 를 안내한다. 사용자는 콘솔 웹에서 가입(미가입 시) → 로그인 → 코드 승인. # Step 3: pollIntervalSeconds 간격으로 토큰 폴링 — 승인 시 신규 API key 평문이 응답으로 1회 내려온다. curl -X POST https://api.h6s.ai/api/v1/auth/device/token \ -H 'Content-Type: application/json' \ -d '{"deviceCode":""}' # 응답: # {"status":"pending"} → pollIntervalSeconds 후 재시도 # {"status":"approved","apiKey":"h6s_live_…","apiKeyId":"","workspaceId":""} → 즉시 Authorization 헤더로 사용 # HTTP 410 {"status":"expired"} → device_code 만료 또는 1회 소비됨. Step 1 부터 다시. # HTTP 403 {"status":"denied"} → 사용자가 명시적으로 거부. ``` `approved` 응답의 `apiKey` 는 사용자의 첫 번째 워크스페이스에 발급된 새 API key 다. 이름은 콘솔 웹의 API keys 메뉴에서 `Device Flow (USERCODE)` 형식으로 식별 가능. 평문은 **응답 1회만 노출**되므로 즉시 보관해 `Authorization: Bearer h6s_live_...` 로 사용한다. 서버는 hash 만 저장하고 평문은 어디에도 남기지 않는다. ## Open API Auth & Base URL ``` Base URL : https://api.h6s.ai/api/v1 Header : Authorization: Bearer h6s_live_... ``` ## Rate Limit - 분당 100 회, 시간당 5000 회 (per API Key). - 모든 응답 헤더에 `X-RateLimit-Limit-Minute`, `X-RateLimit-Limit-Hour`, `X-RateLimit-Remaining` 포함. - 초과 시 `HTTP 429 API_RATE_LIMITED` + `Retry-After` (초) 헤더. - 무료 플랜은 월간 수집 요청 수 / 스크래핑 단계 수 cap 적용 (`FREE_PLAN_JOB_CAP_REACHED`, `FREE_PLAN_TASK_CAP_REACHED`). `GET /api/v1/me/usage` 로 잔여량 확인. TIER_1X 이상은 무제한. ## 자격증명 폼 동적 생성 `POST /api/v1/credentials` 의 `credentials` map 의 키는 임의로 만들면 검증 실패한다. 항상 다음 절차로 가져온다. ```bash # 1. 가용 provider 카탈로그 curl https://api.h6s.ai/api/v1/providers \ -H 'Authorization: Bearer h6s_live_...' # 2. provider 별 자격증명 schema (auth_method 별 fieldKey/fieldType/required/validationPattern) curl https://api.h6s.ai/api/v1/providers/kb_bank/credential-schema \ -H 'Authorization: Bearer h6s_live_...' # 3. 응답의 fieldKey 를 그대로 credentials map 의 키로 사용. validationPattern 으로 클라이언트 측 사전 검증. ``` 스키마별로 어떤 action 이 가능한지는 `GET /api/v1/providers/{code}/actions` 와 `GET /api/v1/schemas/{schema}` 응답의 `requiresDateRange`/`maxRangeDays`/`chunkSizeDays`/`request[]`/`response[]` 가 담당. ## Quickstart — 인증부터 결과 수령까지 한 번에 은행 입출금내역(`bank.transactions.cb.v1`) 을 가져오는 풀 시나리오. Step 0~1 만 사용자 액션이고, 그 이후는 모두 Open API. ```bash # 0) 에이전트: device flow 시작 curl -X POST https://api.h6s.ai/api/v1/auth/device # → verificationUriComplete 를 사용자에게 표시: "이 URL 로 가서 가입 후 코드 승인하시면 됩니다" # 1) 에이전트: pollIntervalSeconds(5초) 간격 폴링 curl -X POST https://api.h6s.ai/api/v1/auth/device/token \ -H 'Content-Type: application/json' -d '{"deviceCode":"..."}' # → status=approved + apiKey 평문 도착. 이 평문을 그대로 다음 단계의 Authorization 헤더에 사용. # 2) Credential 등록 (credential schema 먼저 조회 후 fieldKey 채우기) curl -X POST https://api.h6s.ai/api/v1/credentials \ -H 'Authorization: Bearer h6s_live_...' \ -H 'Content-Type: application/json' \ -d '{ "providerCode":"kb_bank", "authMethod":"INTERNET_BANKING_ID_PASSWORD", "displayName":"내 KB 통장", "credentials":{"loginId":"...","loginPassword":"..."} }' # → { "id":"", "credentialHealth":"UNKNOWN" } # 자격증명 유효성은 다음 단계의 첫 데이터 수집 Job 실행 결과로 자동 확인된다. # 3) 수집 요청 생성 (예: 4월 한 달치 입출금) curl -X POST https://api.h6s.ai/api/v1/data-jobs \ -H 'Authorization: Bearer h6s_live_...' \ -H 'Content-Type: application/json' \ -d '{"credentialId":"", "schema":"bank.transactions.cb.v1", "params":{"accountNumber":"110-...","dateRangeStart":"2026-04-01","dateRangeEnd":"2026-04-30"}}' # → { "id":"", "status":"PENDING", "suggestedPollIntervalMs":5000, "maxWaitSeconds":1800 } # 기간이 maxRangeDays 초과면 chunkSizeDays 단위로 수집 요청을 여러 번 생성하라. # 4) 폴링 → COMPLETED 시 결과 페이지네이션 (totalCount/data[]) curl https://api.h6s.ai/api/v1/data-jobs/ -H 'Authorization: Bearer h6s_live_...' curl https://api.h6s.ai/api/v1/data-jobs//results -H 'Authorization: Bearer h6s_live_...' # → data[] 의 각 record 는 schema="bank.transactions.cb.v1" + 아래 "Contract Schemas" 표의 필드들. # Job 이 SUCCEEDED 면 credential.credentialHealth → VERIFIED. AUTH 카테고리(LOGIN_FAILED/CERT_INVALID 등) 실패 시 # 24h 슬라이딩 윈도우 내 연속 3회 누적되면 NEEDS_REVERIFICATION 으로 전이한다. ``` ## Quickstart (CLI) 위 raw HTTP 시나리오와 동등한 흐름을 공식 CLI(`@h6s-ai/cli`) 한 줄로 끝낼 수 있다. AI 에이전트가 호출할 때 권장. ```bash npm i -g @h6s-ai/cli # 0~1) 인증 — Device Flow 자동 처리. 사용자에게 verificationUriComplete 안내 후 승인 대기. h6s login # 2~4) 자격증명 매칭/생성, data-job 실행, 결과 회수까지 한 번에. h6s fetch bank.transactions.cb.v1 \ --provider kb_bank \ --month 2026-04 \ --output markdown \ --save ./out/ # 디스커버리 / 디버깅 h6s ai-guide --format markdown # CLI cheatsheet h6s providers list --output json h6s schemas list --output json h6s credentials find --provider kb_bank --first # 기존 자격증명 자동 매칭, 없으면 exit 4 h6s cache list # 24h 결과 캐시 ``` ## Endpoints 각 endpoint 는 `h6s ` 형태로 1:1 노출돼 있다. 자세한 매핑은 `h6s --help`. ### Action 스크래핑 액션 카탈로그 - `GET /api/v1/actions` — 액션 목록 - 현재 workspace 에 노출된 스크래핑 액션 ### Bug Reports AI 에이전트 버그 제보 - `POST /api/v1/bug-reports` — 버그 제보 - Open API 사용 중 발견한 버그를 운영자에게 전달한다. title, description 만 필수이며 endpoint/errorCode/requestId/agent/reproduction/context 는 있는 만큼만 채우면 된다. 인증된 워크스페이스/API 키 정보는 자동으로 첨부된다. ### Catalog Provider · authMethod · schema 통합 카탈로그. 기존 /providers, /providers/{code}/credential-schema, /providers/{code}/actions, /schemas 의 정보를 한 번에 반환. - `GET /api/v1/catalog` — 통합 카탈로그 - 한 번의 호출로 "어떤 자격증명으로 어떤 데이터를 어떤 파라미터로 받을 수 있는가" 를 반환. 다중 호출(/providers + /providers/{code}/credential-schema + /providers/{code}/actions) 를 대체한다. ### Certificate 공동인증서(GLOBAL) 입력 폼 메타데이터 - `GET /api/v1/cert-schema` — 공동인증서 입력 폼 조회 - 워크스페이스 GLOBAL 스코프 공동인증서 등록에 필요한 입력 폼 정의. 두 모드 중 한쪽을 골라 그 모드의 fields 만 채워 /credentials 로 보낸다 — `pfx` (PFX 한 파일 + 비밀번호), `split` (인증서 파일 + 개인키 파일 + 비밀번호). ### Credential 외부 금융기관 자격증명 (provider 인증) 관리 - `GET /api/v1/credentials` — 자격증명 목록 - 워크스페이스의 모든 자격증명 - `POST /api/v1/credentials` — 자격증명 생성 - providerCode + authMethod + 자격증명으로 자격증명 등록 - `DELETE /api/v1/credentials/{id}` — 자격증명 삭제 - soft delete - `GET /api/v1/credentials/{id}` — 자격증명 상세 - `PUT /api/v1/credentials/{id}` — 자격증명 수정 - displayName 또는 credentials 를 수정 ### DataJob 스크래핑 수집 요청 생성/조회 - `GET /api/v1/data-jobs` — 수집 요청 목록 - 커서 페이지네이션. status / actionCodes 로 필터. cursor 는 base64 인코딩 된 불투명 문자열로, 직전 응답의 nextCursor 를 그대로 다시 보내면 다음 페이지를 받는다. limit 은 1~100 사이 정수, 미지정 시 기본 20. - `POST /api/v1/data-jobs` — 수집 요청 생성 - providerCode + schema + params 로 스크래핑 실행을 시작. credential 은 워크스페이스에 등록된 것 중 백엔드 CredentialMatcher 가 해당 provider 에 매칭되는 것 (PROVIDER_BOUND 1순위 → 공동인증서 2순위) 을 자동 선택. 응답의 credentialId 로 실제 선택된 credential 확인 가능. - `GET /api/v1/data-jobs/count` — 수집 요청 개수 - 필터 조건에 맞는 총 수집 요청 개수 - `GET /api/v1/data-jobs/{id}` — 수집 요청 상세 - 수집 요청 진행 상태 + 부분 성공 가시성 (succeededRecordCount, failedTaskBreakdown, failedTasks, failureSummary) - `GET /api/v1/data-jobs/{id}/results` — 수집 요청 결과 - 완료된 수집 요청의 데이터. schema 필드에 따라 data 아이템의 ContractRecord variant 가 결정됨 - `GET /api/v1/data-jobs/{id}/results.csv` — 수집 요청 결과 (CSV) - 완료된 수집 요청의 데이터를 CSV (UTF-8 + BOM) 로 다운로드한다. 헤더는 `@ContractField.displayName` 한국어 라벨이며, Excel 한글 호환을 위해 BOM 이 포함된다. ### Device Flow RFC 8628 Device Authorization Grant — CLI/native 클라이언트 자율 진입 - `POST /api/v1/auth/device` — Device Flow 시작 - RFC 8628 device_authorization. 응답의 verificationUriComplete 를 사용자에게 안내하고 deviceCode 로 /api/v1/auth/device/token 을 폴링한다. - `POST /api/v1/auth/device/token` — Device Flow 토큰 폴링 - deviceCode 로 결과 확인. 사용자 미승인이면 status=pending. 승인되면 신규 API key 평문이 1회 노출되어 응답으로 내려온다 (DB 미저장). 권장 폴링 간격은 시작 응답의 pollIntervalSeconds. ### Provider 금융기관(Provider) 메타데이터 조회 - `GET /api/v1/providers` — Provider 목록 - displayGroup 으로 필터 가능 - `GET /api/v1/providers/{providerCode}` — Provider 상세 (통합) - Provider 기본정보 + credential authMethods + 지원 schema 목록을 한 번에 - `GET /api/v1/providers/{providerCode}/actions` — Provider 지원 액션 목록 - Provider 별 수집 가능한 Action + 제약 - `GET /api/v1/providers/{providerCode}/coverage` — Provider coverage - 현재 워크스페이스에서 이 provider 의 데이터 수집 준비 상태 - `GET /api/v1/providers/{providerCode}/credential-schema` — Provider 자격증명 입력 폼 조회 - Provider 가 지원하는 authMethod 별 자격증명 필드 (동적 폼 생성용). Provider 가 GLOBAL 공동인증서 로그인을 받으면 응답의 `globalAlternative` 에 CERT 입력 폼을 함께 노출한다. ### Schema 수집 가능한 데이터 형식 카탈로그 - `GET /api/v1/schemas` — 데이터 형식 목록 조회 - 현재 workspace 에 노출된 데이터 형식의 요약 목록 - `GET /api/v1/schemas/{schema}` — 데이터 형식 상세 조회 - schema 로 입력 항목 / 반환 항목 계약 전체를 반환 ### Usage 워크스페이스 동시 처리 사용량 + 한도 (SDUI) - `GET /api/v1/me/usage` — 워크스페이스 사용량 조회 (SDUI) - 현재 plan 의 동시 처리 한도와 사용량, 메트릭 카드 리스트(카드별 CTA 포함)를 서버 판정으로 내려준다. FE 는 metrics 배열을 그대로 렌더하므로 plan 추가 / cap 차원 추가 / 카피 변경 시 FE 변경 불필요. - `GET /api/v1/me/usage/daily` — 내 워크스페이스 일별 사용량 추세 조회 (Open API) - API Key 의 워크스페이스를 대상으로 최근 N 일 (기본 30, 최대 90) 의 일별 수집 요청 / 스크래핑 단계 수와 플랜 월간 한도를 반환한다. 빈 날짜는 0 으로 채운다. ## Contract Schemas (응답 페이로드 필드) `POST /api/v1/data-jobs` 본문에 넘기는 `schema` 값이 응답 레코드의 `schema` 가 된다. `GET /api/v1/data-jobs/{id}/results` 응답의 각 record 는 아래 필드를 가진다. ### bank.accounts.cb.v1 — 계좌 목록 연결된 뱅킹 프로바이더의 모든 계좌 목록 | 필드 | 타입 | 필수 | 설명 | |------|------|------|------| | `accountNumber` | string | Y | 하이픈/공백 없는 연속 숫자 | | `accountType` | enum(CHECKING,INSTALLMENT_SAVINGS,TRUST,FUND,FOREIGN,LOAN,INSURANCE,PENSION) | Y | 계좌 성격 구분 (요구불/펀드/대출 등) | | `currencyCode` | string | Y | ISO 4217 3자 (KRW, USD, ...) | | `displayName` | string | - | 사용자가 인터넷뱅킹에 지정한 애칭. 없으면 null | | `accountNumberFormatted` | string | - | 금융기관이 UI 에 보여주는 하이픈 포함 포맷 (예: `140-014-167889`). 평생계좌 등 부가 정보가 괄호로 이어질 수 있다 | | `productName` | string | - | 금융기관 상품명 (예: KB Star 정기예금) | | `balance` | number | - | 해당 계좌의 통화 기준 현재 잔액 | | `availableBalance` | number | - | 즉시 이체·출금 가능한 가용 잔액 | ### bank.transactions.cb.v1 — 입출금내역 연결된 뱅킹 프로바이더의 모든 계좌 입출금내역 - 기간 파라미터 `dateRangeStart`/`dateRangeEnd` 필수 (최대 365 일, 내부 90 일 단위 청킹) | 필드 | 타입 | 필수 | 설명 | |------|------|------|------| | `transactionAt` | datetime | Y | ISO 8601 with offset (예: 2026-04-21T14:30:00+09:00) | | `accountNumber` | string | Y | 하이픈/공백 없는 연속 숫자 | | `accountNumberFormatted` | string | - | 금융기관이 UI 에 보여주는 하이픈 포함 포맷 (예: `140-014-167889`). 계좌 목록 조회 시점에 확인된 값을 그대로 사용하며, 금융기관 미제공이면 null | | `accountType` | enum(CHECKING,INSTALLMENT_SAVINGS,TRUST,FUND,FOREIGN,LOAN,INSURANCE,PENSION) | Y | 입출금내역 지원 유형 (CHECKING / FOREIGN / FUND / LOAN) | | `currencyCode` | string | Y | ISO 4217 3자 (KRW, USD, ...). FUND/LOAN 은 KRW 고정 | | `amount` | number | Y | 해당 계좌 잔고 증감 기준 부호값. 입금/매수 +, 출금/매도/상환 - | | `description` | string | - | 거래 설명 (이체 상대방/가맹점명/상품명 등 은행이 제공). 비어있으면 null | | `balance` | number | - | 거래 직후 잔액. 일부 유형/기관은 미제공으로 null 가능 | ### hometax.tax-invoices.sales.v1 — 매출 전자(세금)계산서 매출 세금계산서 + 매출 계산서 통합 목록 - 기간 파라미터 `dateRangeStart`/`dateRangeEnd` 필수 (최대 90 일, 내부 90 일 단위 청킹) | 필드 | 타입 | 필수 | 설명 | |------|------|------|------| | `writeDate` | date | Y | 세금계산서 작성일 (YYYY-MM-DD) | | `issueDate` | date | Y | 세금계산서 발행 완료일 (YYYY-MM-DD) | | `supplierBusinessIdentifier` | string | Y | 하이픈 없는 10자리 숫자 | | `supplyAmount` | number | Y | 부가세 제외 공급가액 (원 단위) | | `taxAmount` | number | Y | 부가가치세액. 면세/계산서는 0 | | `totalAmount` | number | Y | 공급가액 + 세액 (원 단위) | | `sendDate` | date | - | 국세청 서버 전송 완료일 (YYYY-MM-DD) | | `ntsTransactionId` | string | - | 국세청 발급 고유 승인번호 (24자리). 종이 세금계산서 등 미승인 건은 null | | `supplierSubBusinessNumber` | string | - | 종사업장 식별번호 (해당 없으면 null) | | `supplierOrganizationName` | string | - | 공급자 사업자 등록상 상호명 | | `supplierRepresentativeName` | string | - | 공급자 사업자 등록상 대표자명 | | `supplierAddress` | string | - | 공급자 사업장 주소 | | `supplierEmail` | string | - | 공급자 이메일 주소 | | `buyerBusinessIdentifier` | string | - | 하이픈 없는 10자리 숫자. 미등록/영수증 발행 등은 null | | `buyerSubBusinessNumber` | string | - | 공급받는자 종사업장 식별번호 (해당 없으면 null) | | `buyerOrganizationName` | string | - | 공급받는자 사업자 등록상 상호명 | | `buyerRepresentativeName` | string | - | 공급받는자 사업자 등록상 대표자명 | | `buyerAddress` | string | - | 공급받는자 사업장 주소 | | `buyerEmail` | string | - | 공급받는자 주 이메일 | | `buyerEmailSecondary` | string | - | 공급받는자 보조 이메일 | | `trusteeBusinessIdentifier` | string | - | 수탁 발행인 경우만 값 존재 | | `trusteeOrganizationName` | string | - | 수탁사업장 상호 (수탁 발행인 경우만 값 존재) | | `invoiceClassification` | string | - | 세금계산서 / 수정세금계산서 등 | | `invoiceKind` | string | - | 일반 / 일반(수정) 등 | | `issueChannel` | string | - | 인터넷발급 / ASP발급 / ARS발급 / VAN발급 등 | | `paymentType` | string | - | 결제 방식. `영수` (이미 수령) / `청구` (외상) 구분 | | `remark` | string | - | 세금계산서 비고란 | | `itemSupplyDate` | date | - | 대표 품목의 공급일 (YYYY-MM-DD) | | `itemName` | string | - | 대표 품목명. 다품목 명세는 별도 상세 조회 필요 | | `itemSpecification` | string | - | 대표 품목의 규격 | | `itemQuantity` | number | - | 대표 품목 수량 | | `itemUnitPrice` | number | - | 대표 품목 단가 | | `itemSupplyAmount` | number | - | 대표 품목의 부가세 제외 공급가액 | | `itemTaxAmount` | number | - | 대표 품목의 부가가치세액 | | `itemRemark` | string | - | 대표 품목의 비고 | ### hometax.tax-invoices.purchase.v1 — 매입 전자(세금)계산서 매입 세금계산서 + 매입 계산서 통합 목록 - 기간 파라미터 `dateRangeStart`/`dateRangeEnd` 필수 (최대 90 일, 내부 90 일 단위 청킹) | 필드 | 타입 | 필수 | 설명 | |------|------|------|------| | `writeDate` | date | Y | 세금계산서 작성일 (YYYY-MM-DD) | | `issueDate` | date | Y | 세금계산서 발행 완료일 (YYYY-MM-DD) | | `buyerBusinessIdentifier` | string | Y | 하이픈 없는 10자리 숫자 | | `supplyAmount` | number | Y | 부가세 제외 공급가액 (원 단위) | | `taxAmount` | number | Y | 부가가치세액. 면세/계산서는 0 | | `totalAmount` | number | Y | 공급가액 + 세액 (원 단위) | | `sendDate` | date | - | 국세청 서버 전송 완료일 (YYYY-MM-DD) | | `ntsTransactionId` | string | - | 국세청 발급 고유 승인번호 (24자리). 종이 세금계산서 등 미승인 건은 null | | `supplierBusinessIdentifier` | string | - | 하이픈 없는 10자리 숫자. 미등록 공급자는 null | | `supplierSubBusinessNumber` | string | - | 종사업장 식별번호 (해당 없으면 null) | | `supplierOrganizationName` | string | - | 공급자 사업자 등록상 상호명 | | `supplierRepresentativeName` | string | - | 공급자 사업자 등록상 대표자명 | | `supplierAddress` | string | - | 공급자 사업장 주소 | | `supplierEmail` | string | - | 공급자 이메일 주소 | | `buyerSubBusinessNumber` | string | - | 공급받는자 종사업장 식별번호 (해당 없으면 null) | | `buyerOrganizationName` | string | - | 공급받는자 사업자 등록상 상호명 | | `buyerRepresentativeName` | string | - | 공급받는자 사업자 등록상 대표자명 | | `buyerAddress` | string | - | 공급받는자 사업장 주소 | | `buyerEmail` | string | - | 공급받는자 주 이메일 | | `buyerEmailSecondary` | string | - | 공급받는자 보조 이메일 | | `trusteeBusinessIdentifier` | string | - | 수탁 발행인 경우만 값 존재 | | `trusteeOrganizationName` | string | - | 수탁사업장 상호 (수탁 발행인 경우만 값 존재) | | `invoiceClassification` | string | - | 세금계산서 / 수정세금계산서 등 | | `invoiceKind` | string | - | 일반 / 일반(수정) 등 | | `issueChannel` | string | - | 인터넷발급 / ASP발급 / ARS발급 / VAN발급 등 | | `paymentType` | string | - | 결제 방식. `영수` (이미 수령) / `청구` (외상) 구분 | | `remark` | string | - | 세금계산서 비고란 | | `itemSupplyDate` | date | - | 대표 품목의 공급일 (YYYY-MM-DD) | | `itemName` | string | - | 대표 품목명. 다품목 명세는 별도 상세 조회 필요 | | `itemSpecification` | string | - | 대표 품목의 규격 | | `itemQuantity` | number | - | 대표 품목 수량 | | `itemUnitPrice` | number | - | 대표 품목 단가 | | `itemSupplyAmount` | number | - | 대표 품목의 부가세 제외 공급가액 | | `itemTaxAmount` | number | - | 대표 품목의 부가가치세액 | | `itemRemark` | string | - | 대표 품목의 비고 | ### hometax.cash-receipts.sales.v1 — 매출 현금영수증 매출 현금영수증 목록 - 기간 파라미터 `dateRangeStart`/`dateRangeEnd` 필수 (최대 90 일, 내부 90 일 단위 청킹) | 필드 | 타입 | 필수 | 설명 | |------|------|------|------| | `transactionAt` | datetime | Y | 매출 발생 시각. ISO 8601 with offset (예: 2026-04-21T14:30:00+09:00) | | `approvalNumber` | string | Y | 현금영수증 승인번호 | | `supplyAmount` | number | Y | 부가세 제외 공급가액 (원 단위) | | `taxAmount` | number | Y | 부가가치세액. 면세는 0 | | `totalAmount` | number | Y | 공급가액 + 세액 + 봉사료 (원 단위) | | `issueType` | string | - | 홈택스 발행구분 코드 (현금영수증 유형 분류) | | `issueMethod` | string | - | 홈택스 내부 발급수단 코드 (예: 6600 = 현금영수증 카드) | | `transactionType` | string | - | 승인거래 / 취소거래 | | `useType` | string | - | 소득공제 / 지출증빙 등 용도 분류 | | `tip` | number | - | 결제에 포함된 봉사료 | | `remark` | string | - | 홈택스 거래유형명 (비고란에 표시) — 예: `현금(소득공제)` | ### hometax.cash-receipts.purchase.v1 — 매입 현금영수증 매입 현금영수증 목록 - 기간 파라미터 `dateRangeStart`/`dateRangeEnd` 필수 (최대 90 일, 내부 90 일 단위 청킹) | 필드 | 타입 | 필수 | 설명 | |------|------|------|------| | `transactionAt` | datetime | Y | 매입 발생 시각. ISO 8601 with offset (예: 2026-04-21T14:30:00+09:00) | | `approvalNumber` | string | Y | 현금영수증 승인번호 | | `supplyAmount` | number | Y | 부가세 제외 공급가액 (원 단위) | | `taxAmount` | number | Y | 부가가치세액. 면세는 0 | | `totalAmount` | number | Y | 공급가액 + 세액 + 봉사료 (원 단위) | | `merchantBusinessIdentifier` | string | - | 가맹점의 사업자등록번호 (하이픈 없는 10자리) | | `organizationName` | string | - | 결제가 이루어진 가맹점명 | | `issueMethod` | string | - | 홈택스 내부 발급수단 코드 (예: 6600 = 현금영수증 카드) | | `transactionType` | string | - | 승인거래 / 취소거래 | | `tip` | number | - | 결제에 포함된 봉사료 | | `issueTypeCode` | string | - | 홈택스 발행구분 분류 코드 (예: 01/02) | | `issueTypeName` | string | - | 홈택스 발행구분 분류의 한국어 표시명 | | `deductible` | string | - | 공제 / 불공제 | | `merchantClassification` | string | - | 간이사업자 / 법인사업자 등 | | `businessTypeCode` | string | - | 한국표준산업분류 기반 업종 코드 | | `businessTypeName` | string | - | 업종명 (한국표준산업분류 표시명) | | `deductionClassificationCode` | string | - | 공제/불공제 상세 분류 코드 | | `deductionClassificationName` | string | - | 공제/불공제 상세 분류 표시명 | | `roadAddress` | string | - | 가맹점 소재지 도로명 주소 | | `lotAddress` | string | - | 가맹점 소재지 법정동 주소 | | `contactNumber` | string | - | 가맹점 연락처 | ### card.cards.corp.v1 — 법인카드 보유카드 자격증명 단위 카드 목록 스냅샷 | 필드 | 타입 | 필수 | 설명 | |------|------|------|------| | `cardNumberMasked` | string | Y | 발급사 마스킹 표기 그대로. 발급사가 마스킹하지 않고 풀 PAN 을 내려주는 경우 headless 가 앞 6 + 뒤 4 만 노출하도록 마스킹 | | `cardName` | string | Y | 발급사 상품명 (예: KB국민 스타카드) | ### card.approvals.corp.v1 — 법인카드 승인내역 카드 단말 승인 시점 거래 (실시간 지출 모니터링) - 기간 파라미터 `dateRangeStart`/`dateRangeEnd` 필수 (최대 365 일, 내부 90 일 단위 청킹) | 필드 | 타입 | 필수 | 설명 | |------|------|------|------| | `approvedAt` | datetime | Y | ISO 8601 with offset (예: 2026-04-21T14:30:00+09:00) | | `approvalNumber` | string | Y | 카드 승인번호 | | `cardNumberMasked` | string | Y | 발급사 마스킹 표기 그대로. 풀 PAN 발급사는 headless 가 앞 6 + 뒤 4 만 노출 | | `merchantName` | string | Y | 거래 가맹점 상호 | | `settledAmount` | number | Y | 카드 청구·정산 기준 금액. 항상 양수. 취소건도 양수이며 성격은 `status` 로 구분 (해외건 소수 가능) | | `settledCurrencyCode` | string | Y | ISO 4217 3자. 원화 청구건 `KRW`, 발급사 원화 미제공 해외건은 발급사 통화코드, 미상은 `XXX` | | `paymentMethod` | enum(SINGLE_PAYMENT,INSTALLMENT,CHECK,OTHER) | Y | SINGLE_PAYMENT(일시불) / INSTALLMENT(할부) / CHECK(체크) / OTHER | | `status` | enum(APPROVED,CANCELLED,PARTIALLY_CANCELLED,DECLINED,UNKNOWN) | Y | APPROVED / CANCELLED / PARTIALLY_CANCELLED / DECLINED / UNKNOWN. 취소건은 원 승인건과 같은 승인번호로 별도 행으로 올 수 있음 | | `isOverseas` | boolean | Y | true=해외 / false=국내 | | `originalAmount` | number | - | 해외 원거래의 외화 원금. 국내·원화 해외결제(DCC)·발급사 미제공 시 null | | `originalCurrencyCode` | string | - | ISO 4217 3자. 외화 원금의 통화. 원금 부재 시 null | | `installmentMonths` | integer | - | 할부 결제의 개월 수. 일시불/체크 등은 null | | `taxAmount` | number | - | 거래에 포함된 부가가치세액 (발급사 제공 시) | | `merchantBusinessIdentifier` | string | - | 하이픈·공백 제거된 숫자만 (발급사 제공 시) | | `merchantAddress` | string | - | 가맹점 사업장 주소 (발급사 제공 시) | | `merchantContactNumber` | string | - | 가맹점 연락처 (발급사 제공 시) | | `merchantRepresentativeName` | string | - | 가맹점 대표자명 (발급사 제공 시) | | `merchantBusinessType` | string | - | 가맹점 업종 분류 (발급사 제공 시) | ## 에러 코드 모든 에러는 동일한 셰이프로 반환된다: ```json {"code":"","message":"<한국어 메시지>","requestId":"..."} ``` | 코드 | HTTP | 메시지 | |------|------|--------| | `ACTION_NOT_SUPPORTED` | 400 | 해당 프로바이더에서 지원하지 않는 액션입니다 | | `ALREADY_FREE_NO_OP` | 400 | 이미 FREE 플랜이라 해지할 수 없습니다 | | `API_KEY_ALREADY_REVOKED` | 400 | 이미 폐기된 API 키입니다 | | `DATE_RANGE_EXCEEDED` | 400 | 허용된 최대 조회 기간을 초과했습니다 | | `DATE_RANGE_INVALID` | 400 | 조회 기간 범위가 유효하지 않습니다 | | `DELIVERY_ROUTE_NOT_FOUND` | 400 | 해당 워크스페이스에 배달 경로가 설정되지 않았습니다 | | `DEVICE_CODE_EXPIRED` | 400 | 만료된 device_code 입니다. 다시 시도해 주세요 | | `DEVICE_CODE_INVALID` | 400 | 유효하지 않은 device_code 입니다 | | `INVALID_BUSINESS_REGISTRATION_NUMBER` | 400 | 사업자등록번호 형식이 올바르지 않습니다 | | `INVALID_CREDENTIAL_FORMAT` | 400 | 인증 필드 형식이 올바르지 않습니다 | | `INVALID_CURSOR` | 400 | 유효하지 않은 커서입니다 | | `INVALID_DATA_JOB_PARAMS` | 400 | 요청 파라미터가 올바르지 않습니다 | | `INVALID_PARAM_FORMAT` | 400 | 파라미터 형식이 올바르지 않습니다 | | `INVALID_PROVIDER_CODE` | 400 | 지원하지 않는 프로바이더 코드입니다 | | `MALFORMED_REQUEST` | 400 | 요청 본문 형식이 올바르지 않습니다 | | `MISSING_CREDENTIAL_FIELD` | 400 | 필수 인증 필드가 누락되었습니다 | | `MISSING_PARAMETER` | 400 | 필수 파라미터가 누락되었습니다 | | `MISSING_REQUIRED_PARAM` | 400 | 필수 파라미터가 누락되었습니다 | | `NO_PENDING_PLAN_CHANGE` | 400 | 취소할 예약된 플랜 변경이 없습니다 | | `PARTNER_BUSINESS_SELECTOR_REQUIRED` | 400 | X-H6S-Business 헤더(사업자등록번호)가 필요합니다 | | `PARTNER_NAME_INVALID` | 400 | 파트너 이름이 유효하지 않습니다 | | `PAYMENT_METHOD_REQUIRED` | 400 | 결제수단을 먼저 등록해 주세요 | | `PERSONAL_EMAIL_NOT_ALLOWED` | 400 | 회사 업무용 이메일로 가입해 주세요. 회사 이메일을 사용할 수 없는 경우 영업팀(h6s@bolta.io)으로 문의해 주세요 | | `PROVIDER_CODE_MISMATCH` | 400 | 요청한 기관과 자격증명에 묶인 기관이 다릅니다 | | `PROVIDER_CODE_REQUIRED_FOR_GLOBAL_CERT` | 400 | 공동인증서 자격증명은 어느 기관으로 호출할지 함께 지정해야 합니다 | | `PROVIDER_DOES_NOT_ACCEPT_CERT_LOGIN` | 400 | 이 기관은 공동인증서 로그인을 지원하지 않습니다 | | `SAME_PLAN_CHANGE` | 400 | 이미 같은 플랜입니다 | | `SUBSCRIPTION_NOT_PAST_DUE` | 400 | 결제 실패 상태가 아닙니다 | | `UNSUPPORTED_AUTH_METHOD` | 400 | 지원하지 않는 인증 방식입니다 | | `INVALID_CREDENTIALS` | 401 | 이메일 또는 비밀번호가 올바르지 않습니다 | | `INVALID_TOKEN` | 401 | 유효하지 않은 토큰입니다 | | `TOKEN_EXPIRED` | 401 | 만료된 토큰입니다 | | `WEBHOOK_SIGNATURE_INVALID` | 401 | 웹훅 서명이 유효하지 않습니다 | | `CARD_DECLINED` | 402 | 카드사에서 결제를 거절했습니다 | | `CARD_LIMIT_EXCEEDED` | 402 | 카드 이용 한도를 초과했습니다 | | `INSUFFICIENT_FUNDS` | 402 | 결제 계좌의 잔액이 부족합니다 | | `MERCHANT_LIMIT_EXCEEDED` | 402 | 결제 한도가 초과되었습니다. 잠시 후 다시 시도해 주세요 | | `PAYMENT_FAILED` | 402 | 결제에 실패했습니다 | | `SUBSCRIPTION_PAST_DUE` | 402 | 결제 실패 상태입니다 — 결제수단을 갱신해 주세요 | | `ADMIN_ACTION_FORBIDDEN` | 403 | 이 액션을 수행할 권한이 없습니다 | | `ADMIN_FORBIDDEN` | 403 | 어드민 권한이 없습니다 | | `INTERNAL_PLAN_NOT_MUTABLE` | 403 | 내부 전용 플랜은 콘솔에서 직접 변경/해지할 수 없습니다 | | `INTERNAL_PLAN_NOT_PURCHASABLE` | 403 | 내부 전용 플랜으로는 변경할 수 없습니다 | | `WORKSPACE_ACCESS_DENIED` | 403 | 해당 워크스페이스에 접근 권한이 없습니다 | | `ACCOUNT_NOT_FOUND` | 404 | 계정을 찾을 수 없습니다 | | `ACTION_NOT_FOUND` | 404 | 액션을 찾을 수 없습니다 | | `AGENT_BUG_REPORT_NOT_FOUND` | 404 | 버그 제보를 찾을 수 없습니다 | | `API_KEY_NOT_FOUND` | 404 | API 키를 찾을 수 없습니다 | | `CREDENTIAL_NOT_FOUND` | 404 | 자격증명을 찾을 수 없습니다 | | `DATA_JOB_NOT_FOUND` | 404 | 수집 요청을 찾을 수 없습니다 | | `INVOICE_NOT_FOUND` | 404 | 청구서를 찾을 수 없습니다 | | `PARTNER_NOT_FOUND` | 404 | 파트너를 찾을 수 없습니다 | | `PAYMENT_METHOD_NOT_FOUND` | 404 | 결제수단을 찾을 수 없습니다 | | `RESOURCE_NOT_FOUND` | 404 | 요청한 리소스를 찾을 수 없습니다 | | `SUBSCRIPTION_NOT_FOUND` | 404 | 구독 정보를 찾을 수 없습니다 | | `USER_CODE_INVALID` | 404 | 유효하지 않은 인증 코드입니다. 다시 확인해 주세요 | | `WORKSPACE_MEMBER_NOT_FOUND` | 404 | 워크스페이스 멤버를 찾을 수 없습니다 | | `WORKSPACE_NOT_FOUND` | 404 | 워크스페이스를 찾을 수 없습니다 | | `METHOD_NOT_ALLOWED` | 405 | 허용되지 않은 HTTP 메서드입니다 | | `CREDENTIAL_ALREADY_EXISTS` | 409 | 이미 등록된 자격증명입니다 | | `CREDENTIAL_PROVIDER_DUPLICATED` | 409 | 이 기관에 이미 등록된 자격증명이 있습니다. 갱신하려면 기존 자격증명에서 값을 변경하세요 | | `DUPLICATE_EMAIL` | 409 | 이미 등록된 이메일입니다 | | `PAYMENT_METHOD_IN_USE` | 409 | 활성 구독에서 사용 중인 결제수단입니다 | | `USER_CODE_EXPIRED` | 410 | 만료된 인증 코드입니다. CLI 에서 새 코드를 발급해 주세요 | | `UNSUPPORTED_MEDIA_TYPE` | 415 | 지원하지 않는 Content-Type 입니다 | | `CERT_BIZNO_MISMATCH` | 422 | 워크스페이스 사업자번호와 인증서가 일치하지 않습니다 | | `CERT_ENCRYPTION_UNSUPPORTED` | 422 | 지원하지 않는 인증서 암호화 알고리즘입니다 — 다른 형식의 공동인증서로 다시 시도해 주세요 | | `CERT_EXPIRED` | 422 | 인증서가 만료되었습니다 | | `CERT_INVALID` | 422 | 인증서 파일을 읽을 수 없습니다 | | `CERT_KEY_USAGE_INVALID` | 422 | 암호화 전용 인증서는 사용할 수 없습니다 — 서명용 인증서를 등록해 주세요 | | `CERT_R_VALUE_NOT_FOUND` | 422 | 인증서 형식이 올바르지 않습니다 — 사업자번호 확인에 실패했습니다 | | `CERT_TYPE_UNSUPPORTED` | 422 | 지원하지 않는 인증서 유형입니다 — 사업자/법인용 공동인증서를 등록해 주세요 | | `CERT_WRONG_PASSWORD` | 422 | 인증서 비밀번호가 올바르지 않습니다 | | `CREDENTIAL_INSUFFICIENT_FOR_PROVIDER` | 422 | 이 기관 자격증명을 먼저 등록해 주세요 | | `CREDENTIAL_PROBE_FAILED` | 422 | 외부 기관 인증에 실패했습니다 — 입력값을 확인해 주세요 | | `CREDENTIAL_SCOPE_NOT_SUPPORTED` | 422 | 이 endpoint 는 기관 지정 자격증명만 지원합니다 — 공동인증서는 별도 endpoint 를 이용해 주세요 | | `API_RATE_LIMITED` | 429 | API 호출 한도를 초과했습니다. 잠시 후 다시 시도해 주세요 | | `FREE_PLAN_JOB_CAP_REACHED` | 429 | 무료 한도(월 수집 요청 수)에 도달했습니다 — 스탠다드 1x로 업그레이드 시 무제한 | | `FREE_PLAN_TASK_CAP_REACHED` | 429 | 무료 한도(월 스크래핑 단계 수)에 도달했습니다 — 스탠다드 1x로 업그레이드 시 무제한 | | `TOO_MANY_CONCURRENT_WORKERS` | 429 | 동시 처리 한도에 도달했습니다. 잠시 후 다시 시도해주세요 | | `TOO_MANY_LOGIN_ATTEMPTS` | 429 | 로그인 시도가 너무 많습니다. 잠시 후 다시 시도해주세요 | | `ADMIN_ACTION_NOT_MARKED` | 500 | 어드민 액션 엔드포인트에 권한 마킹이 누락되었습니다 | | `INTERNAL_ERROR` | 500 | 서버 내부 오류가 발생했습니다 | | `SCRAPING_PARSER_NOT_FOUND` | 500 | 스크래핑 응답 파서를 찾을 수 없습니다 | | `SCRAPING_RESPONSE_MALFORMED` | 500 | 스크래핑 응답 형식이 올바르지 않습니다 | | `SCRAPING_ENGINE_UNAVAILABLE` | 503 | 스크래핑 엔진에 연결할 수 없습니다 |