xdata-kr Product Catalog Plan Mapping API
The Product Catalog Plan Mapping API from xdata-kr — 2 operation(s) for product catalog plan mapping.
The Product Catalog Plan Mapping API from xdata-kr — 2 operation(s) for product catalog plan mapping.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
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.curl "https://apis.io/api/v1/apis/xdata-kr:xdata-kr-product-catalog-plan-mapping-api"
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.
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: 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: {}