Base URL:
https://scm.mitunolens.com/api/v1(개발:https://dev.mitunolens.com/api/v1) 버전: v1.5 (2026-08-07 갱신 — 상태 통보 API 운영 반영) 대상 코드:routes/api.php·app/Http/Controllers/Api/V1/·app/Http/Middleware/AuthenticateApiKey.php
v1.4 주요 변경 — v1.3(2026-05-08) 이후 실제 코드에 반영된 사항을 현행화했다. ① 주문 재전송 멱등 처리(같은 주문번호 재전송 시
200+ 기존 주문 반환) ② 다통화 접수(단가는 채널 국가의 현지 통화, 저장·응답은 원화 환산 + 환율 스냅샷) ③ 예약주문 한도 강제와 재고 마스터 부재 에러 신설 ④ 재고 목록 응답에quantity·allocated필드가 실재함을 반영 ⑤ 금액 필드가 문자열로 직렬화됨을 명시 ⑥ SCM → 채널 역방향 연동이 실재함을 반영 ⑦ 주문 상태 하드코딩 등 알려진 제약 절 신설.
모든 API 요청은 X-Api-Key 헤더를 통해 인증합니다.
X-Api-Key: {YOUR_API_KEY}
lns_{UUID}).App\Http\Middleware\AuthenticateApiKeySalesChannel이 요청에 자동 주입되어, 이후 모든 조회·판정이 그 채널 범위로 한정됩니다.is_active = false)의 키는 자동 차단됩니다.💡 API Key는 DB에 암호화 저장됩니다(
encrypted캐스트). 그래서 인증은 SQL 조건 검색이 아니라 활성 채널을 순회하며 복호화 비교하는 방식입니다. 채널 수가 많아지면 이 부분이 병목이 될 수 있습니다(현재 운영 채널 3개 — 영향 없음).
| 상황 | HTTP 코드 | 응답 |
|---|---|---|
| 키 미포함 | 401 |
{"error": "API 키가 필요합니다."} |
| 잘못된 키 / 비활성 채널 | 401 |
{"error": "유효하지 않은 API 키입니다."} |
현재 제공되는 엔드포인트는 아래 4개입니다.
| 메서드 | 경로 | 용도 | 상태 |
|---|---|---|---|
GET |
/api/v1/inventory |
채널 매핑 상품 전체 재고 조회 | ✅ 운영 가동 |
GET |
/api/v1/inventory/{sku} |
단품 가용재고 조회 | ✅ 운영 가동 |
POST |
/api/v1/orders |
주문 접수 | ✅ 운영 가동 |
POST |
/api/v1/orders/{orderNumber}/status |
주문 상태 변경 통보 (§2.4) | ✅ 가동 중 (v1.5, 2026-08-07 운영 반영) |
GET /api/v1/inventory
해당 채널에 매핑된 전체 상품의 재고 정보를 반환합니다. 채널별 판매가능 재고는 통장식 할당(Bank Balance) 공식 ②에 의해 산출됩니다.
요청 헤더:
X-Api-Key: {API_KEY}
응답 (200):
{
"data": [
{
"sku": "LENS-RED-01",
"product_code": "LN-0021-0350",
"product_name": "레드 렌즈",
"quantity": 100,
"allocated": 30,
"available": 80,
"reserve_remaining": 10
}
]
}
응답 필드 설명:
| 필드 | 타입 | 설명 |
|---|---|---|
sku |
string | 채널 SKU 코드 (ProductMapping.channel_variant_code) |
product_code |
string | 자사 상품 변형(SKU) 코드 (ProductVariant.code) |
product_name |
string | 상품명 (Product.name — variant→product 경유) |
quantity |
integer | 물리 재고(창고 실재고) |
allocated |
integer | 해당 재고에 걸린 전 채널 사전할당 합계 |
available |
integer | 판매가능 재고 — 해당 채널이 판매 가능한 최종 수량. 미출고 주문 차감 반영 |
reserve_remaining |
integer | 예약주문 접수 가능 잔여량 — 예약주문할당(reserve_quota) − 기접수 예약주문(backordered_qty) |
💡
available에는 사전재고할당 잔여가 이미 포함되어 있습니다. 별도의 할당 잔여 필드는 없으며,available값이 해당 채널이 판매 가능한 최종 수량입니다.reserve_remaining은is_backorder: true주문 시 접수 가능한 추가 수량을 의미합니다.quantity·allocated는 참고용 원자료입니다. 판매 판단은available만 보면 됩니다.
⚠️ 페이지네이션이 없습니다. 매핑된 상품 전체가 한 번에 반환되며, 상품마다 재고 산출 쿼리가 개별 수행됩니다. 대량 매핑 채널에서는 응답이 느려질 수 있으므로 주기적 동기화(크론) 용도로만 사용하고, 실시간 조회에는 §2.2를 사용하십시오.
GET /api/v1/inventory/{sku}
채널 SKU 기반으로 단품 가용재고를 반환합니다. 쇼핑몰 장바구니/결제 시 빠른 응답용으로 설계되었습니다.
경로 파라미터:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
sku |
string | ✅ | 채널 SKU 코드 |
응답 (200):
{
"sku": "LENS-RED-01",
"available": 80,
"reserve_remaining": 10
}
응답 필드 설명:
| 필드 | 타입 | 설명 |
|---|---|---|
sku |
string | 요청한 채널 SKU |
available |
integer | 판매가능 재고 (공식 ② 기반) |
reserve_remaining |
integer | 예약 허용 잔여량 |
이 엔드포인트는
data래퍼 없이 평평한 객체를 반환합니다(§2.1은data배열로 감쌈). 파싱 시 주의하십시오.
에러 (404):
{
"error": "해당 SKU를 찾을 수 없습니다."
}
재고 마스터(
inventory) 행이 아직 없는 매핑 상품은 404가 아니라available: 0,reserve_remaining: 0으로 응답합니다.
POST /api/v1/orders
외부 쇼핑몰에서 주문을 접수합니다.
중요: 주문 접수 시 물리 재고는 차감되지 않습니다. 가용재고는 미출고 주문 수량을 기반으로 자동 차감됩니다 (기획서 §6-2). 실제 물리 재고 차감은 출고(출하) 처리 시점에 발생합니다.
요청 헤더:
X-Api-Key: {API_KEY}
Content-Type: application/json
요청 본문:
{
"order_number": "ORD-2026-001",
"recipient_name": "홍길동",
"recipient_phone": "010-1234-5678",
"shipping_address": "서울시 강남구 테헤란로 123",
"tracking_number": null,
"is_backorder": false,
"items": [
{
"sku": "LENS-RED-01",
"quantity": 2,
"unit_price": 15000
}
]
}
요청 필드 설명:
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
order_number |
string | ✅ | 외부 주문번호 (최대 100자, 전역 고유) |
recipient_name |
string | ✅ | 수령인 이름 (최대 100자) |
recipient_phone |
string | ✅ | 수령인 연락처 (최대 30자) |
shipping_address |
string | ✅ | 배송 주소 (최대 500자) |
tracking_number |
string | ❌ | 운송장 번호 (최대 100자) |
status |
integer | ❌ | SCM 주문 상태 — 0(입금전) 또는 1(입금완료)만 허용. 미전송이면 1(하위 호환). 그 외 값은 422 |
is_backorder |
boolean | ❌ | 예약주문 여부 (기본값: false) |
items |
array | ✅ | 주문 상품 목록 (최소 1개) |
items[].sku |
string | ✅ | 채널 SKU 코드 |
items[].quantity |
integer | ✅ | 수량 (최소 1) |
items[].unit_price |
number | ✅ | 채널 국가의 현지 통화 단가 (0 이상) — §2.3.2 참조 |
주문 상태(
status)는 접수 단계에서 입금전·입금완료만 받습니다. 그 이후 상태(상품준비·발송준비·발송완료·취소)는 §2.4 상태 변경 통보 를 사용하십시오.
| 구분 | is_backorder: false (기본) |
is_backorder: true |
|---|---|---|
| 가용재고 체크 | 가용재고 부족 시 422 반환 |
가용재고 부족해도 접수 가능 |
| 재고 처리 | 물리 재고 불변, 미출고 주문으로 가용재고 자동 차감 | backordered_qty 통장 기록 + 가용재고 차감 |
| 한도 검사 | 없음 | 채널에 reserve_quota > 0이 설정돼 있으면 잔여 한도 초과 시 422 |
| 사용 시나리오 | 일반 즉시 배송 주문 | 선주문 / 예약 판매 |
예약 한도 강제는 점진 도입 상태입니다. 해당 재고에 대한 채널 할당이 없거나
reserve_quota가0이면 한도를 검사하지 않고 무제한 접수됩니다. 한도를 걸려면 재고 관리에서reserve_quota를 양수로 설정하십시오.
2026-08-05부터 채널 국가에 따라 통화를 판별해 접수합니다.
| 단계 | 처리 |
|---|---|
| 1. 통화 판별 | 채널의 country_code → 통화코드 변환 (KR 또는 미설정 시 KRW) |
| 2. 환율 조회 | 접수 시점의 최신 적용환율을 가져옴 (KRW는 항상 1.0) |
| 3. 저장 | 현지 금액과 원화 환산액을 둘 다 저장하고, 적용환율을 스냅샷으로 남김 |
| 저장 위치 | 의미 |
|---|---|
orders.local_currency_code |
접수 통화 (예: JPY) |
orders.local_total_amount |
현지 통화 합계 |
orders.total_amount |
원화 환산 합계 |
orders.exchange_rate |
접수 시점 적용환율 스냅샷 (이후 환율이 바뀌어도 주문 금액은 불변) |
order_items.local_unit_price |
수신 그대로의 현지 단가 |
order_items.unit_price |
원화 환산 단가 |
unit_price는 현지 통화입니다. JP 채널이면 엔화 단가를 그대로 보내십시오.⚠️ 환율 미등록 주의: 해당 통화의 환율 데이터가 SCM에 없으면 적용환율이
0으로 계산되어 원화 금액이 0으로 기록됩니다. 비원화 채널을 연동하기 전에 환율이 수집되고 있는지 반드시 확인하십시오(§4.5).
💡 먼슬리(2개 1세트) 상품: 좌·우 SKU 2개가 한 세트인 상품은 세트 가격을 그대로 양쪽에 보내면 금액이 2배가 됩니다. 분할은 채널(쇼핑몰) 전송단에서 정수 배분(예: 1,985 → 993 + 992)으로 처리하며, SCM은 받은 값을 그대로 신뢰합니다. 채널 상품정보의 먼슬리 체크가 켜져 있어야 분할이 발동합니다.
201){
"data": {
"id": 1,
"order_number": "ORD-2026-001",
"status": 1,
"total_amount": "30000.00",
"recipient_name": "홍길동",
"items": [
{
"product_code": "LN-0021",
"product_name": "레드 렌즈",
"quantity": 2,
"unit_price": "15000.00"
}
],
"created_at": "2026-05-07T14:30:00+09:00"
}
}
응답 필드 설명:
| 필드 | 타입 | 설명 |
|---|---|---|
id |
integer | 내부 주문 ID |
order_number |
string | 외부 주문번호 |
status |
integer | 주문 상태 — 접수 시 항상 1(입금완료). §2.3.5 참조 |
total_amount |
string | 총 주문금액 (원화 환산, 소수 2자리 문자열) |
recipient_name |
string | 수령인 이름 |
items[] |
array | 주문 상품 상세 |
items[].product_code |
string | 자사 상품 코드 (Product.code) |
items[].product_name |
string | 상품명 (Product.name) |
items[].quantity |
integer | 수량 |
items[].unit_price |
string | 단가 (원화 환산, 소수 2자리 문자열) |
created_at |
string | 생성일시 (ISO 8601) |
⚠️ 금액은 숫자가 아니라 문자열입니다(
"30000.00"). DBdecimal(*,2)캐스트가 그대로 직렬화되기 때문입니다. 채널 측에서 숫자로 비교·연산하려면 명시적으로 형변환하십시오.
⚠️
product_code의 의미가 엔드포인트마다 다릅니다. 재고 조회(§2.1)는ProductVariant.code(SKU 단위, 예LN-0021-0350), 주문 응답은Product.code(상품 단위, 예LN-0021)를 반환합니다. 두 값을 같은 키로 대조하지 마십시오.
응답에는
is_backorder·tracking_number·통화 필드가 포함되지 않습니다(요청 전용 / 내부 저장 전용).
채널이 네트워크 타임아웃 등으로 같은 주문을 다시 보내도 주문이 중복 생성되지 않습니다.
| 상황 | HTTP 코드 | 동작 |
|---|---|---|
| 최초 접수 | 201 |
주문 생성 후 반환 |
같은 채널 + 같은 order_number 재전송 |
200 |
기존 주문을 그대로 반환 (에러 아님) |
order_number) 조합입니다.order_number로 보내십시오.201과 200을 모두 성공으로 처리해야 합니다. 200을 실패로 오인하면 재시도 루프에 빠집니다.| 제약 | 내용 | 대응 |
|---|---|---|
| ~~주문 상태가 고정~~ | ✅ 해소 (2026-08-06) — POST /orders 요청에 status 필드가 생겼습니다(0 입금전 / 1 입금완료). 미전송이면 종전대로 입금완료로 접수됩니다(하위 호환). |
§2.4 참조 |
| ~~상태 변경·취소 통보 통로 없음~~ | ✅ 해소 (2026-08-06) — POST /orders/{orderNumber}/status 신설(CH-002·CH-003). |
§2.4 참조 |
order_number가 전역 유니크 |
채널별이 아니라 전체 주문에 걸쳐 고유합니다. 서로 다른 두 채널이 같은 주문번호를 쓰면 뒤에 온 요청이 500으로 실패합니다. |
채널별 접두사로 분리 운영합니다 — 미쯔노 C…, 센스매니아 S… (PO 확정). 현재 채널 간 충돌 위험은 없습니다. 신규 채널을 붙일 때는 반드시 사용되지 않은 접두사를 배정하십시오 |
~~조회 available ≠ 접수 판정 기준~~ |
✅ 해소 (2026-08-06) — 입금전 주문이 가용재고 공식에 편입되면서 조회와 접수 판정이 같은 공식을 씁니다. | 다만 조회 시점과 접수 시점 사이에 다른 주문이 들어올 수 있으므로, 최종 판정은 여전히 접수 응답(422 여부)으로 확인하십시오 |
| Rate Limiting 없음 | 호출 빈도 제한이 걸려 있지 않습니다. | 채널 측에서 호출 간격을 조절하십시오 |
같은 자사 SKU를 가리키는 채널 SKU 별칭이 여러 개이거나, items 배열에 같은 SKU가 여러 줄로 들어온 경우:
A-SKU 3개 + B-SKU 2개가 같은 자사 SKU를 가리키면 → 5개로 합산 판정.422입니다.| 상황 | HTTP 코드 | 응답 |
|---|---|---|
| 필수 필드 누락 / 형식 오류 | 422 |
{"message": "주문번호는 필수입니다. (and 4 more errors)", "errors": {"order_number": ["주문번호는 필수입니다."], ...}} |
| SKU 미존재(채널 매핑 없음) | 422 |
{"error": "SKU 'XXX'에 해당하는 상품을 찾을 수 없습니다."} |
| 재고 마스터 없음 | 422 |
{"error": "SKU 'XXX'의 재고 마스터가 없어 주문을 접수할 수 없습니다."} |
| 재고 부족 (일반주문) | 422 |
{"error": "SKU 'XXX'의 가용재고가 부족합니다. (요청: 5, 가용: 2)"} |
| 예약 잔여 부족 (예약주문) | 422 |
{"error": "SKU 'XXX'의 예약 가능 잔여가 부족합니다. (요청: 5, 잔여: 2)"} |
유효성 검사 실패(
422)만message/errors구조이고, 업무 규칙 위반은 모두{"error": "..."}단일 키 구조입니다. 채널은 두 형식을 모두 파싱해야 합니다.
동시성: 주문 접수는 재고 행 잠금(
SELECT ... FOR UPDATE) 하에 트랜잭션으로 처리됩니다. 같은 SKU에 대한 동시 주문은 직렬화되어, 잠금 획득 후 최신 가용재고로 다시 검증합니다.
POST /api/v1/orders/{orderNumber}/status — 신설 2026-08-06
✅ 운영 가동 중 (2026-08-07 배포). 규격은 확정이며 dev 전항목 실증을 통과했습니다.
채널이 자기 쪽 주문 상태 변경(입금 확인·출고·취소)을 SCM 에 통보합니다.
설계 원칙: 상태 표시는 양방향으로 흐르되, 재고를 움직이는 조작은 SCM 에서만 실행합니다. 채널은 "이 주문이 이렇게 되었다"를 알릴 뿐이고, 실재고 차감·복원은 SCM 이 수행합니다.
{
"status": 3,
"tracking_number": "JP-1234-5678",
"courier_code": "NEKOPOS",
"reason": "고객 취소"
}
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
status |
integer | ✅ | 0 입금전 · 1 입금완료 · 2 상품준비 · 9 발송준비 · 3 발송완료 · 88 취소 |
tracking_number |
string | 조건부 | status=3(발송완료)이면 필수 (최대 100자) |
courier_code |
string | — | 공통코드 DELIVERY_COMPANY 의 code. 쇼핑몰 택배사 이름과 같은 값으로 맞춰져 있습니다(NEKOPOS·SAGAWA·ゆうパケット 등). 못 찾으면 운송장만 저장합니다 |
reason |
string | — | 취소 사유 (최대 255자) |
| 통보 상태 | SCM 동작 | 재고 |
|---|---|---|
3 발송완료 |
shipOrder() — 운송장·택배사 기록 |
🔴 실재고 차감 |
88 취소 |
cancelOrder() — 품목별 취소 수량 기록 |
🔴 가용재고 복원 |
| 그 외 | 전이표를 따라 목표 상태까지 진행 (입금전→입금완료→상품준비·발송준비) | 변동 없음 |
200 (멱등). 큐 재시도와 SCM→채널→SCM 왕복이 여기서 한 바퀴에 멈춥니다 — 에코 루프 차단.200 (멱등). 예외를 던지면 채널 큐가 영구 실패로 오인합니다.409. 조용히 성공으로 응답하면 채널은 반영된 줄 알고 두 장부가 갈라집니다.0→1→2 가 크론 주기 안에 일어나면
통보는 2 하나뿐입니다. 이때 한 단계 전이만 허용하면 정상 통보가 영구히 409 로 거부돼
두 장부가 갈라집니다. SCM 은 전이표를 그대로 밟아 0→1→2 로 따라잡으므로
중간 단계의 재고·기록 규약은 종전과 동일합니다.409 입니다(입금완료 → 입금전). 전이표상 도달 경로가 없는 요청도 409 입니다.성공 (200): POST /orders 와 같은 형식.
| 상황 | 코드 | 응답 |
|---|---|---|
| 해당 채널에 그 주문번호 없음 | 404 |
{"error": "주문번호 'XXX'를 찾을 수 없습니다."} |
| 허용되지 않는 전이 | 409 |
{"error": "허용되지 않는 상태 전이입니다.", "code": "invalid_transition", "current_status": 1, "requested_status": 0} |
| 발송 처리 중 재고 부족 | 409 |
{"error": "재고가 부족합니다. (가용: 1, 요청: 3)", "code": "insufficient_stock", "current_status": 1, "requested_status": 3} |
| 통보 불가 상태 / 운송장 누락 | 422 |
{"message": "...", "errors": {...}} |
409판별은 오류 문구가 아니라code로 하십시오 (2026-08-07 추가). 문구는 다듬어질 수 있습니다. 같은409라도 성격이 다릅니다 —invalid_transition은 재시도해도 결과가 같은 확정 거부이고,insufficient_stock은 재고를 채운 뒤 재전송하면 성공하는 조치 대상입니다.
적용 범위: 통보 대상은 SCM 에 접수된 주문뿐입니다. 쇼핑몰에서 SCM 미연동 상품만으로 구성된 주문은 애초에 전송되지 않으므로 통보 대상이 아닙니다.
409는 재시도해도 결과가 같습니다. 전이표상 불가한 요청이므로 채널은 재시도 대상에서 제외하고 실패로 확정 기록해야 합니다.
| 코드 | 의미 | 설명 |
|---|---|---|
200 |
성공 | 정상 조회 / 주문 재전송 시 기존 주문 반환 |
201 |
리소스 생성 성공 | 주문 신규 접수 완료 |
401 |
인증 실패 | API 키 누락 또는 유효하지 않음 |
404 |
리소스 없음 | 해당 SKU가 채널에 매핑되지 않음 |
422 |
유효성 검사 실패 | 필수 필드 누락, SKU 미존재, 재고 마스터 부재, 재고 부족, 예약 잔여 부족 |
500 |
서버 내부 오류 | 예기치 못한 서버 에러 (타 채널과의 주문번호 충돌 포함) |
API를 통해 재고 조회 및 주문 접수를 연동하기 전에, 아래 사전 설정이 반드시 완료되어야 합니다.
is_active) 를 켜 두어야 합니다. 비활성 채널의 키는 401로 차단됩니다.채널의 국가 코드가 접수 통화를 결정합니다.
KR이면 → KRW, 환율 1.0JP → JPY)국가를 설정하지 않은 해외 채널은 엔화 금액이 원화로 기록됩니다. 해외 채널은 반드시 국가를 지정하십시오.
각 채널에서 판매할 상품의 채널 SKU를 매핑해야 합니다.
channel_variant_code (채널 SKU) = 외부 쇼핑몰에서 사용하는 상품 코드404, 주문 시 422입니다.Admin 패널 > 재고 관리 (/admin/inventories) 에서 채널별 재고 할당을 설정합니다.
| 설정 항목 | 위치 | 설명 |
|---|---|---|
| 사전재고할당 (allocated_qty) | 재고 관리 > 채널별 할당 | 해당 채널에 독점 배분하는 수량. 이 수량은 다른 채널에서 사용 불가 |
| 예약주문할당 (reserve_quota) | 재고 관리 > 채널별 할당 | 물리 재고가 없어도 선주문 가능한 허용량. is_backorder: true 주문 시 이 범위 내에서 접수 가능 |
주의: 사전재고할당과 예약주문할당 값을 설정하지 않으면, 해당 채널의 API로 조회되는 예약 잔여량(
reserve_remaining)이 0으로 반환됩니다. 단available은 공유재고분이 있으면 0이 아닐 수 있습니다(§5).
| 상품 | 물리재고 | A채널 사전할당 | B채널 사전할당 | 공유재고 |
|---|---|---|---|---|
| 레드 렌즈 | 100 | 30 | 20 | 50 |
비원화 채널을 연동하기 전에 해당 통화의 환율이 수집되고 있는지 확인하십시오. 환율이 없으면 원화 환산액이 0으로 기록됩니다(§2.3.2).
reserve_quota) 값 설정GET /api/v1/inventory)200(재전송)을 성공으로 처리하는지 확인본 API의 available 값은 해당 채널에 배분된 재고와 공유 재고를 기반으로 산출됩니다.
공통 가용재고 = 물리재고 − 미출고 일반주문 잔량 − 전 채널 사전할당 합계 − 전 채널 예약접수 합계 (0 미만은 0)
채널 available = 공통 가용재고 + 내 채널 사전할당(allocated_qty)
reserve_remaining = 내 채널 예약주문할당(reserve_quota) − 내 채널 기접수 예약(backordered_qty)
reserve_remaining은 예약주문(is_backorder: true) 시 추가 접수 가능한 수량입니다.💡
available값만으로 재고 판단이 가능합니다. 별도의 내부 산출 과정을 알 필요 없습니다. 단 §2.3.5의 "조회available≠ 접수 판정 기준" 항목은 확인하십시오.
상세 공식(①~⑦)의 정본은 docs/features/inventory.md 입니다.
SCM의 역할 = 재고 흐름 관리자 (주문 상태의 주인은 채널)
| 방향 | 설명 | 현재 상태 |
|---|---|---|
| 채널 → SCM (주문 접수) | 채널이 주문을 SCM에 전달 | ✅ 가동 중 (POST /orders) |
| 채널 ← SCM (재고 조회) | 채널이 재고 정보를 SCM에서 조회 | ✅ 가동 중 (GET /inventory, 5분 주기 동기화) |
| 채널 → SCM (상태·취소 통보) | 채널이 결제·출고·취소를 SCM에 알림 | ✅ 가동 중 (POST /orders/{orderNumber}/status — §2.4, 2026-08-07 운영 반영) |
| SCM → 채널 (상품정보 조회) | SCM 관리자가 채널의 상품·옵션 정보를 끌어옴 | ✅ 가동 중 — 아래 참조 |
v1.3에서 "역방향 연동은 불필요"로 기술했으나, 현재는 실재하는 연동입니다.
SCM 관리자의 상품 등록 화면 > [채널 상품정보 불러오기] 기능이 채널 사이트를 직접 호출합니다.
| 항목 | 내용 |
|---|---|
| 호출 주체 | SCM (ChannelProductFetchService) |
| 대상 | 판매채널에 등록된 API URL (sales_channels.api_url) |
| 인증 헤더 | X-API-KEY: {채널 API Key} |
| 쿼리 파라미터 | usercode={상품코드} |
| 타임아웃 | 5초 |
채널이 반환해야 하는 응답(JSON):
| 필드 | 타입 | 설명 |
|---|---|---|
found |
boolean | 상품 존재 여부. true가 아니면 "존재하지 않는 상품번호"로 처리 |
goods_name |
string | 상품명 |
is_monthly |
integer | 먼슬리(2개 1세트) 상품이면 1 |
options |
array | 옵션 목록 |
options[].opt_group |
string | 옵션 그룹 (좌/우 등) |
options[].power |
string | 도수 |
options[].option_code |
string | 채널 옵션코드 (= 채널 SKU) |
options[].stock |
integer | 채널 측 재고 |
options[].hidden |
boolean/int | 숨김 옵션 여부 |
message |
string | 실패 사유 (선택) |
SCM은 받은 옵션으로 먼슬리 불변식을 검사합니다 — 그룹(좌·우)이 2개면 양쪽 도수 집합이 일치해야 하고, 같은 도수의 옵션코드는 그룹 간에 동일해야 합니다. 좌·우는 같은 물건이므로 코드가 곧 SKU이며, SCM 이 코드 기준으로 병합해 도수당 1 SKU 로 등록합니다. 위반(도수 집합 불일치·같은 도수인데 코드가 서로 다름) 시 SKU 자동 적용을 중단하고 "쇼핑몰 옵션 설정 오류"로 안내합니다.
(2026-08-07 정정: 종전 서술 "옵션코드가 그룹 간에 구분돼야 합니다"는 실제 검증 로직과 정반대였습니다. 실코드는 좌·우 코드가 다르면 경고하고, 같으면 병합합니다.)
| 항목 | 방향 | 상태 | 설명 |
|---|---|---|---|
| ~~주문 상태 변경·취소 통보 API — CH-002 · CH-003~~ | 채널 → SCM | ✅ 운영 반영 완료 (v1.5, 2026-08-07) | 규격은 §2.4 정식 절. dev 전항목 실증 통과 후 운영 배포됐습니다 |
| 센스매니아 적용 — CH-005 | 양방향 | 🔲 미착수 | 미츠노 검증 완료 후 동일 소스에 적용 |
| Pagination 지원 (재고 목록) | 내부 | 🔲 미착수 | 대량 상품 조회 시 페이지 단위 분할 응답 |
| Rate Limiting | 내부 | 🔲 미착수 | API 호출 빈도 제한으로 서버 안정성 확보 |
HMAC 서명 (api_secret) |
내부 | 🔲 결정 대기 | API Key 단독 인증의 보강 |
API 문서 자동 생성 (knuckleswtf/scribe) |
내부 | 🔲 미착수 | 코드 기반 API 규격서 자동 생성 |
이미 가동 중인 항목: CH-001(주문 접수) · CH-004(가용재고 조회) — 미츠노 채널 기준 2026-07-20 E2E 검증 완료.
| 문서 | 내용 |
|---|---|
docs/api/order-api.md |
주문 등록 API 규격 (정본) |
docs/api/inventory-api.md |
재고 조회 API 규격 (정본) |
docs/features/inventory.md |
재고 아키텍처·가용재고 공식 ①~⑦ (정본) |
docs/features/channel-api-integration.md |
채널 연동 계획서 |
docs/features/multicurrency-i18n.md |
다통화·다국어 설계 |
POST /orders 에 status 필드 · §5 미출고 잔량에 입금전 편입 · §2.3.5 제약 3건 해소 표기 · §6 방향표·§7 향후 개발 상태 갱신409 가 아니라 SCM 이 전이표를 밟아 따라잡는다(채널 큐가 최종 상태만 전달하는 구조라, 종전 서술대로면 정상 통보가 영구히 거부된다). §7 CH-002·003 을 dev 검수 완료로 갱신code 필드(insufficient_stock/invalid_transition) 추가 — 판별은 문구가 아니라 code 로code(insufficient_stock/invalid_transition) 반영 예정 항목quantity·allocated 필드 · 금액 문자열 직렬화 · product_code 의미 차이 · 동일 상품 합산 판정 · 알려진 제약 5건 · SCM→채널 상품정보 조회(역방향 실재) 반영is_backorder) 규격 추가