> ## 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.

# 인보이스와 결제 상태 검색

> customer_id, month, from/to(확정 시각, 날짜 종료일 포함/KST), status, mode, min_amount, max_amount, billable_metric_code, q, sort(month/customer_name/total_amount/finalized_at/invoice_number/status), order, page, size를 받는다. mode 기본은 현재 결제 설정이다. 조건 전체 금액과 결제 상태 건수는 페이지와 독립이며 pending이 있으면 outstanding_amount는 null이다. summary는 mode, invoice_count, supply_amount, tax_amount, total_amount, canceled_amount, has_pending, outstanding_amount, status_counts(결제 상태별 건수)다. from과 to는 한쪽만 줘도 되고 month와 함께 주면 둘 다 만족하는 인보이스만 나온다. 이벤트 목록과 내보내기는 from과 to를 함께 요구한다.



## OpenAPI

````yaml https://raw.githubusercontent.com/asm17-ms2/meterengine/main/backend/openapi.yaml get /v1/invoices/search
openapi: 3.1.0
info:
  description: |
    사용량 기반 과금 플랫폼의 API. 사용량 이벤트를 수집하고, 고객별 월 사용량과 청구 예정액을 조회한다.

    요청마다 Authorization 헤더에 Bearer 값으로 API 키(me_live_ 또는 me_test_로 시작)나
    로그인 세션 토큰을 싣는다. 도입사는 키나 세션이 정한다. 헤더가 없으면 401이다.

    X-MeterEngine-Environment: test 또는 live로 업무 환경을 지정한다. 새 키는 발급 환경에 고정된다.
    기존 데이터와 키는 환경 미지정 범위로 보존하며 자동으로 test/live에 배정하지 않는다.
    환경 분리가 지원되지 않는 업무는 명시 환경 요청에 409를 반환한다.
    X-MeterEngine-Organization-Id: 화면의 도입사를 고정하는 선택 UUID 헤더다.
    인증된 도입사와 다르면 403이며 이 헤더로 인증이나 도입사 전환을 대신할 수 없다.

    오류 응답은 code, message, errors로 이뤄진다. 오류별 처리는 code로 분기한다. message는
    code마다 하나인 한국어 문구이고, errors는 틀린 필드를 짚을 수 있는 400에만 실린다.
  title: MeterEngine API
  version: v1
servers:
  - description: MeterEngine API
    url: https://meterengine.com
security:
  - bearerAuth: []
tags:
  - name: organization-environment-controller
    x-group: 업무 환경
  - name: current-organization-controller
    x-group: 도입사 정보
  - name: api-key-controller
    x-group: API 키 (콘솔 전용)
  - name: organization-people-controller
    x-group: 구성원과 초대 (콘솔 전용)
  - name: audit-log-controller
    x-group: 감사 기록 (콘솔 전용)
  - name: billable-metric-controller
    x-group: 미터
  - name: billable-metric-price-controller
    x-group: 미터별 단가 조회
  - name: price-rate-controller
    x-group: 단가
  - name: price-plan-controller
    x-group: 요금제
  - name: customer-controller
    x-group: 고객
  - name: event-controller
    x-group: 이벤트
  - name: event-batch-controller
    x-group: 이벤트 일괄 전송
  - name: event-export-controller
    x-group: 이벤트 내보내기
  - name: billable-metric-usage-controller
    x-group: 사용량 집계
  - name: event-issue-controller
    x-group: 이벤트 매핑 진단
  - name: event-rejection-controller
    x-group: 수집 거절
  - name: unbilled-event-controller
    x-group: 청구 제외 사용량
  - name: dashboard-controller
    x-group: 개요
  - name: workspace-query-controller
    x-group: 검색과 내보내기
  - name: draft-invoice-controller
    x-group: 청구 예정액
  - name: invoice-controller
    x-group: 인보이스
  - name: invoice-view-link-controller
    x-group: 인보이스 조회 링크
  - name: payment-setting-controller
    x-group: 결제 설정
  - name: toss-payments-credential-controller
    x-group: 토스페이먼츠 키
  - name: payment-method-registration-controller
    x-group: 카드 등록 링크
  - name: payment-method-controller
    x-group: 결제 수단
  - name: payment-attempt-controller
    x-group: 결제 요청
  - name: invoice-payment-controller
    x-group: 수납 상태
  - name: payment-cancellation-controller
    x-group: 결제 취소
  - name: payment-reconciliation-mismatch-controller
    x-group: 대사 불일치
  - name: toss-payments-webhook-controller
    x-group: 토스페이먼츠 웹훅 수신
  - name: webhook-endpoint-controller
    x-group: 웹훅
