공공데이터포털 OpenAPI 인증키 오류 정리: 30 "등록되지 않은 서비스키", 20 "서비스 접근거부", 12 "서비스가 없거나 폐기됨"
공공데이터포털 OpenAPI 오류 30 SERVICE_KEY_IS_NOT_REGISTERED_ERROR, 20 SERVICE_KEY_IS_NULL, 12 NO_OPENAPI_SERVICE_ERROR를 가짜 키로 직접 재현해 정리했습니다.
n8n이나 curl로 공공데이터포털(data.go.kr) 오픈 API를 호출했는데 SERVICE_KEY_IS_NOT_REGISTERED_ERROR, SERVICE_KEY_IS_NULL, NO_OPENAPI_SERVICE_ERROR 같은 XML이 돌아왔다면, 오류 코드(20, 30, 12)가 원인을 가른다. 가짜 서비스키로 기상청 초단기실황 조회 API를 호출해 실제 응답을 비교했습니다. 진짜 인증키는 쓰지 않았고 읽기 전용 GET만 보냈습니다.
세 가지 응답
| 상황 | HTTP | 코드(returnReasonCode) | errMsg | returnAuthMsg |
|---|---|---|---|---|
| 서비스키를 보내지 않음 | 401 | 20 | SERVICE_KEY_IS_NULL | 서비스 접근거부 |
| 가짜 서비스키 | 403 | 30 | SERVICE_KEY_IS_NOT_REGISTERED_ERROR | 등록되지 않은 서비스키 |
| 없는 서비스 경로 | 400 | 12 | NO_OPENAPI_SERVICE_ERROR | 해당 오픈API 서비스가 없거나 폐기됨 |
응답은 OpenAPI_ServiceResponse 안의 cmmMsgHeader에 담겨 왔습니다. HTTP 상태 코드도 달랐지만(401, 403, 400), 원인을 가르는 것은 본문의 코드와 메시지였습니다.
직접 시험한 결과
2026년 11월 7일에 기상청 초단기실황 조회 API(apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getUltraSrtNcst)에 읽기 전용 GET을 보내 결과입니다. 모든 키는 지어낸 값입니다.
| 보낸 것 | HTTP, 코드 |
|---|---|
| 서비스키 없음 | 401, 20 (SERVICE_KEY_IS_NULL) |
값이 비어 있는 serviceKey= | 401, 20 |
가짜 키를 serviceKey로 | 403, 30 |
같은 가짜 키를 servicekey, ServiceKey로 | 403, 30 (대소문자를 구분하지 않음) |
같은 가짜 키를 service_key, key로 | 401, 20 (키를 보내지 않은 것과 같음) |
가짜 키에 +, /, = 포함 | 403, 30 |
가짜 키 + 필수 값(base_date 등) 빠짐 | 403, 30 (필수 값 오류가 아니라 키 오류가 먼저) |
가짜 키 + dataType=JSON | 403, 30 (오류도 JSON으로 옴) |
가짜 키, http://로 호출 | 403, 30 (연결이 막히지 않고 같은 응답) |
| 없는 경로 + 가짜 키 | 400, 12 |
- 파라미터 이름이 틀리면 "키를 보내지 않음(20)"으로 처리되었습니다.
service_key나key로 보내면 키가 틀린 것이 아니라 아예 없는 것으로 보였습니다. 반대로 대소문자는 상관없었습니다. - 필수 값이 빠져도 키 오류(30)가 먼저 나왔습니다. 30이 나오면 파라미터보다 키부터 의심해야 합니다. 키가 맞는 뒤에야 필수 값 오류가 나올 것으로 보이지만, 진짜 키가 없어 직접 확인하지는 못했습니다.
dataType=JSON을 주면 오류 응답도 JSON으로 왔습니다.dataType없이 보냈을 때는 오류가 XML로 왔습니다(제 시험). 공공데이터포털 API 상세 페이지 한 곳에도 "Default: XML"로 적혀 있었지만 시험한 API의 페이지는 아니었습니다. JSON으로 파싱하는 노드에 XML 오류가 들어오면 "파싱 오류"로 보일 수 있습니다.- 키에
+,/,=가 들어 있어도 가짜 키는 똑같이 30이었습니다. 인코딩된 키와 디코딩된 키 중 어느 쪽이 맞는지는 진짜 키가 있어야 시험할 수 있어서 이번에 확인하지 못했습니다.
공식 FAQ가 설명하는 것
공공데이터포털 FAQ는 세 코드를 이렇게 설명합니다.
- 12 (NO_OPENAPI_SERVICE_ERROR): 호출하려는 API 서비스가 존재하지 않거나 폐기된 경우.
- 20 (SERVICE_ACCESS_DENIED_ERROR): 해당 API 서비스를 신청하지 않았거나, 변경신청 등으로 인해 일시 중지된 경우.
- 30 (SERVICE_KEY_IS_NOT_REGISTERED_ERROR): 잘못된 인증키를 사용하거나, 서비스 신청이 정상 완료되지 않아 등록되지 않은 경우.
같은 코드 20이여도 원인이 두 가지로 보일 수 있습니다. 제 시험에서 20은 "서비스키를 보내지 않음"(SERVICE_KEY_IS_NULL)일 때 나왔고, FAQ는 20을 "신청하지 않음 또는 일시 중지"로 설명합니다. 신청을 안 했거나 일시 중지된 경우의 응답은 진짜 키가 없어 시험하지 못했습니다. 또 FAQ는 제공 기관 API마다 별도의 에러 메시지가 나올 수 있다고 안내합니다.
점검 순서
- 20,
SERVICE_KEY_IS_NULL: 서비스키가 요청에 실제로 들어 갔는지 봅니다. 파라미터 이름이serviceKey인지(대소문자는 무관), 값이 비어 있지 않은지 확인합니다. n8n에서는 쿼리 파라미터 칸이 실제 값으로 채워진 상태인지 봅니다. - 30,
SERVICE_KEY_IS_NOT_REGISTERED_ERROR: 키가 등록되어 있지 않다는 뜻입니다. FAQ가 드는 대로 잘못된 키인지, 신청이 정상 완료되었는지 확인합니다. 필수 값보다 키를 먼저 봅니다. - 12,
NO_OPENAPI_SERVICE_ERROR: 호출 주소(서비스 이름과 작업 이름)에 오타가 없는지 확인합니다. - JSON으로 받는 워크플로우라면 응답 형식을 정하는
dataType파라미터를 보내고, 오류가 XML로 와도 파싱이 깨지지 않게 응답 본문을 먼저 확인합니다. - 서비스키는 주소에 들어가는 값이라 로그나 글, 대화창에 붙이지 마세요. 이 시험에서
http://로도 같은 응답이 왔으므로 가능하면https://를 쓰세요.
비슷한 구조의 다른 오류는 네이버·카카오 API 인증 오류와 OpenAI·Anthropic API 키 오류도 정리했습니다.
시험하지 못한 것
- 진짜 인증키를 쓰지 않았습니다. 그래서 성공 응답, 신청 미완료와 일시 중지에 해당하는 오류, 호출 한도 초과, 기한 만료, 등록되지 않은 IP 오류는 확인하지 못했습니다.
- 하나의 API(기상청 초단기실황 조회)만 시험했습니다. 다른 제공 기관 API는 자체 오류 메시지를 낼 수 있습니다.
- 공공데이터포털 화면에서 인증키를 발급하고 확인하는 메뉴 경로는 확인하지 못해 적지 않았습니다. FAQ에 첨부된 에러 코드 파일도 열어 보지 못했습니다.
- n8n 화면에서 이 오류가 어떻게 보이는지는 확인하지 않았습니다(curl로만 시험).
- 하루 동안의 시험이고, 서비스가 메시지를 바꿀 수 있습니다.
출처 공공데이터포털 FAQ, OpenAPI 에러 코드. 응답 문구와 표의 결과는 제가 2026년 11월 7일에 보낸 요청의 결과입니다.
수정: 2026년 11월 7일