출고 연동
입고가 완료된 상품 100개 중 20개를 예약하고 그중 12개를 출고 요청한 뒤, 출고 완료 수량을 조회하는 예제입니다. 5개가 먼저 출고되는 부분 완료와 12개 전체 완료를 구분합니다. 전체 업무 흐름의 수량 예제와 같은 흐름이며, 각 수량의 정의와 규칙은 재고와 예약에서 확인할 수 있습니다.
시작 전: 연결 준비의 환경 변수를 설정하고, 출고할 SKU의 재고 반영을 확인하세요. 상품과 입고는 앞선 가이드를 참고합니다. Maybox 담당자와 테스트 출고 및 실제 창고 작업 범위를 맞춘 뒤 실행합니다.
전체 흐름
섹션 제목: “전체 흐름”- 고객사 · 수량 확인과 예약: 가용 수량과 미사용 예약 수량을 조회하고, 새로 필요한 수량만 예약합니다.
- 고객사 · 출고 요청: 작업을 시작해도 되는 SKU·수량을 제출하고
outboundId를 저장합니다. - 고객사 · 인계 계획 / 창고 · 작업: 고객사는 인계 예정 정보를 등록하고, 창고는 피킹·포장과 실제 인계를 진행합니다.
- 고객사 · 결과 조회: 출고 완료 수량과 남은 수량, 요청 전체의 상태를 조회합니다. 운송장 번호만으로 출고 완료를 판단하지 않습니다.
재고 수량 읽기
섹션 제목: “재고 수량 읽기”첫 연결 확인과 같은 GET /api/v1/stock?sku=DEMO-SERUM-001로 최신 수량을 가져옵니다.
| 항목 | 사용 목적 |
|---|---|
onHandQuantity |
입고·재고 정정 등으로 재고에 반영됐고 아직 출고하지 않은 수량. 예약·출고 준비 중인 수량도 포함 |
reservedQuantity |
전체 예약 수량 |
availableQuantity |
새로 예약할 수 있는 수량 |
securedOutboundQuantity |
진행 중인 출고가 확보한 예약 수량 |
unusedReservedQuantity |
새 출고에 사용하거나 예약 해제할 수 있는 수량 |
예약 수량은 고객사와 SKU별로 합산해 관리합니다. 개별 주문이나 호출자가 예약을 소유하지 않으며, 예약 ID를 지정해 출고하는 방식도 아닙니다. 주문별로 사용할 수량과 우선순위는 고객사 시스템에서 관리합니다.
다음으로 갈 조건: 아래 예제처럼 20개를 새로 예약하려면 availableQuantity가 20개 이상이어야 합니다. 이번 출고에 필요한 미사용 예약 수량(unusedReservedQuantity) 12개가 이미 확보돼 있다면 추가 예약 없이 출고 요청으로 진행할 수 있습니다. 조회와 변경 사이에 수량은 달라질 수 있습니다.
출고에 필요한 수량 예약
섹션 제목: “출고에 필요한 수량 예약”예제에서는 재고 반영을 확인한 뒤 20개를 새로 예약하고, 그중 12개를 이번 출고에 사용합니다. 이미 충분한 미사용 예약 수량이 있다면 중복해서 예약하지 않습니다.
reservation.json:
{ "sku": "DEMO-SERUM-001", "quantity": 20 }curl --fail-with-body --silent --show-error \ --request POST --data-binary @reservation.json --config - <<EOFurl = "${MAYBOX_API_ORIGIN}/api/v1/stock/reservations"header = "Authorization: Bearer ${MAYBOX_API_CREDENTIAL}"header = "Content-Type: application/json"header = "Idempotency-Key: demo-outbound-20261113-001-reserve"EOF성공 응답 예시:
{ "reservationEventId": "3001" }다음 단계: 예약 성공을 기록하고 출고 요청으로 진행합니다. reservationEventId는 예약 이벤트의 식별자이며, 출고 요청에 이 ID로 예약을 지정하지 않습니다.
최신 가용 수량이 부족하면 422 RESERVATION.INSUFFICIENT_AVAILABLE_QUANTITY입니다. 조회 뒤 다른 처리로 수량이 바뀔 수 있으므로 변경 API의 결과로 성공 여부를 판단합니다.
출고 요청
섹션 제목: “출고 요청”모든 SKU 행에 충분한 unusedReservedQuantity가 있어야 합니다. 아래 예제는 추가 인계 준비 지시가 필요 없는 NOT_REQUIRED입니다. 팔레트 구성이나 문서 부착 같은 추가 지시를 고객사에서 조율하려면 생성할 때 CONFIRMATION_REQUIRED를 선택하고 지시 등록과 최종 확정을 진행합니다. 이 정책은 출고 전체의 작업 시작 승인을 뜻하지 않습니다.
outbound.json:
{ "externalReference": "DEMO-ORDER-20261113-001", "dispatchPreparationConfirmationPolicy": "NOT_REQUIRED", "note": "테스트 출고 연동 확인", "lines": [ { "sku": "DEMO-SERUM-001", "skuName": "데모 세럼 30ml", "brandName": "데모 브랜드", "quantity": 12, "unitLabelingTasks": [] } ]}curl --fail-with-body --silent --show-error \ --request POST --data-binary @outbound.json --config - <<EOFurl = "${MAYBOX_API_ORIGIN}/api/v1/outbounds"header = "Authorization: Bearer ${MAYBOX_API_CREDENTIAL}"header = "Content-Type: application/json"header = "Idempotency-Key: demo-outbound-20261113-001-create"EOF성공 응답 예시:
{ "outboundId": "4001" }출고 생성에는 모든 SKU 행에서 충분한 unusedReservedQuantity가 필요합니다. 부족하면 422 OUTBOUND.INSUFFICIENT_RESERVED_QUANTITY로 출고 전체가 생성되지 않습니다. 예약 API와 출고 생성 API는 별도 처리이므로, 예약 성공 뒤 출고 생성이 실패했다면 다시 조회해 재시도 또는 불필요한 예약 해제를 판단합니다.
응답을 받은 뒤: outboundId를 고객사 주문·출고 ID와 연결해 저장합니다. 생성 성공은 출고 완료를 뜻하지 않습니다. 창고 작업 진행은 출고 결과로 확인합니다.
다른 변경이 없는 예제에서는 예약 20개 중 12개를 이번 출고가 확보하고, 미사용 예약 수량은 8개가 됩니다.
인계 계획 등록
섹션 제목: “인계 계획 등록”인계는 창고가 상품을 운송사나 픽업 담당자에게 넘기는 작업입니다. 출고 요청과 별도로 인계 예정 정보를 Dispatch로 등록합니다. 다음은 픽업 인계 예제입니다.
dispatch.json:
{ "scheduledDispatchDate": "2026-11-22T15:00:00.000Z", "handoffNote": "픽업 담당자와 시간은 창고 담당자에게 사전 전달", "handoffMethod": "PICKUP"}export MAYBOX_OUTBOUND_ID='4001'
curl --fail-with-body --silent --show-error \ --request POST --data-binary @dispatch.json --config - <<EOFurl = "${MAYBOX_API_ORIGIN}/api/v1/outbounds/${MAYBOX_OUTBOUND_ID}/dispatches"header = "Authorization: Bearer ${MAYBOX_API_CREDENTIAL}"header = "Content-Type: application/json"header = "Idempotency-Key: demo-outbound-20261113-001-dispatch-create"EOF성공 응답 예시:
{ "outboundId": "4001", "dispatchId": "5001" }MAYBOX_OUTBOUND_ID에는 실제 생성 응답을 설정합니다. 예제 예정일은 서울 기준 2026년 11월 23일입니다. 택배 인계에는 handoffMethod: "PARCEL"과 parcelRecipient의 name·address·phone이 필요합니다. 인계 계획 등록만으로 운송사 예약·운임 결제·라벨 발급·인계 완료가 처리되지는 않습니다.
출고 결과와 운송장 조회
섹션 제목: “출고 결과와 운송장 조회”창고 작업을 기다리며 조회하는 단계입니다. 고객사 시스템에서 피킹·포장·실제 인계를 완료 처리하지 않습니다. 변경 알림을 받거나 상세를 조회해 결과를 반영합니다.
curl --fail-with-body --silent --show-error --config - <<EOFurl = "${MAYBOX_API_ORIGIN}/api/v1/outbounds/${MAYBOX_OUTBOUND_ID}"header = "Authorization: Bearer ${MAYBOX_API_CREDENTIAL}"EOFstatus는 IN_PROGRESS·COMPLETED·CANCELED입니다. SKU별로 다음 수량을 함께 읽습니다.
| 항목 | 의미 |
|---|---|
lines[].requestedQuantity |
요청한 수량 |
lines[].packedQuantity |
포장된 수량. 아직 출고하지 않은 물량도 포함 |
lines[].dispatchedQuantity |
출고 완료 수량. 실제로 창고 밖으로 나간 누계 |
| 요청 수량 − 출고 완료 수량 | 아직 출고하지 않은 남은 수량 |
부분 완료와 요청 전체 완료
섹션 제목: “부분 완료와 요청 전체 완료”다음은 12개 중 5개가 먼저 출고된 시점의 응답 일부입니다. 전체 응답에는 포장·팔레트 구성과 개별 인계 결과(dispatches) 등 다른 필드도 포함됩니다.
{ "outboundId": "4001", "status": "IN_PROGRESS", "completedAt": null, "lines": [ { "sku": "DEMO-SERUM-001", "requestedQuantity": 12, "packedQuantity": 12, "dispatchedQuantity": 5 } ]}현재고·예약이 각각 100개·20개였고 다른 변동이 없다면 다음처럼 바뀝니다.
| 출고 완료 수량 | 출고 상태 | 현재고 | 예약 | 가용 |
|---|---|---|---|---|
| 0 | IN_PROGRESS |
100 | 20 | 80 |
| 5 | IN_PROGRESS |
95 | 15 | 80 |
| 12 | COMPLETED |
88 | 8 | 80 |
부분 완료라도 출고된 수량부터 현재고와 예약에서 빠집니다. 남은 7개는 진행 중인 출고가 계속 확보합니다. 모든 SKU의 요청 수량이 출고돼야 요청 전체가 COMPLETED가 됩니다. 이미 예약한 물량이 출고되는 것이므로 가용 수량은 80개로 유지됩니다.
창고에서는 운송사나 픽업 담당자에게 실제로 넘긴 인계 결과를 기록할 때 출고 완료 수량을 반영합니다. 포장 완료나 인계 계획 등록만으로 출고 완료 수량이 늘지는 않습니다.
운송장 조회
섹션 제목: “운송장 조회”창고에 국내 운송장 번호가 등록돼 있다면 다음 API로 조회합니다.
curl --fail-with-body --silent --show-error --config - <<EOFurl = "${MAYBOX_API_ORIGIN}/api/v1/outbounds/${MAYBOX_OUTBOUND_ID}/domestic-waybills"header = "Authorization: Bearer ${MAYBOX_API_CREDENTIAL}"EOF성공 응답 예시:
{ "waybills": [{ "packageId": "6001", "number": "DEMO-WAYBILL-001" }] }packageId를 출고 상세의 packing.packages와 연결하면 어느 박스의 번호인지 알 수 있습니다. 아직 번호가 등록되지 않은 박스는 응답 목록에 없습니다. 운송장 번호만으로 출고 완료를 판단하지 않으며, 출고 후 번호가 정정될 수도 있습니다.
이 가이드의 완료 기준: 고객사 시스템이 출고 생성·부분 완료·요청 전체 완료를 구분하고, SKU별 출고 완료 수량과 남은 수량을 업무에 반영할 수 있습니다. 개별 인계 결과와 운송장도 함께 조회합니다. 취소가 필요하면 아래 절차를 따릅니다.
출고 취소와 예약 해제
섹션 제목: “출고 취소와 예약 해제”출고 취소는 POST /api/v1/outbounds/{outboundId}/cancellation입니다. body 없이 새 Idempotency-Key를 지정합니다. 실제 인계 등 진행 상태에 따라 취소할 수 없으면 409 OUTBOUND.NOT_CANCELABLE입니다.
공개 API의 출고 취소는 예약을 자동 해제하지 않습니다. 불필요한 미사용 예약 수량은 최신 unusedReservedQuantity를 확인한 뒤 POST /api/v1/stock/reservation-releases로 해제합니다. 예를 들어 이번 출고에 쓰려던 12개가 필요 없어졌다면 { "sku": "DEMO-SERUM-001", "quantity": 12 }를 제출할 수 있습니다. 실제 해제할 수량은 다른 주문과 출고에 필요한 예약도 고려해 결정합니다. 다른 출고가 사용 중인 수량은 해제할 수 없습니다.