> ## Documentation Index
> Fetch the complete documentation index at: https://docs.meterengine.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 이벤트가 청구에 안 보일 때

> 보낸 사용량이 사용량이나 청구 예정액에 나오지 않을 때 원인을 찾는 순서와 증상별 조치를 정리했습니다.

보낸 사용량이 청구 예정액에 보이지 않으면 이벤트가 어느 단계에서 멈췄는지부터 찾습니다. 수집 요청이 거절됐는지, 저장은 됐지만 사용량으로 집계되지 않았는지, 사용량은 있지만 단가가 붙지 않았는지에 따라 원인과 조치가 다릅니다. 정상적인 확인 순서는 [보낸 데이터 확인하기](https://docs.meterengine.com/integration/verify-usage.md)를 보세요.

## 진단 순서

**1. 수집 응답을 본다**

`POST /v1/events`나 `POST /v1/event-batches`의 HTTP 상태와 응답 본문의 `code`를 확인합니다. 단건이 200이 아니거나 배치 결과의 원소가 `rejected`면 그 이벤트는 저장되지 않았습니다. 배치 요청 자체가 400이면 그 요청의 이벤트는 하나도 저장되지 않았습니다. 아래 '수집 요청이 거절됐다' 표를 봅니다.

**2. 업무 환경을 맞춘다**

콘솔 화면 위 '업무 환경'이 API 키를 발급한 환경과 같은지 확인합니다. 로그인하면 '기존 데이터'로 열리므로, 테스트 환경 키로 보냈다면 '테스트 환경'으로 바꿔야 보입니다. 자세한 내용은 [업무 환경](https://docs.meterengine.com/concepts/environments.md)을 보세요.

**3. 저장됐는지 본다**

'수집 로그' 화면에서 전송 ID로 찾거나 `GET /v1/events/lookup?transaction_id=값`을 부릅니다. 없으면 '수집 거절' 화면을 봅니다.

**4. 사용량으로 집계됐는지 본다**

'사용량' 화면의 '수집 확인과 정정'에서 청구에서 빠지는 이벤트 건수를 보고, '이벤트 매핑 진단'에서 이벤트별 원인을 봅니다.

**5. 금액이 붙었는지 본다**

'청구 검토' 화면이나 `GET /v1/invoices/draft?month=YYYY-MM`에서 라인과 단가 없는 사용량을 봅니다.

**6. 이미 확정됐는지 본다**

고객이 청구 예정액에서 사라졌으면 '확정 인보이스' 화면이나 `GET /v1/invoices`를 봅니다.

## 증상별 원인과 조치

### 수집 요청이 거절됐다

| 증상 | 확인할 곳 | 원인 | 조치 |
| - | - | - | - |
| 단건 요청이 400 `malformed_request_body` | 응답 본문뿐입니다. '수집 거절'에 남지 않습니다 | 본문을 JSON으로 읽지 못했거나 필드 값을 그 형식으로 읽지 못했습니다. 예를 들어 `customer_id`에 UUID가 아닌 값(외부 고객 ID 등)을 넣거나 `timestamp`에 오프셋을 붙이지 않으면 이 응답이 옵니다 | 본문을 고쳐 다시 보냅니다. `customer_id`에는 고객 등록 응답의 `id`(UUID)를 넣고 `timestamp`에는 `+09:00`이나 `Z` 같은 오프셋을 붙입니다 |
| 단건 요청이 400 `validation_error` | 응답의 `errors[].field`뿐입니다. '수집 거절'에 남지 않습니다 | 필수 필드가 없거나 값이 허용 범위를 벗어났습니다 | `errors`가 짚은 필드를 고쳐 다시 보냅니다 |
| 배치 요청 전체가 400 `validation_error`나 `malformed_request_body` | 응답 본문뿐입니다. '수집 거절'에 남지 않습니다 | `events`가 없거나 비었거나 100건을 넘었거나, 본문을 JSON으로 읽지 못했습니다 | 한 요청에 1건에서 100건까지 담아 다시 보냅니다 |
| 배치 결과 원소의 `result`가 `rejected`, `error.code`가 `validation_error` | 응답의 `results[].error`, '수집 거절'의 '요청 항목 확인 필요' | 그 원소의 필드가 없거나 형식이 틀렸습니다 | 그 원소만 고쳐 다시 보냅니다 |
| 404 `customer_not_found` | '수집 거절'의 '고객을 찾을 수 없음' | 고객을 등록하지 않았거나 다른 업무 환경의 고객 id를 넣었습니다 | 키와 같은 업무 환경에 고객을 등록하고 같은 `transaction_id`로 다시 보냅니다 |
| 409 `customer_archived` | '수집 거절'의 '보관된 고객' | 고객을 보관했습니다 | 청구할 고객이면 '고객' 화면의 '고객 복원'이나 admin 권한 키의 `POST /v1/customers/{id}/restorations`로 복원한 뒤 같은 `transaction_id`로 다시 보냅니다 |
| 400 `event_too_old` | '수집 거절'의 '수집 가능 기간 초과' | `timestamp`가 받는 시각보다 35일 넘게 과거입니다 | 같은 이벤트를 다시 보내도 받지 않습니다. 이 사용량을 청구할 방법은 없습니다 |
| 401, 403, 429 | 응답의 `code` | 인증, 권한, 분당 요청 한도 문제입니다. 이벤트 전송에는 ingest 권한이 필요합니다 | [오류 응답과 X-Request-ID](https://docs.meterengine.com/api-basics/errors.md)와 [요청 한도와 429](https://docs.meterengine.com/api-basics/rate-limits.md)를 보세요 |

배치는 HTTP 상태가 200이어도 원소마다 결과가 다릅니다. 원소별 결과를 읽는 방법과 다시 보낼 것과 멈출 것은 [사용량 이벤트 보내기](https://docs.meterengine.com/integration/events.md)와 [재전송 설계](https://docs.meterengine.com/integration/retries.md)를 보세요. 영구 거절 code는 다시 보내지 마세요.

### 저장됐는데 보이지 않는다

| 증상 | 확인할 곳 | 원인 | 조치 |
| - | - | - | - |
| 200에 `"duplicate": true`인데 고친 값이 반영되지 않았다 | `GET /v1/events/lookup?transaction_id=값` | 같은 `transaction_id`로 다시 보내면 처음 저장한 이벤트를 그대로 두고 새 본문은 버립니다 | 저장된 이벤트는 바뀌지 않습니다. 아래 경고를 보세요 |
| 200을 받았는데 '수집 로그'에 없다 | 화면 위 '업무 환경', '조회 월' | 콘솔이 다른 업무 환경을 보고 있거나, 이벤트의 발생 시각이 다른 달입니다 | 키를 발급한 업무 환경으로 바꾸고, `timestamp`가 속한 KST 달을 고릅니다 |

> [!WARNING]
>
> 보낸 이벤트는 고치거나 지울 수 없습니다. 같은 `transaction_id`로 다시 보내도 처음 것이 남습니다. 집계 방식에 따라 확정 전에 바로잡을 수 있는 경우가 있으니 [사용량 이벤트 보내기](https://docs.meterengine.com/integration/events.md)의 정정 방법을 보세요.

### 사용량이 0이거나 적다

| 증상 | 확인할 곳 | 원인 | 조치 |
| - | - | - | - |
| '수집 로그'에는 있는데 사용량이 0이다 | '수집 확인과 정정'의 '미터와 연결되지 않은 유형', '이벤트 매핑 진단'의 '연결할 미터 없음', `GET /v1/unbilled-events`의 `unmatched_type` | 이벤트의 `type`을 세는 미터가 없거나 `type` 철자가 미터의 이벤트 유형과 다릅니다 | 그 `type`을 세는 미터를 등록합니다. 미터를 만들면 이미 저장된 그 `type`의 이벤트도 집계됩니다. 미터를 바꿀 수 있는 조건은 [미터 설계](https://docs.meterengine.com/pricing/meters.md)를 보세요 |
| 미터는 있는데 사용량이 0이거나 적다 | '집계할 수 없는 속성', '이벤트 매핑 진단'의 '집계할 수량 확인 필요', `non_numeric_value` | 미터가 세는 속성(`target_property`)이 이벤트에 없거나 형식이 맞지 않습니다. `count`는 값을 보지 않고, `count_distinct`는 숫자, 문자열, 불리언 값만 셉니다. 그 밖의 집계는 JSON 숫자만 셉니다. `"1234"`처럼 문자열로 보낸 숫자는 세지 않습니다 | 이후 이벤트는 그 속성을 맞는 형식으로 보냅니다. 이미 저장된 이벤트는 바뀌지 않습니다 |
| 이벤트가 집계에 들지 않고 '미래 시각의 이벤트'에 잡혔다 | '수집 확인과 정정'의 '미래 시각의 이벤트', `future_timestamp` | 발생 시각이 지금보다 뒤입니다 | 그 시각이 오면 집계에 듭니다. 시각을 잘못 보냈다면 저장된 이벤트는 고칠 수 없으니 위 경고를 보세요 |
| 월말이나 월초 이벤트가 다른 달에 들었다 | '수집 로그'의 '발생 시각 (KST)' | 청구 월은 KST 기준 달력 월입니다. UTC 시각을 KST로 착각하면 9시간이 어긋납니다 | `timestamp`의 오프셋이 실제 시간대와 맞는지 확인하고 KST 달로 확인합니다. [시간 규칙](https://docs.meterengine.com/concepts/time-rules.md)을 보세요 |

### 사용량은 있는데 금액이 없거나 적다

| 증상 | 확인할 곳 | 원인 | 조치 |
| - | - | - | - |
| 사용량은 있는데 청구 예정액 라인에 없다 | '청구 검토'의 단가 없는 사용량, 청구 예정액의 `unpriced_usages`, '이벤트 매핑 진단'의 '적용 단가 없음' | 그 차원 속성 값 조합의 단가가 없습니다. 조합의 값은 글자까지 같아야 하고 다른 조합의 단가로 대신하지 않습니다 | 이번 달이면 그 조합의 단가를 '요금 설계' 화면이나 admin 권한 키의 `POST /v1/billable-metrics/{code}/price-rates`로 등록합니다. 지난달 단가는 넣을 수 없어(409 `price_rate_history_immutable`) 그 사용량은 청구되지 않습니다. [차원과 속성 조합](https://docs.meterengine.com/pricing/dimensions.md)을 보세요 |
| 라인 금액이 0원이거나 예상보다 10원 미만만큼 적다 | 청구 예정액 `lines[].amount` | 금액은 라인마다 10원 미만을 버립니다 | 단가와 미터의 `unit_size`를 확인합니다. [예정액, 확정액, 수납액](https://docs.meterengine.com/concepts/amounts.md)을 보세요 |
| 한 조합의 금액이 0원이고 라인에서 빠졌다 | 청구 예정액의 `negative_usages`, '개요'의 '음수 합계', '청구 검토' | 그 조합의 변환 전 집계량이 음수라 0원으로 보고 라인에서 뺐습니다 | 음수 값을 보낸 이벤트를 확인합니다. 정정 방법은 [사용량 이벤트 보내기](https://docs.meterengine.com/integration/events.md)를 보세요 |

### 지난달이나 확정한 달의 이벤트가 청구되지 않았다

| 증상 | 확인할 곳 | 원인 | 조치 |
| - | - | - | - |
| 지난달 이벤트가 200으로 저장됐는데 지난달 청구 예정액과 인보이스에 없다 | '수집 로그'를 '수신 시각'으로 정렬, 이벤트의 `received_at` | 다음 달 1일 13:00 KST 뒤에 받았습니다. 집계 마감 뒤에 받은 지난달 이벤트는 저장만 되고 청구되지 않습니다 | 청구할 방법은 없습니다. 재전송이 마감 전에 끝나도록 설계하세요. [재전송 설계](https://docs.meterengine.com/integration/retries.md)를 보세요 |
| 확정한 뒤 들어온 이벤트가 청구되지 않았다 | '확정 인보이스', 인보이스의 `cutoff_at`, '이벤트 매핑 진단'의 안내 문구 | 그 달 그 고객을 이미 확정했습니다. 인보이스에는 `cutoff_at` 전에 받은 이벤트만 들어 있습니다 | 확정한 인보이스는 되돌릴 수 없습니다. [확정 뒤 바뀌는 것과 안 바뀌는 것](https://docs.meterengine.com/billing/after-finalization.md)을 보세요 |
| '청구 검토'에서 고객이 사라졌다 | '확정 인보이스', `GET /v1/invoices` | 그 달 그 고객이 확정되어 청구 예정액에서 빠졌습니다 | 확정된 금액은 '확정 인보이스'에서 봅니다 |

## 놓치기 쉬운 것

> [accordion] '수집 거절'의 조회 월은 이벤트의 달이 아니다
>
> '수집 거절' 화면의 '거절 기록 월'과 `GET /v1/event-rejections/search`의 `month`는 거절을 기록한 달입니다. 10월 31일에 발생한 이벤트를 11월 1일에 보내 거절됐다면 11월에서 찾습니다. 화면에 나오는 '최초 거절 기록' 시각 전의 거절은 기록되어 있지 않습니다.

> [accordion] '수집 거절'에는 이벤트 원문이 없다
>
> 수집 거절 기록에는 전송 ID, 요청에 담긴 고객 ID, 이벤트 유형, 발생 시각, 거절 사유, 확인할 항목, 배치 행, 요청 ID, 거절 기록 시각만 남습니다. 원본 속성과 오류 원문은 남지 않습니다. 검색어는 전송 ID와 이벤트 유형만 찾고, '요청의 고객 ID'는 등록되지 않은 고객 ID로도 찾을 수 있습니다. 다시 보내려면 원문을 연동 쪽에 보관해 두어야 합니다.

> [accordion] 진단 검색의 페이지 번호는 0부터 센다
>
> `GET /v1/event-rejections/search`와 `GET /v1/event-issues/search`의 `page`는 0부터 세고, 고객이나 사용량 같은 자원의 `/search`는 1부터 셉니다. 자원별 규칙은 [서버 조회와 CSV 내보내기](https://docs.meterengine.com/reference/search-and-export.md)를 보세요.

> [accordion] '이벤트 매핑 진단'은 지금의 정의로 다시 계산한다
>
> '이벤트 매핑 진단'은 조회할 때의 미터 정의와 단가로 저장된 이벤트를 다시 진단합니다. 단가를 등록하면 그 조합의 '적용 단가 없음' 행은 사라집니다. 이미 확정한 달의 행에는 "인보이스를 확정한 달이라 단가를 등록해도 이 달 청구에는 반영되지 않습니다" 안내가 붙습니다.

> [accordion] 마감 뒤에 받은 이벤트를 세는 진단은 없다
>
> '이벤트 매핑 진단'과 청구 제외 집계(`GET /v1/unbilled-events`)는 발생 시각으로만 대상을 고르고 수신 시각은 보지 않습니다. 그래서 집계 마감 뒤에 받아 청구에서 빠진 지난달 이벤트를 따로 세는 항목이 없습니다. `GET /v1/events?month=YYYY-MM&sort=received_at&order=desc`로 수신 시각이 늦은 이벤트부터 보거나, 이벤트 CSV의 `received_at` 열로 확인하세요.

> [accordion] 수집 요청은 감사 기록에 나오지 않는다
>
> 이벤트 수집 요청은 감사 기록에 나오지 않으니 저장된 이벤트와 수집 거절 기록의 `request_id`, `transaction_id`로 찾습니다. '수집 거절'과 '이벤트 매핑 진단' 화면은 감사 기록에서 확인하라고 안내하지만 수집 요청은 감사 기록에 없습니다. 자세한 내용은 [오류 응답과 X-Request-ID](https://docs.meterengine.com/api-basics/errors.md)를 보세요.
>
> `malformed_request_body`나 단건 `validation_error`처럼 저장도 거절 기록도 되지 않는 오류는 응답 본문과 응답 헤더 `X-Request-ID`를 연동 쪽 로그에 남겨 두어야 나중에 찾을 수 있습니다.

## 미리 통보 받기

청구에서 빠지는 사용량이 있으면 웹훅 `unbilled_usage_detected`로 매일 통보를 받을 수 있습니다. 보내는 조건과 본문은 [웹훅 이벤트 유형과 data](https://docs.meterengine.com/webhooks/events.md)를 보세요. 예약 작업 시각은 [시간 규칙](https://docs.meterengine.com/concepts/time-rules.md)에 모았습니다.

## 그래도 원인을 모르겠다면

문의와 승인 요청 방법은 [소개 페이지의 문의 절](https://docs.meterengine.com/index.md)을 보세요. 문의할 때는 요청한 시각, 응답의 `code`, 응답 헤더 `X-Request-ID`, 이벤트의 `transaction_id`를 함께 적어 주세요. API 키와 고객 정보는 적지 마세요.

> [card] [보낸 데이터 확인하기](https://docs.meterengine.com/integration/verify-usage.md)
>
> 저장, 사용량, 청구 예정액 순서로 확인합니다.

> [card] [재전송 설계](https://docs.meterengine.com/integration/retries.md)
>
> 다시 보낼 오류와 멈출 오류를 나눕니다.

> [card] [서버 조회와 CSV 내보내기](https://docs.meterengine.com/reference/search-and-export.md)
>
> 한 달 치 이벤트를 내려받아 자기 기록과 맞춥니다.

> [card] [시간 규칙](https://docs.meterengine.com/concepts/time-rules.md)
>
> 35일, 집계 마감, 청구 월의 기준을 봅니다.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.