
Nts Business Registration
- 1.6k installs
- 6.5k repo stars
- Updated July 27, 2026
- nomadamas/k-skill
nts-business-registration is an agent skill for 국세청 사업자등록정보 진위확인 및 사업자등록 상태조회를 공공데이터포털 api(k-skill-proxy 경유)로 수행한다.
About
The nts-business-registration skill is designed for 국세청 사업자등록정보 진위확인 및 사업자등록 상태조회를 공공데이터포털 API(k-skill-proxy 경유)로 수행한다. 국세청 사업자등록정보 진위확인 및 상태조회 What this skill does 공공데이터포털의 국세청_사업자등록정보 진위확인 및 상태조회 서비스를 k-skill-proxy 경유로 호출해 다음을 확인한다. 비우면 기본 hosted https://k-skill-proxy.nomadamas.org 를 사용한다. Invoke when the user asks about nts business registration or related SKILL.md workflows.
- status: 사업자등록번호 기준 상태조회 (계속사업자, 휴업자, 폐업자, 과세유형 등 upstream 응답 그대로 포함).
- validate: 사업자등록번호 + 개업일자 + 대표자명(및 선택 필드) 기준 진위확인.
- "이 사업자등록번호가 계속사업자인지 확인해줘".
- "사업자등록번호 상태조회해줘".
- "사업자등록번호, 개업일, 대표자명으로 진위확인해줘".
Nts Business Registration by the numbers
- 1,649 all-time installs (skills.sh)
- +129 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #211 of 1,896 Design & UI/UX skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
nts-business-registration capabilities & compatibility
- Capabilities
- status: 사업자등록번호 기준 상태조회 (계속사업자, 휴업자, 폐업자, 과세유형 등 · validate: 사업자등록번호 + 개업일자 + 대표자명(및 선택 필드) 기준 진위확인 · "이 사업자등록번호가 계속사업자인지 확인해줘" · "사업자등록번호 상태조회해줘"
- Use cases
- frontend
What nts-business-registration says it does
국세청 사업자등록정보 진위확인 및 사업자등록 상태조회를 공공데이터포털 API(k-skill-proxy 경유)로 수행한다.
국세청 사업자등록정보 진위확인 및 사업자등록 상태조회를 공공데이터포털 API(k-skill-proxy 경유)로 수행한다.
npx skills add https://github.com/nomadamas/k-skill --skill nts-business-registrationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.6k |
|---|---|
| repo stars | ★ 6.5k |
| Security audit | 2 / 3 scanners passed |
| Last updated | July 27, 2026 |
| Repository | nomadamas/k-skill ↗ |
How do I 국세청 사업자등록정보 진위확인 및 사업자등록 상태조회를 공공데이터포털 api(k-skill-proxy 경유)로 수행한다?
국세청 사업자등록정보 진위확인 및 사업자등록 상태조회를 공공데이터포털 API(k-skill-proxy 경유)로 수행한다.
Who is it for?
Developers using nts business registration workflows documented in SKILL.md.
Skip if: Skip when the task falls outside nts-business-registration scope or needs a different stack.
When should I use this skill?
User asks about nts business registration or related SKILL.md workflows.
What you get
Completed nts-business-registration workflow with documented commands, files, and expected deliverables.
- Validated business JSON
- Batch registration results
- API error diagnostics
By the numbers
- BATCH_LIMIT is 100 records per batch request
- Validates p_nm and p_nm2 fields up to 30 characters each
Files
국세청 사업자등록정보 진위확인 및 상태조회
What this skill does
공공데이터포털의 국세청_사업자등록정보 진위확인 및 상태조회 서비스를 k-skill-proxy 경유로 호출해 다음을 확인한다.
status: 사업자등록번호 기준 상태조회 (계속사업자,휴업자,폐업자, 과세유형 등 upstream 응답 그대로 포함)validate: 사업자등록번호 + 개업일자 + 대표자명(및 선택 필드) 기준 진위확인
When to use
- "이 사업자등록번호가 계속사업자인지 확인해줘"
- "사업자등록번호 상태조회해줘"
- "사업자등록번호, 개업일, 대표자명으로 진위확인해줘"
- 거래처 등록 전 공식 NTS/공공데이터포털 기준 확인이 필요할 때
Prerequisites
- 인터넷 연결
python3- 설치된 skill payload 안에
scripts/nts_business_registration.pyhelper 포함 - hosted/self-host
k-skill-proxy의/v1/nts-business/status,/v1/nts-business/validateroute 접근 가능
Credential requirements
- 사용자 측 필수 시크릿 없음.
KSKILL_PROXY_BASE_URL— self-host·별도 프록시를 쓸 때만 설정. 비우면 기본 hostedhttps://k-skill-proxy.nomadamas.org를 사용한다.DATA_GO_KR_API_KEY는 프록시 운영 서버 환경에만 둔다. 공공데이터포털에서국세청_사업자등록정보 진위확인 및 상태조회 서비스활용신청이 되어 있어야 한다.
Validate privacy boundary
validate는 대표자명(p_nm), 개업일자(start_dt), 주소·상호 같은 선택 메타데이터를 hosted proxy와 공공데이터포털 upstream으로 전송한다.- hosted proxy는
validate성공 응답을 캐시하지 않고, 프록시queryecho를 붙이지 않으며, upstream이 요청값을 되돌려도 민감 입력 필드를 응답에서 제거한다. - 프록시의 기본 Fastify request logging은 꺼져 있다. 운영자가 별도 로그를 켠 self-host 환경에서는 요청 본문 로깅 정책을 직접 점검해야 한다.
- hosted proxy 경유가 부담스러운 진위확인 업무는
KSKILL_PROXY_BASE_URL로 직접 운영하는 self-host proxy를 지정한다.
Official surfaces
- 공공데이터포털 문서:
https://www.data.go.kr/tcs/dss/selectApiDataDetailView.do?publicDataPk=15081808 - 상태조회 upstream:
POST https://api.odcloud.kr/api/nts-businessman/v1/status?serviceKey=... - 진위확인 upstream:
POST https://api.odcloud.kr/api/nts-businessman/v1/validate?serviceKey=... - 프록시 route:
POST /v1/nts-business/status,POST /v1/nts-business/validate
Inputs
상태조회
b_no: 사업자등록번호 10자리. 하이픈은 허용되며 helper/proxy가 숫자만 남긴다.- 한 요청은 최대 100개까지 보낸다.
진위확인
필수:
b_no: 사업자등록번호 10자리start_dt: 개업일자YYYYMMDD(하이픈/점 허용)p_nm: 대표자 성명
선택:
p_nm2: 대표자 성명2b_nm: 상호corp_no: 법인등록번호b_sector: 주업태명b_type: 주종목명b_adr: 사업장주소
텍스트 필드는 NTS 입력 규격에 맞춰 보수적으로 길이를 제한한다(p_nm/p_nm2 30자, b_nm 200자, b_sector/b_type 100자, b_adr 500자). corp_no는 제공할 경우 숫자 13자리여야 한다.
Workflow
1. 사용자 입력에서 사업자등록번호는 숫자 10자리인지 확인한다. 2. 상태조회만 필요하면 status를 호출한다. 3. 진위확인은 최소 b_no, start_dt, p_nm이 있을 때만 호출한다. 4. 개인정보/거래처 정보는 필요한 필드만 보내고, 프록시 응답을 그대로 보존하되 핵심 상태/진위 결과를 짧게 요약한다. 5. upstream이 upstream_not_configured, 활용신청 미승인, 인증키 오류 등을 반환하면 설정/승인 문제로 안내한다.
CLI examples
python3 scripts/nts_business_registration.py status \
--b-no 123-45-67890python3 scripts/nts_business_registration.py validate \
--business-json '{"b_no":"123-45-67890","start_dt":"2020-01-31","p_nm":"홍길동","b_nm":"테스트상사"}'Direct proxy examples
curl -fsS -X POST "$KSKILL_PROXY_BASE_URL/v1/nts-business/status" \
-H 'content-type: application/json' \
-d '{"b_no":["123-45-67890"]}'curl -fsS -X POST "$KSKILL_PROXY_BASE_URL/v1/nts-business/validate" \
-H 'content-type: application/json' \
-d '{"businesses":[{"b_no":"123-45-67890","start_dt":"20200131","p_nm":"홍길동"}]}'Failure modes
400 bad_request: 사업자등록번호가 10자리가 아니거나 진위확인 필수 필드가 빠짐.503 upstream_not_configured: 프록시 서버에DATA_GO_KR_API_KEY가 없음.- upstream 인증/활용신청 오류: API 키가 해당 서비스에 승인되지 않았거나 만료/오류 상태.
- 빈 결과 또는 진위불일치: 공식 응답의
valid,valid_msg,b_stt값을 그대로 근거로 설명한다.
Done when
- 상태조회는 공식 응답의
b_stt,b_stt_cd,tax_type등 핵심 필드를 확인했다. - 진위확인은
valid,valid_msg결과를 확인했다. - API 키는 사용자에게 요구하지 않고 프록시 서버에만 둔다는 점을 지켰다.
from __future__ import annotations
import argparse
import datetime as dt
import json
import os
import re
import sys
import urllib.error
import urllib.request
from typing import Any
PROXY_BASE_URL_ENV_VAR = "KSKILL_PROXY_BASE_URL"
DEFAULT_PROXY_BASE_URL = "https://k-skill-proxy.nomadamas.org"
BATCH_LIMIT = 100
VALIDATE_TEXT_FIELD_LIMITS = {
"p_nm": 30,
"p_nm2": 30,
"b_nm": 200,
"b_sector": 100,
"b_type": 100,
"b_adr": 500,
}
class ApiError(RuntimeError):
def __init__(self, message: str, *, status_code: int | None = None, url: str | None = None):
super().__init__(message)
self.status_code = status_code
self.url = url
def _text_or_none(value: Any) -> str | None:
if value is None:
return None
text = str(value).strip()
return text or None
def resolve_proxy_base_url(explicit_base_url: str | None = None, env: dict[str, str] | None = None) -> str:
env = os.environ if env is None else env
candidate = _text_or_none(explicit_base_url or env.get(PROXY_BASE_URL_ENV_VAR))
if candidate and candidate.casefold() in {"off", "false", "0", "disable", "disabled", "none"}:
raise ValueError("KSKILL_PROXY_BASE_URL 가 비활성화되어 있습니다.")
if candidate and candidate != "replace-me":
return candidate.rstrip("/")
return DEFAULT_PROXY_BASE_URL
def normalize_business_number(value: Any) -> str:
raw = _text_or_none(value)
if not raw:
raise ValueError("사업자등록번호(b_no)를 입력하세요.")
normalized = re.sub(r"\D", "", raw)
if not re.fullmatch(r"\d{10}", normalized):
raise ValueError("사업자등록번호는 숫자 10자리여야 합니다.")
return normalized
def normalize_start_date(value: Any) -> str:
raw = _text_or_none(value)
if not raw:
raise ValueError("개업일자(start_dt)를 YYYYMMDD 형식으로 입력하세요.")
normalized = re.sub(r"\D", "", raw)
if not re.fullmatch(r"\d{8}", normalized):
raise ValueError("개업일자는 YYYYMMDD 형식이어야 합니다.")
try:
dt.date(int(normalized[:4]), int(normalized[4:6]), int(normalized[6:8]))
except ValueError as error:
raise ValueError("개업일자는 유효한 날짜여야 합니다.") from error
return normalized
def normalize_validate_text(value: Any, field_name: str, *, required: bool = False) -> str | None:
text = _text_or_none(value)
if not text:
if required:
raise ValueError(f"{field_name}을(를) 입력하세요.")
return None
max_length = VALIDATE_TEXT_FIELD_LIMITS.get(field_name)
if max_length and len(text) > max_length:
raise ValueError(f"{field_name}은(는) {max_length}자 이하여야 합니다.")
return text
def normalize_corp_no(value: Any) -> str | None:
raw = _text_or_none(value)
if not raw:
return None
normalized = re.sub(r"\D", "", raw)
if not re.fullmatch(r"\d{13}", normalized):
raise ValueError("corp_no는 숫자 13자리여야 합니다.")
return normalized
def build_status_payload(business_numbers: list[Any]) -> dict[str, list[str]]:
numbers = [normalize_business_number(value) for value in business_numbers]
numbers = list(dict.fromkeys(numbers))
if not numbers:
raise ValueError("사업자등록번호를 1개 이상 입력하세요.")
if len(numbers) > BATCH_LIMIT:
raise ValueError("한 번에 조회할 수 있는 사업자등록번호는 100개까지입니다.")
return {"b_no": numbers}
def build_validate_business(**kwargs: Any) -> dict[str, str]:
p_nm = normalize_validate_text(kwargs.get("p_nm"), "p_nm", required=True)
business = {
"b_no": normalize_business_number(kwargs.get("b_no")),
"start_dt": normalize_start_date(kwargs.get("start_dt")),
"p_nm": p_nm,
}
for key in ("p_nm2", "b_nm", "b_sector", "b_type", "b_adr"):
value = normalize_validate_text(kwargs.get(key), key)
if value:
business[key] = value
corp_no = normalize_corp_no(kwargs.get("corp_no"))
if corp_no:
business["corp_no"] = corp_no
return business
def build_validate_payload(businesses: list[dict[str, Any]]) -> dict[str, list[dict[str, str]]]:
if not businesses:
raise ValueError("진위확인 대상 businesses를 1개 이상 입력하세요.")
if len(businesses) > BATCH_LIMIT:
raise ValueError("한 번에 진위확인할 수 있는 사업자는 100개까지입니다.")
return {"businesses": [build_validate_business(**business) for business in businesses]}
def read_json_response(request: urllib.request.Request) -> dict[str, Any]:
try:
with urllib.request.urlopen(request, timeout=30) as response:
return json.loads(response.read().decode("utf-8"))
except urllib.error.HTTPError as error:
body = error.read().decode("utf-8", errors="replace")
try:
payload = json.loads(body)
except json.JSONDecodeError:
payload = None
if isinstance(payload, dict) and payload.get("message"):
raise ApiError(str(payload["message"]), status_code=error.code, url=getattr(error, "url", None)) from error
raise ApiError(f"NTS business proxy request failed with HTTP {error.code}", status_code=error.code, url=getattr(error, "url", None)) from error
except urllib.error.URLError as error:
raise ApiError(f"NTS business proxy request failed: {error.reason}") from error
def _post_json(path: str, payload: dict[str, Any], *, base_url: str | None = None, read_json: Any = read_json_response) -> dict[str, Any]:
resolved_base_url = resolve_proxy_base_url(base_url)
request = urllib.request.Request(
f"{resolved_base_url}{path}",
data=json.dumps(payload, ensure_ascii=False).encode("utf-8"),
headers={
"Accept": "application/json",
"Content-Type": "application/json",
"User-Agent": "k-skill-nts-business-registration/1.0",
},
method="POST",
)
return read_json(request)
def query_status(business_numbers: list[Any], *, base_url: str | None = None, read_json: Any = read_json_response) -> dict[str, Any]:
return _post_json("/v1/nts-business/status", build_status_payload(business_numbers), base_url=base_url, read_json=read_json)
def validate_businesses(businesses: list[dict[str, Any]], *, base_url: str | None = None, read_json: Any = read_json_response) -> dict[str, Any]:
return _post_json("/v1/nts-business/validate", build_validate_payload(businesses), base_url=base_url, read_json=read_json)
def _parse_business_json(value: str) -> dict[str, Any]:
payload = json.loads(value)
if not isinstance(payload, dict):
raise argparse.ArgumentTypeError("business JSON must be an object")
return payload
def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description="NTS business registration status/authenticity helper")
subparsers = parser.add_subparsers(dest="command", required=True)
status = subparsers.add_parser("status", help="사업자등록번호 상태조회")
status.add_argument("--b-no", action="append", required=True, help="사업자등록번호(10자리; 하이픈 허용). 여러 번 지정 가능")
status.add_argument("--proxy-base-url")
validate = subparsers.add_parser("validate", help="사업자등록정보 진위확인")
validate.add_argument("--business-json", action="append", type=_parse_business_json, required=True, help='예: {"b_no":"1234567890","start_dt":"20200101","p_nm":"홍길동"}')
validate.add_argument("--proxy-base-url")
return parser
def main(argv: list[str] | None = None) -> int:
args = build_parser().parse_args(argv)
try:
if args.command == "status":
print(json.dumps(query_status(args.b_no, base_url=args.proxy_base_url), ensure_ascii=False, indent=2))
return 0
if args.command == "validate":
print(json.dumps(validate_businesses(args.business_json, base_url=args.proxy_base_url), ensure_ascii=False, indent=2))
return 0
except (ValueError, ApiError) as error:
print(json.dumps({"error": str(error)}, ensure_ascii=False, indent=2), file=sys.stderr)
return 1
return 1
if __name__ == "__main__":
raise SystemExit(main())
Related skills
How it compares
Choose nts-business-registration when you need a scripted Korean NTS verification path with batch support instead of hand-rolling proxy calls and field validation.
FAQ
What does nts-business-registration do?
국세청 사업자등록정보 진위확인 및 사업자등록 상태조회를 공공데이터포털 API(k-skill-proxy 경유)로 수행한다.
When should I use nts-business-registration?
User asks about nts business registration or related SKILL.md workflows.
Is nts-business-registration safe to install?
Review the Security Audits panel on this page before installing in production.