paths:
  /v1/invoices/search:
    get:
      tags:
        - workspace-query-controller
      summary: 인보이스와 결제 상태 검색
      description: >-
        customer_id, month, from/to(확정 시각, 날짜 종료일 포함/KST), status, mode,
        min_amount, max_amount, billable_metric_code, q,
        sort(month/customer_name/total_amount/finalized_at/invoice_number/status),
        order, page, size를 받는다. mode 기본은 현재 결제 설정이다. 조건 전체 금액과 결제 상태 건수는 페이지와
        독립이며 pending이 있으면 outstanding_amount는 null이다. summary는 mode,
        invoice_count, supply_amount, tax_amount, total_amount, canceled_amount,
        has_pending, outstanding_amount, status_counts(결제 상태별 건수)다. from과 to는
        한쪽만 줘도 되고 month와 함께 주면 둘 다 만족하는 인보이스만 나온다. 이벤트 목록과 내보내기는 from과 to를 함께
        요구한다.
      operationId: searchInvoices
      parameters:
        - in: query
          name: q
          schema:
            type: string
            maxLength: 2000
        - in: query
          name: sort
          schema:
            type: string
            maxLength: 2000
        - in: query
          name: order
          schema:
            type: string
            enum:
              - asc
              - desc
        - in: query
          name: page
          schema:
            type: integer
            default: 1
            maximum: 2147483647
            minimum: 1
        - in: query
          name: size
          schema:
            type: integer
            default: 25
            maximum: 200
            minimum: 1
        - in: query
          name: month
          schema:
            type: string
            example: 2026-08
            pattern: ^[0-9]{4}-(0[1-9]|1[0-2])$
        - in: query
          name: customer_id
          schema:
            type: string
            format: uuid
        - in: query
          name: billable_metric_code
          schema:
            type: string
            maxLength: 2000
        - in: query
          name: from
          schema:
            type: string
            maxLength: 2000
        - in: query
          name: to
          schema:
            type: string
            maxLength: 2000
        - in: query
          name: status
          schema:
            type: string
            maxLength: 2000
        - in: query
          name: mode
          schema:
            type: string
            enum:
              - test
              - live
        - in: query
          name: min_amount
          schema:
            type: integer
            format: int64
            minimum: 0
        - in: query
          name: max_amount
          schema:
            type: integer
            format: int64
            minimum: 0
      responses:
        '200':
          content:
            '*/*':
              schema:
                $ref: '#/components/schemas/SearchPageResponseInvoiceSearchResponse'
          description: 조건에 맞는 페이지. total은 조건 전체 건수다.
        '400':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: >-
            code=validation_error: 받지 않는 쿼리 파라미터가 있거나 값의 형식이나 범위가 틀렸다. 어느 값인지는
            errors에 있다.
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: |
            code=authentication_required: Authorization 헤더가 없다.
            code=invalid_credentials: 키나 토큰의 형식이 틀렸거나, 모르는 값이거나, 폐기 또는 만료됐다.
        '403':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: >
            code=permission_denied: 키의 스코프나 계정의 역할로는 할 수 없는 요청이거나, 도입사가 정해지지 않은
            로그인 세션이다.

            code=organization_not_active: 도입사가 활성 상태가 아니다.

            code=consent_required: 로그인 세션의 사용자가 필수 안내에 아직 동의하지 않았다. POST
            /v1/sessions/current/consents로 동의한다.
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: 'code=customer_not_found: customer_id의 고객이 현재 도입사와 업무 환경에 없다.'
        '429':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
          description: >-
            code=rate_limit_exceeded: 키의 분당 요청 한도를 넘었다. Retry-After 헤더의 초만큼 기다린
            뒤 다시 보낸다.
          headers:
            Retry-After:
              description: 다시 보내기 전에 기다릴 초
              required: true
              schema:
                type: integer
                format: int32
