이 문서는
kma구현자를 위한 API 레퍼런스입니다. 사용자용 빠른 설명은README.md, 에이전트 구현 규칙은SKILL.md를 보세요.
APIHub 전체 범위와 generic 호출 방식은 docs/apihub.md, APIHub 함수형 endpoint 목록은 docs/apihub-endpoints.md, data.go.kr generic 호출 방식은 docs/datagokr.md를 함께 보세요.
| 항목 | 값 |
|---|---|
| 서비스 | 기상청 단기예보 조회서비스 |
| 공공데이터포털 서비스명 | VilageFcstInfoService_2.0 |
| Base URL | http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0 |
| 인증 파라미터 | serviceKey |
| 출력 형식 | dataType=JSON |
| 기본 페이지 | pageNo=1 |
| 권장 row 수 | numOfRows=1000 |
| 시간대 | KST(UTC+9) |
| 좌표계 | KMA LCC DFS 격자 nx, ny |
공공데이터포털은 Encoding 키와 Decoding 키를 함께 보여줍니다.
kma의 기본 HTTP 호출은 다음 형태입니다.
requests.get(url, params={"serviceKey": service_key, ...})따라서 service_key에는 Decoding 키를 넣는 것을 권장합니다. 이미 URL 인코딩된 Encoding 키를 params=에 넣으면 다시 인코딩되어 SERVICE_KEY_IS_NOT_REGISTERED_ERROR가 발생할 수 있습니다.
URL 문자열에 직접 붙여야 하는 디버깅 상황에서는 Encoding 키를 사용할 수 있지만, 라이브러리의 일반 경로에서는 Decoding 키를 기준으로 합니다.
초단기실황, 초단기예보, 단기예보의 공통 파라미터:
| 파라미터 | 필수 | 설명 |
|---|---|---|
serviceKey |
예 | 공공데이터포털 인증키 |
pageNo |
예 | 보통 1 |
numOfRows |
예 | getVilageFcst는 항목이 많으므로 1000 권장 |
dataType |
예 | JSON |
base_date |
예 | 발표일, YYYYMMDD |
base_time |
예 | 발표시각, HHMM |
nx |
예 | KMA 격자 X |
ny |
예 | KMA 격자 Y |
초단기실황입니다. 격자 기준 현재 관측값을 반환합니다.
| 항목 | 값 |
|---|---|
| public method | KmaClient.now() |
| 발표시각 | 매시 정각 HH00 |
| 조회 가능 | 발표 후 약 40분 |
| 시간 필드 | baseDate, baseTime |
| 값 필드 | obsrValue |
| 반환 모델 | WeatherSnapshot |
대표 category:
| 코드 | 의미 | 단위 |
|---|---|---|
T1H |
기온 | C |
RN1 |
1시간 강수량 | mm 또는 범주 |
UUU |
동서바람성분 | m/s |
VVV |
남북바람성분 | m/s |
REH |
습도 | % |
PTY |
강수형태 | code |
VEC |
풍향 | deg |
WSD |
풍속 | m/s |
초단기예보입니다. 대략 향후 6시간의 시간별 예보를 반환합니다.
| 항목 | 값 |
|---|---|
| public method | KmaClient.forecast_short() |
| 발표시각 | 매시 30분 HH30 |
| 조회 가능 | 발표 후 약 15분, 보통 HH45 이후 |
| 시간 필드 | baseDate, baseTime, fcstDate, fcstTime |
| 값 필드 | fcstValue |
| 반환 모델 | list[ForecastItem] |
대표 category:
| 코드 | 의미 | 단위 |
|---|---|---|
T1H |
기온 | C |
RN1 |
1시간 강수량 | mm 또는 범주 |
SKY |
하늘상태 | code |
UUU |
동서바람성분 | m/s |
VVV |
남북바람성분 | m/s |
REH |
습도 | % |
PTY |
강수형태 | code |
LGT |
낙뢰 | code |
VEC |
풍향 | deg |
WSD |
풍속 | m/s |
단기예보입니다. 대략 3일 범위의 예보 항목을 반환합니다.
| 항목 | 값 |
|---|---|
| public method | KmaClient.forecast() |
| 발표시각 | 0200, 0500, 0800, 1100, 1400, 1700, 2000, 2300 |
| 조회 가능 | 발표 후 약 10분 |
| 시간 필드 | baseDate, baseTime, fcstDate, fcstTime |
| 값 필드 | fcstValue |
| 반환 모델 | list[ForecastItem] |
대표 category:
| 코드 | 의미 | 단위/형식 |
|---|---|---|
TMP |
1시간 기온 | C |
TMN |
일 최저기온 | C |
TMX |
일 최고기온 | C |
UUU |
동서바람성분 | m/s |
VVV |
남북바람성분 | m/s |
VEC |
풍향 | deg |
WSD |
풍속 | m/s |
SKY |
하늘상태 | code |
PTY |
강수형태 | code |
POP |
강수확률 | % |
WAV |
파고 | m |
PCP |
1시간 강수량 | 숫자 또는 범주 문자열 |
SNO |
1시간 신적설 | 숫자 또는 범주 문자열 |
예보 버전 정보를 조회합니다.
| 파라미터 | 설명 |
|---|---|
ftype |
예보 타입 |
basedatetime |
기준일시 문자열 |
초기 구현에서는 raw mapping을 반환합니다. 안정적인 사용례가 쌓이면 별도 모델을 추가할 수 있습니다.
cutoff = now_kst - timedelta(minutes=40)
base_time = cutoff.replace(minute=0, second=0, microsecond=0)예시:
| 현재 KST | 선택 base |
|---|---|
2026-04-30 14:35 |
20260430 1300 |
2026-04-30 14:45 |
20260430 1400 |
cutoff = now_kst - timedelta(minutes=15)
if cutoff.minute >= 30:
base = HH30
else:
base = previous_hour_HH30예시:
| 현재 KST | 선택 base |
|---|---|
2026-04-30 14:44 |
20260430 1330 |
2026-04-30 14:50 |
20260430 1430 |
발표시각 후보:
[2, 5, 8, 11, 14, 17, 20, 23]현재시각에서 10분을 뺀 뒤, 그 시각보다 작거나 같은 가장 최근 발표시각을 고릅니다. 후보가 없으면 전날 23:00을 사용합니다.
KMA 격자는 LCC DFS 좌표입니다.
라이브러리 public API에서는 외부 프로그램이 좌표계를 섞지 않도록 다음 값 객체를 제공합니다.
from kma import GridPoint, LatLon, normalize_location
LatLon(37.5665, 126.9780).to_grid() # GridPoint(nx=60, ny=127)
GridPoint(60, 127).to_latlon() # 격자 중심에 가까운 WGS84 좌표
normalize_location({"latitude": 37.5665, "longitude": 126.9780})
normalize_location({"nx": 60, "ny": 127})LatLon은 WGS84(EPSG:4326) 위도/경도입니다.GridPoint는 KMA DFS 격자 좌표입니다.nx/ny를 위도/경도로 해석하지 않습니다.location=입력은lat/lon또는nx/ny와 섞어 쓰지 않습니다.
상수:
RE = 6371.00877
GRID = 5.0
SLAT1 = 30.0
SLAT2 = 60.0
OLON = 126.0
OLAT = 38.0
XO = 43
YO = 136검증점:
| 위치 | WGS84 | nx, ny |
|---|---|---|
| 서울시청 | 37.5665, 126.9780 |
60, 127 |
| 부산시청 | 35.1796, 129.0756 |
98, 76 |
| 제주시청 | 33.4996, 126.5312 |
53, 38 |
| 강남역 | 37.4979, 127.0276 |
61, 125 |
코드 식별자는 외부 프로그램에서 문자열 오타를 줄일 수 있도록 public enum으로도 제공합니다.
from kma import KmaEndpoint, WeatherCategory, label_for, unit_for
unit_for(WeatherCategory.TEMPERATURE) # "C"
label_for(WeatherCategory.SKY, "1") # "맑음"
label_for(WeatherCategory.PRECIPITATION_TYPE, "4", endpoint=KmaEndpoint.VILAGE_FCST)WeatherCategory와 KmaEndpoint는 KMA wire value를 그대로 담은 str enum입니다. 알 수 없는 새 category는 모델에서 문자열 원문으로 보존합니다.
| 코드 | 라벨 |
|---|---|
1 |
맑음 |
3 |
구름많음 |
4 |
흐림 |
| 코드 | 라벨 |
|---|---|
0 |
없음 |
1 |
비 |
2 |
비/눈 |
3 |
눈 |
5 |
빗방울 |
6 |
빗방울눈날림 |
7 |
눈날림 |
| 코드 | 라벨 |
|---|---|
0 |
없음 |
1 |
비 |
2 |
비/눈 |
3 |
눈 |
4 |
소나기 |
PCP, SNO는 숫자가 아닐 수 있습니다.
예시:
강수없음적설없음1.0mm 미만30.0~50.0mm50.0mm 이상
라이브러리 정책:
ForecastItem.value에는 원문 문자열을 보존합니다.parse_amount()는 대표값이 필요할 때만 사용합니다.- 범위는 midpoint, 미만은 절반, 이상은 하한값을 반환합니다.
정상 JSON 구조:
{
"response": {
"header": {
"resultCode": "00",
"resultMsg": "NORMAL_SERVICE"
},
"body": {
"items": {
"item": []
}
}
}
}구현 규칙:
header.resultCode가00(정상)·03(NO_DATA, 빈 결과) 외이면 typed exception을 raise합니다.resultCode == "03"(NO_DATA)은 오류가 아니라 "조회 결과 없음"이므로 빈 결과(body.items.item =[], totalCount = 0)로 정규화합니다.- JSON을 요청해도 HTTP 200 본문이
OpenAPI_ServiceResponseXML 오류 envelope로 올 수 있습니다. 이때returnReasonCode또는resultCode를 같은 표로 분류하며, XML의03도 JSON과 동일한 빈 결과입니다. items.item이 dict 하나로 오면 list로 감쌉니다.items.item이 없거나 예상과 다르면KmaParseError입니다.
| 코드 | 의미 | 처리 |
|---|---|---|
00 |
NORMAL_SERVICE | 성공 |
03 |
NODATA_ERROR | 빈 결과로 정규화 (items 없음, totalCount=0) |
04 |
HTTP_ERROR | KmaServerError |
12 |
NO_OPENAPI_SERVICE_ERROR | KmaRequestError |
20 |
SERVICE_ACCESS_DENIED_ERROR | KmaAuthError |
22 |
LIMITED_NUMBER_OF_SERVICE_REQUESTS_EXCEEDS_ERROR | KmaRequestError(failure_kind="quota", retryable=False) |
30 |
SERVICE_KEY_IS_NOT_REGISTERED_ERROR | KmaAuthError |
31 |
DEADLINE_HAS_EXPIRED_ERROR | KmaAuthError |
99 |
UNKNOWN_ERROR | KmaServerError |
-
serviceKey는 Decoding 키 기준으로params=에 전달한다. -
dataType=JSON을 기본으로 보낸다. - API별 base time helper를 사용한다.
- 모든 datetime은 KST aware로 만든다.
-
lat/lon과nx/ny를 동시에 받지 않는다. -
PCP/SNO를 무조건 float로 변환하지 않는다. -
PTY매핑은 endpoint-aware로 처리한다. - 실제 네트워크 호출 없는 단위 테스트를 먼저 작성한다.