주문
Orders API로 주문 정보를 조회하고 아이템 지급 기록을 관리하는 방법을 알아봅니다.
Order API는 주문 관리를 위한 세 개의 독립 엔드포인트를 제공합니다. 주문 조회 API로 상태, 아이템, 고객 정보 등 상세 주문 정보를 확인할 수 있습니다. 주문 취소 API로 더 이상 진행할 필요가 없는 주문을 취소하고, 아이템 지급 기록 등록 API로 유연한 구조의 아이템 지급 기록을 등록하여 주문 이행을 추적할 수 있습니다.
주문은 판매자가 Checkout Session을 생성할 때 자동으로 생성되며, 아이템, 금액, 고객 정보 등 모든 구매 내역을 포함합니다.
금액 형식: 모든 금액 값(amount 필드 등)은 각 통화의 최소 단위로 표시합니다. 통화별 정확한 형식은 지원 통화를 참고하세요.
개요
주문 시스템의 주요 API 엔드포인트는 다음과 같습니다.
- 주문 조회 API: 상태, 아이템, 고객 정보 등 상세 주문 정보를 조회합니다.
- 주문 취소 API: 주문을 취소하고
canceledAt타임스탬프가 포함된 변경된 주문 상태를 받습니다. - 아이템 지급 기록 등록 API: 유연하게 아이템 지급 기록을 등록합니다. 모든 JSON 구조를 수락하며 중요 필드에 대한 경고와 제안을 제공합니다.
이 API들은 독립적으로 동작합니다. 언제든 주문 정보를 조회하고, 아이템을 지급할 때 기록을 등록할 수 있습니다. 아이템 지급 기록 등록 API는 모든 유효한 JSON 페이로드를 수락하며, 경고 시스템으로 중요한 정보를 포함하도록 안내합니다.
주문 수명 주기
결제가 처리됨에 따라 주문 상태가 자동으로 변경됩니다.
- 주문 생성: 판매자가 Checkout Session을 생성하면 주문이 자동 생성됩니다.
- 주문 처리:
requiresPayment→processing→succeeded순서로 진행됩니다. - 주문 조회: Orders API로 주문 이행과 추적에 필요한 정보를 조회합니다.
- 지급 등록: 주문 이행 시 지급 정보를 별도로 등록합니다.
주문 상태 값
주문은 다음 상태를 가집니다.
requiresPayment: 아직 결제를 기다리는 주문입니다.processing: 결제가 접수되어 주문을 처리 중입니다.succeeded: 주문이 성공적으로 완료되었습니다.failed: 처리 후 주문이 실패했습니다.blocked: 추가 작업이 일시적으로 차단된 주문입니다.canceled: 취소되어 더 이상 처리하지 않는 주문입니다.expired: 만료되어 더 이상 유효하지 않은 주문입니다.
API 호출 예제
주문 조회 API
ID로 특정 주문의 상세 정보를 조회합니다. 주문 ID는 Checkout Session 생성 응답이나 웹훅에서 확인할 수 있습니다.
curl --request GET \
--url https://api.tokenz.one/v1/order/{YOUR_ORDER_ID} \
--header 'Authorization: Bearer secret_test_YOUR_KEY_HERE' \
--header 'Content-Type: application/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만 지정합니다.
curl --request POST \
--url https://api.tokenz.one/v1/order/{YOUR_ORDER_ID}/cancel \
--header 'Authorization: Bearer secret_test_YOUR_KEY_HERE' \
--header 'Content-Type: application/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 구조를 수락하고, 요청을 개선할 수 있도록 경고와 제안을 반환합니다.
참고: 같은 주문에 여러 번 호출하여 부분 지급을 추적할 수 있습니다. 예를 들어 주문의 여러 아이템을 서로 다른 시각에 지급한다면 각 지급마다 호출할 수 있습니다. 호출마다 독립적인 아이템 지급 기록이 생성되어 이행 진행 상황을 정확히 추적할 수 있습니다.
curl --request POST \
--url https://api.tokenz.one/v1/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)"
}
}'
응답:
{
"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<String, String>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: 내부 서버 오류가 발생했습니다.
모든 오류 응답에는 코드에서 처리할 수 있도록 오류 코드와 메시지를 담은 구조화된 오류 객체가 포함됩니다.
오류 응답 예제
{
"status": 404,
"code": "entity.not-found",
"message": "The requested order could not be found."
}
주문 웹훅
주문 이벤트 알림을 수신하도록 웹훅을 설정하세요.
order.created
주문이 생성되면 발생합니다.
{
"id": "d4e5f6a7-b8c9-0123-defa-234567890abc",
"object": "order.created",
"createdAt": "2024-01-15T00:00:00Z",
"test": true,
"eventData": {
"type": "order",
"version": "v1",
"data": {
"order": {
"id": "order_1D5xA9BnKfv_t",
"object": "order",
"status": "requiresPayment",
"amount": {
"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
결제 후 주문이 성공적으로 완료되면 발생합니다.
{
"id": "e5f6a7b8-c9d0-1234-efab-345678901def",
"object": "order.succeeded",
"createdAt": "2024-01-15T00:45:00Z",
"test": true,
"eventData": {
"type": "order",
"version": "v1",
"data": {
"order": {
"id": "order_1D5xA9BnKfv_t",
"object": "order",
"status": "succeeded",
"amount": {
"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
완료되지 않은 채 만료 시각에 도달하면 발생합니다.
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"object": "order.expired",
"createdAt": "2024-12-31T23:59:59Z",
"test": true,
"eventData": {
"type": "order",
"version": "v1",
"data": {
"order": {
"id": "order_1D5xA9BnKfv_t",
"object": "order",
"status": "expired",
"amount": {
"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
주문이 취소되면 발생합니다.
{
"id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"object": "order.canceled",
"createdAt": "2024-01-15T10:05:32Z",
"test": true,
"eventData": {
"type": "order",
"version": "v1",
"data": {
"order": {
"id": "order_1D5xA9BnKfv_t",
"object": "order",
"status": "canceled",
"amount": {
"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
주문이 실패하면 발생합니다.
{
"id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
"object": "order.failed",
"createdAt": "2024-01-15T11:00:00Z",
"test": true,
"eventData": {
"type": "order",
"version": "v1",
"data": {
"order": {
"id": "order_1D5xA9BnKfv_t",
"object": "order",
"status": "failed",
"amount": {
"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 이후인지 확인하세요.