
Delivery Tracking
Track package/delivery status, likely via a courier tracking API.
Install
npx skills add https://github.com/nomadamas/k-skill --skill delivery-trackingWhat is this skill?
- Delivery/package tracking
- Courier status lookup
Adoption & trust: 2.7k installs on skills.sh; 5.4k GitHub stars; 2/3 security scanners passed (skills.sh audits).
Recommended Skills
Agent Browservercel-labs/agent-browser
Lark Imlarksuite/cli
Lark Calendarlarksuite/cli
Lark Sheetslarksuite/cli
Lark Vclarksuite/cli
Lark Contactlarksuite/cli
Journey fit
Primary fit
A delivery-status lookup that calls a courier's tracking service — build-phase integration of an external API into a tool. Querying carrier tracking endpoints to report delivery status is integrating an external service, mapped to build/integrations.
Common Questions / FAQ
Is Delivery Tracking safe to install?
skills.sh reports 2 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.
SKILL.md
READMESKILL.md - Delivery Tracking
# Delivery Tracking ## What this skill does CJ대한통운과 우체국 공식 조회 표면을 사용해 송장 번호로 현재 배송 상태를 조회한다. - **CJ대한통운**: 공식 배송조회 페이지가 노출하는 JSON endpoint 사용 - **우체국**: 공식 배송조회 페이지가 사용하는 HTML endpoint 사용 - 결과는 공통 포맷(택배사 / 송장번호 / 현재 상태 / 최근 이벤트들)으로 짧게 정리 ## When to use - "CJ대한통운 송장 조회해줘" - "우체국 택배 지금 어디야" - "이 송장번호 배송완료인지 확인해줘" - "택배사별 조회 로직을 나중에 더 붙일 수 있게 정리해줘" ## When not to use - 주문번호만 있고 송장번호가 없는 경우 - 택배 예약/반품 접수까지 바로 해야 하는 경우 - 비공식 통합 배송조회 서비스로 우회하고 싶은 경우 ## Prerequisites - 인터넷 연결 - `python3` - `curl` - 선택 사항: `jq` ## Inputs - 택배사 식별자: `cj` 또는 `epost` - 송장번호 - CJ대한통운: 숫자 10자리 또는 12자리 - 우체국: 숫자 13자리 ## Carrier adapter rule 이 스킬은 택배사별 로직을 **carrier adapter** 단위로 나눈다. 새 택배사를 붙일 때는 아래 필드를 먼저 정한다. - `carrier id`: 예) `cj`, `epost` - `validator`: 송장번호 자리수/패턴 - `entrypoint`: 공식 조회 진입 URL - `transport`: JSON API / HTML form / CLI 중 무엇을 쓰는지 - `parser`: 어떤 필드나 테이블에서 상태를 뽑는지 - `status map`: 각 택배사의 원본 상태 코드를 공통 상태로 어떻게 줄일지 - `retry policy`: timeout/retry 규칙 현재 어댑터는 아래 둘이다. | carrier adapter | official entry | transport | validator | parser focus | | --- | --- | --- | --- | --- | | `cj` | `https://www.cjlogistics.com/ko/tool/parcel/tracking` | page GET + `tracking-detail` POST JSON | 10자리 또는 12자리 숫자 | `parcelDetailResultMap.resultList` | | `epost` | `https://service.epost.go.kr/trace.RetrieveRegiPrclDeliv.postal?sid1=` | form POST HTML | 13자리 숫자 | 기본정보 `table_col` + 상세 `processTable` | ## Workflow ### 0. Normalize the input first - 택배사 이름을 `cj` / `epost` 둘 중 하나로 정규화한다. - 송장번호에서 공백과 `-` 를 제거한다. - 자리수 검증이 먼저 실패하면 조회를 보내지 않는다. ### 1. CJ대한통운: official JSON flow 공식 진입 페이지에서 `_csrf` 를 읽고, 그 값을 `tracking-detail` POST에 같이 보낸다. - 진입 페이지: `https://www.cjlogistics.com/ko/tool/parcel/tracking` - 상세 endpoint: `https://www.cjlogistics.com/ko/tool/parcel/tracking-detail` - 필수 필드: `_csrf`, `paramInvcNo` 기본 예시는 `curl` 로 `_csrf` 와 cookie를 유지하고, Python은 JSON 정리에만 쓴다. ```bash tmp_body="$(mktemp)" tmp_cookie="$(mktemp)" tmp_json="$(mktemp)" invoice="1234567890" # 공식 페이지 placeholder 성격의 smoke-test 값 curl -sS -L -c "$tmp_cookie" \ "https://www.cjlogistics.com/ko/tool/parcel/tracking" \ -o "$tmp_body" csrf="$(python3 - <<'PY' "$tmp_body" import re import sys text = open(sys.argv[1], encoding="utf-8", errors="ignore").read() print(re.search(r'name="_csrf" value="([^"]+)"', text).group(1)) PY )" curl -sS -L -b "$tmp_cookie" \ -H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" \ --data-urlencode "_csrf=$csrf" \ --data-urlencode "paramInvcNo=$invoice" \ "https://www.cjlogistics.com/ko/tool/parcel/tracking-detail" \ -o "$tmp_json" python3 - <<'PY' "$tmp_json" import json import sys payload = json.load(open(sys.argv[1], encoding="utf-8")) events = payload["parcelDetailResultMap"]["resultList"] if not events: raise SystemExit("조회 결과가 없습니다.") status_map = { "11": "상품인수", "21": "상품이동중", "41": "상품이동중", "42": "배송지도착", "44": "상품이동중", "82": "배송출발", "91": "배달완료", } latest = events[-1] normalized_events = [ { "timestamp": event.get("dTime"), "location": event.get("regBranNm"), "status_code": event.get("crgSt"), "status": status_map.get(event.get("crgSt"), event.get("scanNm") or "알수없음"), } for event in events ] print(json.dumps({ "carrier": "cj", "invoice": payload["parcelDetailResultMap"]["paramInvcNo"], "status_code": latest.get("crgSt"), "status": status_map.get(latest.get("crgSt"), latest.get("scanNm") or "알수없음"), "timestamp": latest.get("dTime"), "location": latest.get("regBranNm"), "event_count": len(events), "recent_events": normalized_events[-min(3, len(normalized_events)):], }, ensure_ascii=False, indent=2)) PY rm -f "$tmp_b