components:
  schemas:
    SearchPageResponseInvoiceSearchResponse:
      type: object
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/InvoiceSearchResponse'
        page:
          type: integer
          format: int32
        size:
          type: integer
          format: int32
        summary:
          type: object
          additionalProperties: {}
        total:
          type: integer
          format: int64
        total_unfiltered:
          type: integer
          format: int64
    ErrorResponse:
      type: object
      description: 오류 응답. code로 오류 종류를 구분하고, message는 code마다 하나인 한국어 문구다.
      properties:
        code:
          type: string
          description: 오류 종류. 오류별 처리는 이 값으로 분기한다.
          enum:
            - validation_error
            - malformed_request_body
            - invalid_billable_metric
            - invalid_price_rate
            - event_too_old
            - invalid_toss_payments_credential
            - payment_method_rejected
            - toss_payments_test_code_in_live_mode
            - invalid_webhook_url
            - invalid_webhook_event_type
            - authentication_required
            - invalid_credentials
            - permission_denied
            - organization_not_active
            - environment_mismatch
            - consent_required
            - customer_not_found
            - event_not_found
            - billable_metric_not_found
            - price_rate_not_found
            - invoice_not_found
            - invoice_view_link_not_found
            - endpoint_not_found
            - api_key_not_found
            - organization_not_found
            - user_account_not_found
            - payment_method_not_found
            - payment_method_registration_not_found
            - payment_attempt_not_found
            - toss_payments_credential_not_found
            - price_plan_not_found
            - webhook_endpoint_not_found
            - webhook_delivery_not_found
            - invitation_not_found
            - method_not_allowed
            - response_type_not_acceptable
            - resource_version_conflict
            - idempotency_conflict
            - customer_archived
            - resource_archived
            - environment_not_ready
            - archive_restoration_conflict
            - customer_has_events
            - customer_has_payment_attempts
            - billable_metric_has_events
            - billable_metric_has_price_rate
            - billable_metric_already_exists
            - billable_metric_event_type_target_property_already_exists
            - invoice_already_paid
            - payment_result_unconfirmed
            - payment_retry_unavailable
            - payment_retry_stale
            - invoice_amount_zero
            - email_already_exists
            - organization_status_transition_invalid
            - organization_member_already_exists
            - toss_payments_credential_missing
            - payment_method_missing
            - payment_mode_mismatch
            - payment_attempt_not_cancelable
            - payment_attempt_fully_canceled
            - payment_cancellation_amount_exceeded
            - payment_cancellation_in_progress
            - payment_cancellation_idempotency_conflict
            - webhook_delivery_not_retryable
            - price_rate_history_immutable
            - price_plan_history_immutable
            - webhook_endpoint_disabled
            - webhook_endpoint_limit_exceeded
            - invitation_unavailable
            - last_owner_required
            - owner_scopes_required
            - last_operator_required
            - api_key_unavailable
            - upload_size_exceeded
            - request_type_not_supported
            - rate_limit_exceeded
            - internal_server_error
            - request_timed_out
            - toss_payments_unavailable
        errors:
          type: array
          description: 틀린 필드 목록. 400 응답에만 실린다.
          items:
            $ref: '#/components/schemas/FieldError'
        message:
          type: string
          description: code마다 하나인 한국어 문구. 예고 없이 바뀔 수 있으니 분기에 쓰지 않는다.
          example: 서버 내부 오류입니다
      required:
        - code
        - message
    InvoiceSearchResponse:
      type: object
      properties:
        invoice:
          $ref: '#/components/schemas/InvoiceResponse'
        payment:
          $ref: '#/components/schemas/InvoicePaymentResponse'
    FieldError:
      type: object
      description: 틀린 필드 하나
      properties:
        field:
          type: string
          description: 틀린 값을 보낸 자리의 이름. 요청에 쓴 이름과 같다.
          example: event_type
        message:
          type: string
          description: 이 자리의 값이 거절된 이유.
          example: 공백일 수 없습니다
    InvoiceResponse:
      type: object
      properties:
        customer_id:
          type: string
          format: uuid
        customer_name:
          type: string
        cutoff_at:
          type: string
          format: date-time
          description: 확정이 읽은 이벤트의 받은 시각 상한. 그 달에 발생했고 이 시각 전에 받은 이벤트만 금액에 들었다. KST(+09:00)
        finalized_at:
          type: string
          format: date-time
        id:
          type: string
          format: uuid
        invoice_number:
          type: string
          description: 고객에게 표시하는 안정적인 인보이스 번호. 세금계산서나 영수증 번호가 아니다
        lines:
          type: array
          items:
            $ref: '#/components/schemas/InvoiceLineResponse'
        month:
          type: string
        supply_amount:
          type: integer
          format: int64
        tax_amount:
          type: integer
          format: int64
        total_amount:
          type: integer
          format: int64
    InvoicePaymentResponse:
      type: object
      properties:
        amount:
          type: integer
          format: int64
          description: 인보이스의 total_amount. 원 단위 정수
        attempt_count:
          type: integer
          format: int64
          description: 현재 결제 모드로 이 인보이스에 한 결제 시도 수
        canceled_amount:
          type: integer
          format: int64
          description: 결제된 시도에서 취소를 마친 금액의 합. 결제된 시도가 아니면 0이다
        completed_at:
          type: string
          format: date-time
          description: 가장 늦게 요청한 시도의 completed_at. 시도가 없거나 pending이면 null이다
        invoice_id:
          type: string
          format: uuid
        last_failure_code:
          type: string
          description: 가장 늦게 요청한 시도가 failed일 때만 있다. 그 시도의 failure_code다
        mode:
          type: string
          description: 상태를 정한 결제 모드. 조회한 때 도입사의 결제 모드다
          enum:
            - test
            - live
        next_retry_at:
          type: string
          format: date-time
          description: >-
            가장 늦게 요청한 시도가 failed이고, 실패 코드가 다시 시도할 대상이며, 시도 수가 상한보다 적을 때만 있다. 카드
            오류처럼 다시 시도하지 않는 코드여도 그 시도가 끝난 뒤 고객이 카드를 다시 등록했으면 다시 시도할 대상이고,
            ALREADY_REMOVED_BILLING_KEY는 지금 등록 카드가 있으면 대상이다. NOT_FOUND_PAYMENT는
            그 시도가 끝난 지 7일 안일 때만 대상이다. 그 시도의 completed_at에 재시도 간격을 더한 시각이다
        status:
          type: string
          description: >-
            현재 결제 모드의 가장 늦게 요청한 시도로 정한 결제 상태. total_amount가 0원이면 not_required,
            시도가 없으면 unpaid, 시도가 pending이면 pending, failed면 failed, done이면 취소한 합에
            따라 paid, partially_canceled, canceled다
          enum:
            - not_required
            - unpaid
            - pending
            - paid
            - failed
            - partially_canceled
            - canceled
    InvoiceLineResponse:
      type: object
      properties:
        amount:
          type: integer
          format: int64
        billable_metric_code:
          type: string
        billable_metric_name:
          type:
            - string
            - 'null'
          description: >-
            확정할 때의 미터 이름. 미터 이름을 나중에 바꿔도 그대로다. 기본료와 최소 사용료 조정 줄, 이 값을 저장하기 전에
            확정한 줄은 null이다
        dimension_values:
          type: object
          additionalProperties: {}
          description: >-
            확정할 때 저장한 조합. 이 조합의 단가를 수량에 곱했다. 미터에 dimension_properties가 없었으면 빈
            객체다
        line_type:
          type: string
          enum:
            - per_unit
            - volume
            - graduated_tier
            - base_fee
            - minimum_adjustment
        quantity:
          type: number
          description: 표시용 수량. 금액 계산에는 quantity_numerator/quantity_denominator를 사용한다
        quantity_denominator:
          type: number
          description: 정확 청구 수량의 양수 분모. 분자/분모에 단가를 곱해 라인별 10원 미만을 버린다
        quantity_numerator:
          type: number
          description: 금액과 구간 판정에 사용한 정확 청구 수량의 분자
        target_property:
          type: string
        tier_index:
          type: integer
          format: int32
        unit_price:
          type: number
  securitySchemes:
    bearerAuth:
      scheme: bearer
      type: http

````

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