--- title: "주문" description: "Orders API로 주문 정보를 조회하고 아이템 지급 기록을 관리하는 방법을 알아봅니다." source: "https://docs.tokenz.one/ko-KR/v2/order" api_version: "v2" locale: "ko-KR" version_status: "current" docs_stage: "prod" --- # 주문 Orders API로 주문 정보를 조회하고 아이템 지급 기록을 관리하는 방법을 알아봅니다. Order API는 주문 관리를 위한 세 개의 독립 엔드포인트를 제공합니다. 주문 조회 API로 상태, 아이템, 고객 정보 등 상세 주문 정보를 확인할 수 있습니다. 주문 취소 API로 더 이상 진행할 필요가 없는 주문을 취소하고, 아이템 지급 기록 등록 API로 유연한 구조의 아이템 지급 기록을 등록하여 주문 이행을 추적할 수 있습니다. 주문은 판매자가 Checkout Session을 생성할 때 자동으로 생성되며, 아이템, 금액, 고객 정보 등 모든 구매 내역을 포함합니다. **금액 형식:** 모든 금액 값(`amount` 필드 등)은 각 통화의 최소 단위로 표시합니다. 통화별 정확한 형식은 [지원 통화](https://docs.tokenz.one/ko-KR/v2/checkout/currency)를 참고하세요. ## 개요 주문 시스템의 주요 API 엔드포인트는 다음과 같습니다. - **주문 조회 API**: 상태, 아이템, 고객 정보 등 상세 주문 정보를 조회합니다. - **주문 취소 API**: 주문을 취소하고 `canceledAt` 타임스탬프가 포함된 변경된 주문 상태를 받습니다. - **아이템 지급 기록 등록 API**: 유연하게 아이템 지급 기록을 등록합니다. 모든 JSON 구조를 수락하며 중요 필드에 대한 경고와 제안을 제공합니다. 이 API들은 독립적으로 동작합니다. 언제든 주문 정보를 조회하고, 아이템을 지급할 때 기록을 등록할 수 있습니다. 아이템 지급 기록 등록 API는 모든 유효한 JSON 페이로드를 수락하며, 경고 시스템으로 중요한 정보를 포함하도록 안내합니다. ## 주문 수명 주기 결제가 처리됨에 따라 주문 상태가 자동으로 변경됩니다. 1. **주문 생성**: 판매자가 Checkout Session을 생성하면 주문이 자동 생성됩니다. 2. **주문 처리**: `requiresPayment` → `processing` → `succeeded` 순서로 진행됩니다. 3. **주문 조회**: Orders API로 주문 이행과 추적에 필요한 정보를 조회합니다. 4. **지급 등록**: 주문 이행 시 지급 정보를 별도로 등록합니다. ### 주문 상태 값 주문은 다음 상태를 가집니다. - `requiresPayment`: 아직 결제를 기다리는 주문입니다. - `processing`: 결제가 접수되어 주문을 처리 중입니다. - `succeeded`: 주문이 성공적으로 완료되었습니다. - `failed`: 처리 후 주문이 실패했습니다. - `blocked`: 추가 작업이 일시적으로 차단된 주문입니다. - `canceled`: 취소되어 더 이상 처리하지 않는 주문입니다. - `expired`: 만료되어 더 이상 유효하지 않은 주문입니다. ```mermaid sequenceDiagram; autonumber; participant M as 판매자 앱; participant T as Tokenz API; participant DB as 주문 데이터베이스; %% Order Retrieval Flow; Note over M,DB: 주문 조회 API; M->>T: GET /v2/order/{id}; T->>DB: 주문 상세 조회; DB-->>T: 주문 데이터 반환; T-->>M: 주문 상세 정보; %% Delivery Registration Flow (Independent); Note over M,DB: 아이템 지급 기록 등록 API; M->>T: POST /v2/order/{orderId}/delivery; T->>DB: 아이템 지급 기록 저장; T-->>M: 아이템 지급 기록 등록 확인; ``` ## API 호출 예제 ### 주문 조회 API ID로 특정 주문의 상세 정보를 조회합니다. 주문 ID는 Checkout Session 생성 응답이나 웹훅에서 확인할 수 있습니다. ```bash curl --request GET \ --url https://api.tokenz.one/v2/order/{YOUR_ORDER_ID} \ --header 'Authorization: Bearer secret_test_YOUR_KEY_HERE' \ --header 'Content-Type: application/json' ``` **응답:** ```json { "id": "order_1D5xA9BnKfv_t", "object": "order", "status": "requiresPayment", "amount": { "amount": 3700, "currency": "JPY" }, "items": [ { "id": "item_1D6F8mR5TnK_t", "detail": { "product": { "price": { "amount": 1200, "currency": "JPY" }, "quantity": 3, "label": "ひとにぎりのエメラルド", "description": "80+8", "images": [ "https://images.ctfassets.net/z82qbo7cv7ia/1dWPbk5Qx2M1Qikj6Knyuc/e37b2c26829c0d30793a348ae3adb3b0/fake-pass.webp" ] } } }, { "id": "item_1xejV7puGeK_t", "detail": { "product": { "price": { "amount": 100, "currency": "JPY" }, "quantity": 1, "label": "Diamond", "description": "", "images": [], "sku": "sku_103843dfjhdfgiu", "taxCategory": "VIRTUAL_CURRENCY" } } } ], "description": "Game items purchase", "reference": "ORDER_2024_001", "test": true, "expiresAt": "2024-12-31T23:59:59Z", "createdAt": "2024-01-15T10:00:00Z", "updatedAt": "2024-01-15T10:05:30Z" } ``` ### 주문 취소 API 더 이상 진행하지 않을 기존 주문을 취소합니다. 요청 본문은 필요하지 않으며 경로에 주문 ID만 지정합니다. ```bash curl --request POST \ --url https://api.tokenz.one/v2/order/{YOUR_ORDER_ID}/cancel \ --header 'Authorization: Bearer secret_test_YOUR_KEY_HERE' \ --header 'Content-Type: application/json' ``` **응답:** ```json { "id": "order_1D5xA9BnKfv_t", "object": "order", "status": "canceled", "amount": { "amount": 3700, "currency": "JPY" }, "items": [ { "id": "item_1D6F8mR5TnK_t", "detail": { "product": { "price": { "amount": 1200, "currency": "JPY" }, "quantity": 3, "label": "ひとにぎりのエメラルド", "description": "80+8", "images": [ "https://images.ctfassets.net/z82qbo7cv7ia/1dWPbk5Qx2M1Qikj6Knyuc/e37b2c26829c0d30793a348ae3adb3b0/fake-pass.webp" ] } } }, { "id": "item_1xejV7puGeK_t", "detail": { "product": { "price": { "amount": 100, "currency": "JPY" }, "quantity": 1, "label": "Diamond", "description": "", "images": [], "sku": "sku_103843dfjhdfgiu", "taxCategory": "VIRTUAL_CURRENCY" } } } ], "description": "Game items purchase", "reference": "ORDER_2024_001", "test": true, "expiresAt": "2024-12-31T23:59:59Z", "createdAt": "2024-01-15T10:00:00Z", "updatedAt": "2024-01-15T10:05:30Z", "canceledAt": "2024-01-15T10:05:32Z" } ``` 이미 성공한 주문 등 취소할 수 없는 상태라면 `422 Unprocessable Entity`와 `order.status-invalid` 오류 코드를 반환합니다. ### 아이템 지급 기록 등록 API 유연한 페이로드로 주문의 지급 정보를 등록합니다. 모든 유효한 JSON 구조를 수락하고, 요청을 개선할 수 있도록 경고와 제안을 반환합니다. **참고**: 같은 주문에 여러 번 호출하여 부분 지급을 추적할 수 있습니다. 예를 들어 주문의 여러 아이템을 서로 다른 시각에 지급한다면 각 지급마다 호출할 수 있습니다. 호출마다 독립적인 아이템 지급 기록이 생성되어 이행 진행 상황을 정확히 추적할 수 있습니다. ```bash curl --request POST \ --url https://api.tokenz.one/v2/order/{YOUR_ORDER_ID}/delivery \ --header 'Authorization: Bearer secret_test_YOUR_KEY_HERE' \ --header 'Content-Type: application/json' \ --data '{ "at": "2025-01-15T10:30:00Z", "user": { "userId": "user_67890", "phoneNumber": "+1234567890", "emailAddress": "test-user@example.com" }, "items": [ { "sku": "TEST-SKU-001", "name": "Test Product for Delivery", "itemId": "item_12345", "itemChange": { "inAppBalanceAfter": 102, "inAppBalanceBefore": 100 }, "deliveredQuantity": 2 } ], "status": "succeeded", "metadata": { "customField": "test_value", "merchantNotes": "Successfully delivered via API", "deliveryChannel": "api" }, "progress": "completed", "cartContext": { "deviceId": "device_abc123", "timestamp": "2025-01-15T10:00:00Z", "ipAddress": "192.168.1.100", "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)", "geoLocation": { "lat": 37.7749, "lon": -122.4194, "region": "US" } }, "deliveryInfo": { "deliveryMethod": "digital_download", "confirmationType": "email", "confirmationProof": "delivery_confirmation_12345" }, "deliveryContext": { "deviceId": "device_abc123", "timestamp": "2025-01-15T10:30:00Z", "ipAddress": "192.168.1.100", "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" } }' ``` **응답:** ```json { "success": true, "message": "Delivery record has been registered successfully" } ``` `warnings`와 `suggestions` 배열이 비어 있으면 응답에서 생략됩니다. 포함될 경우 페이로드에서 누락되거나 개선이 필요한 필드를 설명하는 문자열이 들어 있습니다. ## API의 유연성과 안내 아이템 지급 기록 등록 API는 **모든 유효한 JSON 구조를 제출**할 수 있도록 설계되었습니다. 다만 지급 추적에 더 유용하게 활용할 수 있도록 응답에서 경고와 제안을 제공합니다. ### 경고 및 제안 시스템 아이템 지급 기록을 등록하면 API가 페이로드를 분석하여 다음 안내를 반환합니다. - **경고**: 효과적인 지급 추적을 위해 강력히 권장되는 핵심 필드가 없거나 유효하지 않으면 알립니다. - **제안**: 분석, 부정 거래 탐지, 지급 최적화에 도움이 되는 선택 필드를 권장합니다. 간단하게 시작한 후 제공되는 피드백에 따라 점진적으로 연동을 개선할 수 있습니다. ### 필드 정의 및 중요도 #### 상태 및 진행 열거형 **`status`**: 개별 지급 상태 - `succeeded` - 해당 지급이 완료되었습니다. - `failed` - 해당 지급이 실패했습니다. **`progress`**: 전체 주문 이행 진행 상태 - `completed` - 주문의 모든 아이템이 지급되었습니다. - `in_progress` - 일부 아이템은 지급되었고 나머지는 대기 중입니다. - `pending` - 아직 어떤 아이템도 지급되지 않았습니다. **주요 차이**: 여러 아이템을 나누어 지급하는 주문에서는 다음과 같이 구분합니다. - `status`는 각 개별 지급을 추적합니다. - `progress`는 전체 주문 이행을 추적합니다. - 예: 아이템 3개를 두 번에 나누어 지급하면 각각의 `status`를 가진 아이템 지급 기록 2개가 생성되고, `progress`는 3개 모두 지급되었는지 나타냅니다. #### 필드 중요도 분류 연동 우선순위를 정할 수 있도록 필드를 중요도에 따라 분류합니다. **핵심 필드**(누락되거나 유효하지 않으면 경고): - `status`: 지급 상태(위 열거형 참고) - `progress`: 지급 진행 상태(위 열거형 참고) - `at`: 지급 시각의 ISO 8601 타임스탬프 - `cartContext.timestamp`: `cartContext`가 있을 경우 해당 객체의 타임스탬프 - `deliveryContext.timestamp`: `deliveryContext`가 있을 경우 해당 객체의 타임스탬프 **권장 필드**(누락 시 제안): - `items`: 상세 정보를 포함한 지급 아이템 배열 - `items[].deliveredQuantity`: 각 아이템의 지급 수량 - `items[].itemChange.inAppBalanceBefore/After`: 잔액 추적의 핵심 정보 - `user`: 개인화된 분석을 위한 사용자 정보 - `user.userId`: 지급 추적용 사용자 식별자 - `user.emailAddress`: 식별용 사용자 이메일 - `deliveryContext`: 부정 거래 탐지용 맥락 정보 - `deliveryInfo`: 지급 방식 및 확인 정보 **선택 필드**(경고는 없지만 유용): - `metadata`: 용도에 맞춘 사용자 정의 필드. 형식: Map - `cartContext`: 원래 구매의 맥락 정보 - 지리적 위치 데이터 ## 아이템 지급 기록 데이터 구조 모든 유효한 JSON 구조를 허용하지만, 분쟁 발생 시 사업을 보호할 수 있도록 **포괄적인 지급 정보를 제공하는 것을 강력히 권장합니다.** 기록이 상세할수록 문제 발생 시 증빙이 강해집니다. 위 curl 예제처럼 사용 가능한 모든 필드를 포함한 전체 페이로드를 전송하는 것을 권장합니다. ### 상세 기록이 분쟁에 중요한 이유 분쟁에 대비하려면 완전한 지급 정보가 필요합니다. - **증빙 자료**: 상세 기록은 고객이 이의를 제기할 때 지급 증거가 됩니다. - **시점 확인**: 타임스탬프와 맥락 정보로 지급 시점과 방식을 입증합니다. - **아이템 추적**: 정확히 어떤 아이템을 얼마나 지급했는지 입증합니다. API는 최소 데이터도 수락하지만 기록이 불완전하면 분쟁 시 증빙이 부족할 수 있습니다. 사용 가능한 모든 정보를 포함하여 포괄적인 감사 추적을 유지하세요. ## 응답 상태 코드 Orders API는 표준 HTTP 상태 코드와 상세 오류 메시지를 반환합니다. - `200 OK`: 주문 조회 또는 취소에 성공했습니다. - `201 Created`: 아이템 지급 기록 등록에 성공했습니다. - `400 Bad Request`: 요청 형식이 잘못되었거나 필수 필드가 누락되었습니다. - `401 Unauthorized`: API 키가 없거나 유효하지 않습니다. - `403 Forbidden`: 요청한 리소스에 대한 접근이 거부되었습니다. - `404 Not Found`: 주문이 없거나 접근이 거부되었습니다. - `422 Unprocessable Entity`: 현재 주문 상태에서 허용되지 않는 작업입니다(예: 완료된 주문 취소 시 `order.status-invalid`). - `500 Server Error`: 내부 서버 오류가 발생했습니다. 모든 오류 응답에는 코드에서 처리할 수 있도록 오류 코드와 메시지를 담은 구조화된 오류 객체가 포함됩니다. ### 오류 응답 예제 ```json { "status": 404, "code": "entity.not-found", "message": "The requested order could not be found." } ``` ## 주문 웹훅 주문 이벤트 알림을 수신하도록 웹훅을 설정하세요. ### `order.created` 주문이 생성되면 발생합니다. ```json { "id": "d4e5f6a7-b8c9-0123-defa-234567890abc", "object": "order.created", "createdAt": "2024-01-15T10:00:00Z", "test": true, "eventData": { "type": "order", "version": "v2", "data": { "order": { "id": "order_1D5xA9BnKfv_t", "object": "order", "status": "requiresPayment", "amount": { "amount": 3700, "currency": "JPY" }, "consumerAmount": { "amount": 3700, "currency": "JPY" }, "items": [ { "id": "item_1D6F8mR5TnK_t", "detail": { "product": { "price": { "amount": 3700, "currency": "JPY" }, "quantity": 1, "label": "Game Item Bundle", "description": "In-game items", "images": [] } } } ], "description": "Game items purchase", "reference": "ORDER_2024_001", "test": true, "expiresAt": "2024-01-16T10:00:00Z", "createdAt": "2024-01-15T10:00:00Z", "updatedAt": "2024-01-15T10:00:00Z", "regionCode": "JP" } } } } ``` ### `order.succeeded` 결제 후 주문이 성공적으로 완료되면 발생합니다. ```json { "id": "e5f6a7b8-c9d0-1234-efab-345678901def", "object": "order.succeeded", "createdAt": "2024-01-15T10:45:00Z", "test": true, "eventData": { "type": "order", "version": "v2", "data": { "order": { "id": "order_1D5xA9BnKfv_t", "object": "order", "status": "succeeded", "amount": { "amount": 3700, "currency": "JPY" }, "consumerAmount": { "amount": 3700, "currency": "JPY" }, "items": [ { "id": "item_1D6F8mR5TnK_t", "detail": { "product": { "price": { "amount": 3700, "currency": "JPY" }, "quantity": 1, "label": "Game Item Bundle", "description": "In-game items", "images": [] } } } ], "description": "Game items purchase", "reference": "ORDER_2024_001", "test": true, "expiresAt": "2024-01-16T10:00:00Z", "createdAt": "2024-01-15T10:00:00Z", "updatedAt": "2024-01-15T10:45:00Z", "regionCode": "JP" } } } } ``` ### `order.expired` 완료되지 않은 채 만료 시각에 도달하면 발생합니다. ```json { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "object": "order.expired", "createdAt": "2024-12-31T23:59:59Z", "test": true, "eventData": { "type": "order", "version": "v2", "data": { "order": { "id": "order_1D5xA9BnKfv_t", "object": "order", "status": "expired", "amount": { "amount": 3700, "currency": "JPY" }, "consumerAmount": { "amount": 3700, "currency": "JPY" }, "items": [ { "id": "item_1D6F8mR5TnK_t", "detail": { "product": { "price": { "amount": 3700, "currency": "JPY" }, "quantity": 1, "label": "Game Item Bundle", "description": "In-game items", "images": [] } } } ], "description": "Game items purchase", "reference": "ORDER_2024_001", "test": true, "expiresAt": "2024-12-31T23:59:59Z", "createdAt": "2024-01-15T10:00:00Z", "updatedAt": "2024-12-31T23:59:59Z", "regionCode": "JP" } } } } ``` ### `order.canceled` 주문이 취소되면 발생합니다. ```json { "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "object": "order.canceled", "createdAt": "2024-01-15T10:05:32Z", "test": true, "eventData": { "type": "order", "version": "v2", "data": { "order": { "id": "order_1D5xA9BnKfv_t", "object": "order", "status": "canceled", "amount": { "amount": 3700, "currency": "JPY" }, "consumerAmount": { "amount": 3700, "currency": "JPY" }, "items": [ { "id": "item_1D6F8mR5TnK_t", "detail": { "product": { "price": { "amount": 3700, "currency": "JPY" }, "quantity": 1, "label": "Game Item Bundle", "description": "In-game items", "images": [] } } } ], "description": "Game items purchase", "reference": "ORDER_2024_001", "test": true, "createdAt": "2024-01-15T10:00:00Z", "updatedAt": "2024-01-15T10:05:32Z", "canceledAt": "2024-01-15T10:05:32Z", "regionCode": "JP" } } } } ``` ### `order.failed` 주문이 실패하면 발생합니다. ```json { "id": "c3d4e5f6-a7b8-9012-cdef-123456789012", "object": "order.failed", "createdAt": "2024-01-15T11:00:00Z", "test": true, "eventData": { "type": "order", "version": "v2", "data": { "order": { "id": "order_1D5xA9BnKfv_t", "object": "order", "status": "failed", "amount": { "amount": 3700, "currency": "JPY" }, "consumerAmount": { "amount": 3700, "currency": "JPY" }, "items": [ { "id": "item_1D6F8mR5TnK_t", "detail": { "product": { "price": { "amount": 3700, "currency": "JPY" }, "quantity": 1, "label": "Game Item Bundle", "description": "In-game items", "images": [] } } } ], "description": "Game items purchase", "reference": "ORDER_2024_001", "test": true, "createdAt": "2024-01-15T10:00:00Z", "updatedAt": "2024-01-15T11:00:00Z", "regionCode": "JP" } } } } ``` ## 권장 사항 ### 주문 및 아이템 지급 기록 관리 - 나중에 참조할 수 있도록 시스템에 주문 ID를 저장하세요. - 웹훅으로 실시간 주문 상태 업데이트를 받으세요. - 자체 아이템 지급 기록을 유지하고 지급 후 즉시 등록하세요. API는 분쟁 해결을 위한 백업 저장소이며, 지급 데이터의 원본은 자체 시스템에 있어야 합니다. - 부분 지급 시 각 묶음마다 아이템 지급 기록 등록 API를 호출하세요. 호출별로 별도 기록이 생성되어 여러 번에 걸친 지급을 정확히 추적할 수 있습니다. ### 아이템 지급 기록 등록 API 연동 전략 - 포괄적인 페이로드로 경고를 줄이고 추적 기능을 최대한 활용하세요. - 모든 권장 필드(`at`, `user`, `items`, `deliveryContext`, `deliveryInfo`)를 포함하세요. - 모든 타임스탬프(`at`, `cartContext.timestamp`, `deliveryContext.timestamp`)에 ISO 8601 형식을 사용하고 2024-03-01T00:00:00.000Z 이후인지 확인하세요.