xdata-kr Product Catalog Plan Mapping API

The Product Catalog Plan Mapping API from xdata-kr — 2 operation(s) for product catalog plan mapping.

Operations 3

GET /v1/plans/{plan_id}/products List Plan Product Mappings #
POST /v1/plans/{plan_id}/products Create Plan Product Mappings #
DELETE /v1/plans/{plan_id}/products/{product_id} Delete Plan Product Mapping #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/xdata-kr:xdata-kr-product-catalog-plan-mapping-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

xdata-kr-product-catalog-plan-mapping-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: XBOSS Product Catalog Plan Mapping API
  description: '통합 REST API 서버 (홈택스 등). Human API guide: https://developer.xdata.kr · OpenAPI Reference: /docs'
  version: 2.0.0
security:
- basicClientCredential: []
- mcpOAuth2: []
tags:
- name: Product Catalog Plan Mapping
paths:
  /v1/plans/{plan_id}/products:
    get:
      tags:
      - Product Catalog Plan Mapping
      summary: List Plan Product Mappings
      operationId: list_plan_product_mappings_v1_plans__plan_id__products_get
      parameters:
      - name: plan_id
        in: path
        required: true
        schema:
          type: integer
          title: Plan Id
      - name: query
        in: query
        required: true
        schema:
          $ref: '#/components/schemas/PlanProductMappingListQuery'
      - name: env_scope
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: 환경을 고릅니다. 값은 production · real_test · sandbox 중 하나입니다. 경로 접두(/v1/sandbox/... · /v1/test/... · /v1/production/...) · X-Env-Scope 헤더 · env_scope 쿼리 가운데 한 통로로 반드시 보내야 합니다. 빼면 자동으로 채우지 않고 거절하며, 두 통로에 서로 다른 값을 담아도 거절합니다. 거절은 HTTP 422 이고 오류 코드는 VALIDATION_ENV_SCOPE_MISMATCH 입니다.
          enum:
          - production
          - real_test
          - sandbox
          title: Env Scope
        description: 환경을 고릅니다. 값은 production · real_test · sandbox 중 하나입니다. 경로 접두(/v1/sandbox/... · /v1/test/... · /v1/production/...) · X-Env-Scope 헤더 · env_scope 쿼리 가운데 한 통로로 반드시 보내야 합니다. 빼면 자동으로 채우지 않고 거절하며, 두 통로에 서로 다른 값을 담아도 거절합니다. 거절은 HTTP 422 이고 오류 코드는 VALIDATION_ENV_SCOPE_MISMATCH 입니다.
      - name: Authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: X-Env-Scope
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: 환경을 고릅니다. 값은 production · real_test · sandbox 중 하나입니다. 경로 접두(/v1/sandbox/... · /v1/test/... · /v1/production/...) · X-Env-Scope 헤더 · env_scope 쿼리 가운데 한 통로로 반드시 보내야 합니다. 빼면 자동으로 채우지 않고 거절하며, 두 통로에 서로 다른 값을 담아도 거절합니다. 거절은 HTTP 422 이고 오류 코드는 VALIDATION_ENV_SCOPE_MISMATCH 입니다.
          enum:
          - production
          - real_test
          - sandbox
          title: X-Env-Scope
        description: 환경을 고릅니다. 값은 production · real_test · sandbox 중 하나입니다. 경로 접두(/v1/sandbox/... · /v1/test/... · /v1/production/...) · X-Env-Scope 헤더 · env_scope 쿼리 가운데 한 통로로 반드시 보내야 합니다. 빼면 자동으로 채우지 않고 거절하며, 두 통로에 서로 다른 값을 담아도 거절합니다. 거절은 HTTP 422 이고 오류 코드는 VALIDATION_ENV_SCOPE_MISMATCH 입니다.
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PageEnvelope_PlanProductMappingResponseItem_'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
    post:
      tags:
      - Product Catalog Plan Mapping
      summary: Create Plan Product Mappings
      operationId: create_plan_product_mappings_v1_plans__plan_id__products_post
      parameters:
      - name: plan_id
        in: path
        required: true
        schema:
          type: integer
          title: Plan Id
      - name: env_scope
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: 환경을 고릅니다. 값은 production · real_test · sandbox 중 하나입니다. 경로 접두(/v1/sandbox/... · /v1/test/... · /v1/production/...) · X-Env-Scope 헤더 · env_scope 쿼리 가운데 한 통로로 반드시 보내야 합니다. 빼면 자동으로 채우지 않고 거절하며, 두 통로에 서로 다른 값을 담아도 거절합니다. 거절은 HTTP 422 이고 오류 코드는 VALIDATION_ENV_SCOPE_MISMATCH 입니다.
          enum:
          - production
          - real_test
          - sandbox
          title: Env Scope
        description: 환경을 고릅니다. 값은 production · real_test · sandbox 중 하나입니다. 경로 접두(/v1/sandbox/... · /v1/test/... · /v1/production/...) · X-Env-Scope 헤더 · env_scope 쿼리 가운데 한 통로로 반드시 보내야 합니다. 빼면 자동으로 채우지 않고 거절하며, 두 통로에 서로 다른 값을 담아도 거절합니다. 거절은 HTTP 422 이고 오류 코드는 VALIDATION_ENV_SCOPE_MISMATCH 입니다.
      - name: Idempotency-Key
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Idempotency-Key
      - name: Authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: X-Env-Scope
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: 환경을 고릅니다. 값은 production · real_test · sandbox 중 하나입니다. 경로 접두(/v1/sandbox/... · /v1/test/... · /v1/production/...) · X-Env-Scope 헤더 · env_scope 쿼리 가운데 한 통로로 반드시 보내야 합니다. 빼면 자동으로 채우지 않고 거절하며, 두 통로에 서로 다른 값을 담아도 거절합니다. 거절은 HTTP 422 이고 오류 코드는 VALIDATION_ENV_SCOPE_MISMATCH 입니다.
          enum:
          - production
          - real_test
          - sandbox
          title: X-Env-Scope
        description: 환경을 고릅니다. 값은 production · real_test · sandbox 중 하나입니다. 경로 접두(/v1/sandbox/... · /v1/test/... · /v1/production/...) · X-Env-Scope 헤더 · env_scope 쿼리 가운데 한 통로로 반드시 보내야 합니다. 빼면 자동으로 채우지 않고 거절하며, 두 통로에 서로 다른 값을 담아도 거절합니다. 거절은 HTTP 422 이고 오류 코드는 VALIDATION_ENV_SCOPE_MISMATCH 입니다.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlanProductMappingCreateRequest'
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlanProductMappingResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/plans/{plan_id}/products/{product_id}:
    delete:
      tags:
      - Product Catalog Plan Mapping
      summary: Delete Plan Product Mapping
      description: '요금제에서 상품 하나를 **내린다**(매핑 해제) - 운영자의 유일한 해제 경로.


        왜 생겼나(admin 실측 DE-20 뒤 설계 공백 · 내 판단 편지 1a1329df9ee): 활성 요금제 매핑이

        있는 상품의 삭제를 409 로 막은 뒤(5c743fba0) 운영자가 그 매핑을 내릴 길이 **0** 이어서

        빠져나갈 수 없는 거절이 됐다. 저장소의 ``soft_delete_mapping`` 을 부르던 자리 셋은 다

        교체의 부작용이거나 MCP 묶음 삭제였다.


        모양은 나란한 삭제(``DELETE /v1/products/{product_id}``)를 그대로 따른다 - 멱등키 필수 ·

        운영자 쓰기 권한 · 200 과 본문 · 없으면 404(원칙 3). 감사는 교체가 쓰던

        ``record_plan_product_mapping_deleted`` 를 그대로 쓴다(원칙 1 - 같은 사실이다).'
      operationId: delete_plan_product_mapping_v1_plans__plan_id__products__product_id__delete
      parameters:
      - name: plan_id
        in: path
        required: true
        schema:
          type: integer
          title: Plan Id
      - name: product_id
        in: path
        required: true
        schema:
          type: integer
          title: Product Id
      - name: env_scope
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: 환경을 고릅니다. 값은 production · real_test · sandbox 중 하나입니다. 경로 접두(/v1/sandbox/... · /v1/test/... · /v1/production/...) · X-Env-Scope 헤더 · env_scope 쿼리 가운데 한 통로로 반드시 보내야 합니다. 빼면 자동으로 채우지 않고 거절하며, 두 통로에 서로 다른 값을 담아도 거절합니다. 거절은 HTTP 422 이고 오류 코드는 VALIDATION_ENV_SCOPE_MISMATCH 입니다.
          enum:
          - production
          - real_test
          - sandbox
          title: Env Scope
        description: 환경을 고릅니다. 값은 production · real_test · sandbox 중 하나입니다. 경로 접두(/v1/sandbox/... · /v1/test/... · /v1/production/...) · X-Env-Scope 헤더 · env_scope 쿼리 가운데 한 통로로 반드시 보내야 합니다. 빼면 자동으로 채우지 않고 거절하며, 두 통로에 서로 다른 값을 담아도 거절합니다. 거절은 HTTP 422 이고 오류 코드는 VALIDATION_ENV_SCOPE_MISMATCH 입니다.
      - name: Idempotency-Key
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Idempotency-Key
      - name: Authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      - name: X-Env-Scope
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: 환경을 고릅니다. 값은 production · real_test · sandbox 중 하나입니다. 경로 접두(/v1/sandbox/... · /v1/test/... · /v1/production/...) · X-Env-Scope 헤더 · env_scope 쿼리 가운데 한 통로로 반드시 보내야 합니다. 빼면 자동으로 채우지 않고 거절하며, 두 통로에 서로 다른 값을 담아도 거절합니다. 거절은 HTTP 422 이고 오류 코드는 VALIDATION_ENV_SCOPE_MISMATCH 입니다.
          enum:
          - production
          - real_test
          - sandbox
          title: X-Env-Scope
        description: 환경을 고릅니다. 값은 production · real_test · sandbox 중 하나입니다. 경로 접두(/v1/sandbox/... · /v1/test/... · /v1/production/...) · X-Env-Scope 헤더 · env_scope 쿼리 가운데 한 통로로 반드시 보내야 합니다. 빼면 자동으로 채우지 않고 거절하며, 두 통로에 서로 다른 값을 담아도 거절합니다. 거절은 HTTP 422 이고 오류 코드는 VALIDATION_ENV_SCOPE_MISMATCH 입니다.
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlanProductMappingDeleteResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
components:
  schemas:
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
            - type: string
            - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
        input:
          title: Input
        ctx:
          type: object
          title: Context
      type: object
      required:
      - loc
      - msg
      - type
      title: ValidationError
    PlanProductMappingResponse:
      properties:
        plan_id:
          type: integer
          maximum: 9.223372036854776e+18
          minimum: 1.0
          title: Plan Id
          description: plans.id. 경로 파라미터 echo. BIGINT 범위 잠금.
        mappings:
          items:
            $ref: '#/components/schemas/PlanProductMappingResponseItem'
          type: array
          minItems: 1
          title: Mappings
          description: 신규 INSERT 또는 갱신된 매핑 행 목록. 옵션 A 는 1행, 옵션 B 는 N 행.
      additionalProperties: false
      type: object
      required:
      - plan_id
      - mappings
      title: PlanProductMappingResponse
      description: "`POST /v1/plans/{plan_id}/products` 응답 본문.\n\n- 신규 매핑 INSERT만 발생 시 → 201 Created (응답 상태 코드는 라우트 영역).\n- 기존 활성 매핑 본문 갱신 발생 시 → 200 OK + 기존 행 soft delete + 신규 INSERT\n  (감사 이벤트 2건 = `plan_product.mapping.deleted` + `plan_product.mapping.created`).\n\n응답 envelope:\n```json\n{ \"data\": { \"plan_id\": 100, \"mappings\": [ {...}, ... ] } }\n```\n본 DTO 는 `data` 내부 본문 (`plan_id` + `mappings` 배열) 만 정의 — 외부 `data`\n래핑은 통합 담당 envelope 영역."
    PageEnvelope_PlanProductMappingResponseItem_:
      properties:
        items:
          items:
            $ref: '#/components/schemas/PlanProductMappingResponseItem'
          type: array
          title: Items
          description: Page result items. Empty list allowed.
        next_cursor:
          anyOf:
          - type: string
          - type: 'null'
          title: Next Cursor
          description: Opaque cursor for next page, or null on last page.
        has_more:
          type: boolean
          title: Has More
          description: Whether another page exists. False when next_cursor is null.
          default: false
      additionalProperties: false
      type: object
      title: PageEnvelope[PlanProductMappingResponseItem]
    PlanProductMappingCreateRequest:
      properties:
        product_id:
          anyOf:
          - type: integer
            maximum: 9.223372036854776e+18
            minimum: 1.0
          - type: 'null'
          title: Product Id
          description: 옵션 A (단일 매핑). 옵션 B (mappings) 와 상호 배타. BIGINT 범위 잠금.
        product_version_id:
          anyOf:
          - type: integer
            maximum: 9.223372036854776e+18
            minimum: 1.0
          - type: 'null'
          title: Product Version Id
          description: 옵션 A (단일 매핑). NULL=동적 (api_products.current_version_id 참조). BIGINT 범위 잠금.
        is_default:
          anyOf:
          - type: boolean
          - type: 'null'
          title: Is Default
          description: 옵션 A (단일 매핑). 기본 false (서비스 레벨 보강).
        mappings:
          anyOf:
          - items:
              $ref: '#/components/schemas/PlanProductMappingItem'
            type: array
            maxItems: 100
            minItems: 1
          - type: 'null'
          title: Mappings
          description: 옵션 B (다중 매핑 일괄 추가/갱신). 1~100 행. 옵션 A (product_id) 와 상호 배타.
      additionalProperties: false
      type: object
      title: PlanProductMappingCreateRequest
      description: '`POST /v1/plans/{plan_id}/products` 요청 본문.


        옵션 A (단일): `product_id` + `product_version_id` + `is_default` 평면 본문.

        옵션 B (다중): `mappings` 배열 nested 본문 (운영 효율).


        DTO `model_validator(mode=''after'')` 가 "양쪽 모두 지정" 또는 "양쪽 모두 미지정"

        본문을 사전 거부한다 - 422 분기가 한 곳에 있어야 하므로 라우트 진입 전에 걸러진다.

        라우트와 서비스는 옵션 A · B 분기와 DB 트랜잭션만 맡는다(빈 본문 · 모순 본문은

        여기서 막혀 라우트에 닿지 않는다).'
    PlanProductMappingListQuery:
      properties:
        limit:
          type: integer
          maximum: 100.0
          minimum: 1.0
          title: Limit
          default: 20
        cursor:
          anyOf:
          - type: string
            maxLength: 2048
          - type: 'null'
          title: Cursor
          description: opaque cursor (id DESC tie-break).
        sort:
          type: string
          enum:
          - id:desc
          - id:asc
          - created_at:desc
          - created_at:asc
          title: Sort
          default: id:desc
      type: object
      title: PlanProductMappingListQuery
      description: Shared list query for plan mapping GET endpoints (Sprint 1 SS7 read extension).
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    PlanProductMappingResponseItem:
      properties:
        id:
          type: integer
          maximum: 9.223372036854776e+18
          minimum: 1.0
          title: Id
          description: plan_products.id.
        product_id:
          type: integer
          maximum: 9.223372036854776e+18
          minimum: 1.0
          title: Product Id
        product_version_id:
          anyOf:
          - type: integer
            maximum: 9.223372036854776e+18
            minimum: 1.0
          - type: 'null'
          title: Product Version Id
        is_default:
          type: boolean
          title: Is Default
        env_scope:
          type: string
          enum:
          - sandbox
          - real_test
          - production
          title: Env Scope
        created_at:
          type: string
          format: date-time
          title: Created At
        updated_at:
          type: string
          format: date-time
          title: Updated At
      additionalProperties: false
      type: object
      required:
      - id
      - product_id
      - is_default
      - env_scope
      - created_at
      - updated_at
      title: PlanProductMappingResponseItem
      description: "매핑 응답 1행.\n\nDB → DTO 매핑(`plan_products`):\n- `id` / `product_id` / `product_version_id` / `is_default` / `env_scope` /\n  `created_at` / `updated_at` → 직접 매핑.\n- `plan_id` 는 응답 envelope 상위 키로 분리(같은 plan 내 1개 + 매핑 N 개 구조)."
    PlanProductMappingItem:
      properties:
        product_id:
          type: integer
          maximum: 9.223372036854776e+18
          minimum: 1.0
          title: Product Id
          description: api_products.id 존재 + env_scope 일치 + status IN ('ACTIVE','DEPRECATED'). RETIRED/DRAFT 매핑 거부 → 409 CATALOG_RETIRED_PRODUCT_USE / CATALOG_VERSION_NOT_PUBLISHED. BIGINT 범위 잠금.
        product_version_id:
          anyOf:
          - type: integer
            maximum: 9.223372036854776e+18
            minimum: 1.0
          - type: 'null'
          title: Product Version Id
          description: (선택) api_product_versions.id. NULL=동적 (api_products.current_version_id 참조). BIGINT 범위 잠금.
        is_default:
          type: boolean
          title: Is Default
          description: true 지정 시 같은 plan 내 다른 default 매핑 자동 false 전환. 같은 plan 내 default 행 최대 1건(부분 유니크 인덱스가 강제한다).
          default: false
      additionalProperties: false
      type: object
      required:
      - product_id
      title: PlanProductMappingItem
      description: "매핑 1 항목 - 단일(옵션 A) · 다중(옵션 B) 양쪽에서 공유한다.\n\n`product_version_id`:\n- 지정 시 `api_product_versions.id` 존재 + `product_id` 일치 + `version_status='PUBLISHED'`.\n  PUBLISHED 아니면 `409 CATALOG_VERSION_NOT_PUBLISHED`.\n- NULL 이면 항상 `api_products.current_version_id` 참조(동적). 운영 권장.\n\n`is_default`:\n- true 지정 시 같은 plan 내 다른 default 매핑 자동 false 전환(트랜잭션).\n- 같은 plan 내 default 행은 최대 1건 (BILLING `plan_products` 부분 유니크 인덱스)."
    PlanProductMappingDeleteResponse:
      properties:
        plan_id:
          type: integer
          maximum: 9.223372036854776e+18
          minimum: 1.0
          title: Plan Id
        mapping_id:
          type: integer
          maximum: 9.223372036854776e+18
          minimum: 1.0
          title: Mapping Id
          description: plan_products.id.
        product_id:
          type: integer
          maximum: 9.223372036854776e+18
          minimum: 1.0
          title: Product Id
        product_version_id:
          anyOf:
          - type: integer
            maximum: 9.223372036854776e+18
            minimum: 1.0
          - type: 'null'
          title: Product Version Id
        is_default:
          type: boolean
          title: Is Default
        env_scope:
          type: string
          enum:
          - sandbox
          - real_test
          - production
          title: Env Scope
      additionalProperties: false
      type: object
      required:
      - plan_id
      - mapping_id
      - product_id
      - is_default
      - env_scope
      title: PlanProductMappingDeleteResponse
      description: '``DELETE /v1/plans/{plan_id}/products/{product_id}`` 응답 본문.


        **내린 행의 정체성만** 돌려준다 - ``deleted_at`` 은 싣지 않는다. 그 값을 실으려면

        저장소의 ``soft_delete_mapping`` 이 시각을 돌려줘야 하는데 그 함수는 호출자가 셋이고

        (매핑 교체 · MCP 패키지 재시드 · 묶음 삭제) 반환 모양을 바꾸면 그 셋이 함께 흔들린다.

        2026-10-13 에 목록 함수의 둘째 반환값을 바꿔 쪽 넘김 반복문 둘이 500 이 된 일이 있어

        (abb4e4093 · 413b20f63 으로 고침) 같은 꼴을 되풀이하지 않는다 - 운영자가 알아야 할

        것은 「무엇이 내려갔나」 이고 그것은 이 칸들로 충분하다.'
  securitySchemes:
    basicClientCredential:
      type: http
      scheme: basic
      description: 'Console-issued client credential. Send `Authorization: Basic base64(client_id:client_secret)`.'
    mcpOAuth2:
      type: oauth2
      description: For MCP clients. OAuth 2.0 authorization code flow with PKCE (S256) for public clients. The client_id is the HTTPS URL of an OAuth Client ID Metadata Document that XBOSS has allow-listed; dynamic client registration is not supported.
      flows:
        authorizationCode:
          authorizationUrl: https://api.xdata.kr/oauth/authorize
          tokenUrl: https://api.xdata.kr/oauth/token
          scopes: {}