이 가이드에서는 범용 커머스 프로토콜(UCP) 버전 2026-04-08의 웹훅을 사용하여 전체 주문 상태 업데이트, 주문 처리 이벤트, 조정을 Google에 푸시하기 위한 기술 API 참조 및 페이로드 스키마를 제공합니다.
엔드포인트를 빌드하기 전에 주문 수명 주기 개요에서 대략적인 개념, 필수 이벤트, 웹훅 엔드포인트 세부정보를 검토했는지 확인하세요.
인증 및 서명 요청
2026-04-08 버전의 주요 변경사항에는 새로운 필수 웹훅 헤더와 특정 서명 요청 절차의 도입이 포함됩니다.
필수 웹훅 헤더
모든 웹훅 요청에는 다음 HTTP 헤더가 필수입니다.
Webhook-Id: 이 특정 웹훅 이벤트의 고유 식별자입니다. 이 ID는 전송되는 기본 이벤트의id(예: 주문 처리 이벤트 ID 또는 조정 이벤트 ID)와 일치해야 합니다.Webhook-Timestamp: 이벤트가 발생한 시간을 나타내는 타임스탬프입니다.
이러한 헤더는 이전에 주문 페이로드에서 예상되었던 id 및 created_time 필드를 대체합니다.
서명 요청
- 원시 요청 본문의 SHA-256 다이제스트를 계산하고
Content-Digest헤더를 설정합니다. - UCP 프로필의
signing_keys에서 서명 키를 선택합니다. - RFC
9421에 따라 서명 기준을 빌드합니다.
- 서명된 구성요소의 사양을 참고하세요.
UCP-Agent,Signature-Input,Signature헤더를 설정합니다.UCP-Agent는profile="https://merchant.example.com/.well-known/ucp"형식의 UCP 프로필 링크입니다.Signature-Input은 서명 내에 포함된 구성요소와 서명에 사용된keyid를 설명하는 사전 구조 필드입니다. 이keyid는 UCP 프로필의signing_keys에서 선택한 서명 키의kid와 일치해야 합니다.Signature헤더에는 비공개 키를 사용하여 서명한 후 base64로 인코딩된 서명 기준이 포함됩니다.
자세한 내용은 ucp.dev의 서명 안내 를 참고하세요.
주문 생성됨 이벤트
- 트리거: 주문이 확인된 직후 (
status: processing)
이 버전의 주요 변경사항:
- 이제 Order 객체의 최상위 수준에서
currency필드가 필요합니다. - 이제
totals배열에 있는 각 객체의type필드는 개방형 문자열입니다 (예: '소계', '세금', '수수료', '총계'). - 필수
Webhook-Id헤더에는 웹훅 이벤트의 고유 식별자가 포함됩니다. 주문 확인 ID가 포함된 페이로드의id필드는 여전히 필요합니다. - 필수
Webhook-Timestamp헤더는 생성 시간을 제공하며, 페이로드의 이전created_time필드를 대체합니다.
예: 이 예에서는 구매자가 결제를 완료한 후 생성된 주문을 보여줍니다. 결제.
필수 헤더:
Webhook-Id: order_01Webhook-Timestamp: 2026-03-23T19:00:00Z
{
"ucp": {
"version": "2026-04-08",
"capabilities": {
"dev.ucp.shopping.order": [{"version": "2026-04-08"}]
}
},
"id": "order_01",
"checkout_id": "checkout_01",
"currency": "USD",
// Always include all line items, even for single-item checkouts. This ensures any add-ons, gifts, or separate charges are accounted for.
"line_items": [
{
"id": "line_1",
"item":
{
"id": "product_123",
"title": "Running Shoes",
"price": 10000
},
"quantity": { "total": 1, "fulfilled": 0 },
"totals": [
{"type": "subtotal", "display_text": null, "amount": 10000},
{"type": "total", "display_text": null, "amount": 10000}
],
// The status of a line item must match total and fulfilled quantities (e.g., total 1, fulfilled 0 -> status: processing).
"status": "processing"
}
],
"totals": [
{"type": "subtotal", "display_text": "Subtotal", "amount": 10000}, // Tax-inclusive markets: Set display_text to "Subtotal (including taxes)". Amount must include tax.
{"type": "fee", "display_text": "Service Fee", "amount": 100},
{"type": "tax", "display_text": "Tax", "amount": 800}, // Tax-inclusive markets: Omit this entry.
{"type": "total", "display_text": "Total", "amount": 10900}
],
"fulfillment": {
"expectations": [
{
"id": "exp_1",
"line_items": [{ "id": "line_1", "quantity": 1 }],
"method_type": "shipping",
"destination": {
"first_name": "Alice",
"last_name": "Example",
"street_address": "123 Main St",
"address_locality": "Austin",
"address_region": "TX",
"address_country": "US",
"postal_code": "78701"
},
"description": "Arrives in 2-3 business days", // Maximum length: 200 characters.
"fulfillable_on": "now"
}
]
},
"permalink_url": "https://merchant.example.com/orders/789"
}
주문 처리 이벤트
이러한 이벤트는 fulfillment.events 배열의 일부로 전송됩니다.
주문 발송
주문의 상품이 발송된 경우입니다. tracking_number 및 tracking_url 필드는 발송된 이벤트에 필요합니다. 이러한 필드는 '내 주문' 페이지에서 상품을 정확하게 그룹화하는 데 필요하기 때문입니다.
배송 완료
주문의 상품이 배송된 경우입니다.
예 (shipped 및 delivered): 이 예에서는 상품이 발송된 후 배송된 주문 업데이트를 보여줍니다.
필수 헤더:
Webhook-Id: fulfill_evt_2Webhook-Timestamp: 2026-02-10T14:00:00Z
{
"ucp": {
"version": "2026-04-08",
"capabilities": {
"dev.ucp.shopping.order": [{"version": "2026-04-08"}]
}
},
"id": "order_01",
"checkout_id": "checkout_01",
"currency": "USD",
"line_items": [
{
"id": "line_1",
"item":
{
"id": "product_123",
"title": "Running Shoes",
"price": 10000
},
"quantity": { "total": 1, "fulfilled": 1 },
"totals": [
{"type": "subtotal", "amount": 10000},
{"type": "total", "amount": 10000}
],
"status": "fulfilled"
}
],
"totals": [
{"type": "subtotal", "amount": 10000},
{"type": "total", "amount": 10000}
],
// Updated fulfillment details
"fulfillment": {
"events": [
{
"id": "fulfill_evt_1",
"occurred_at": "2026-02-08T10:30:00Z",
"type": "shipped",
"line_items": [{ "id": "line_1", "quantity": 1 }],
"tracking_number": "123456789",
"tracking_url": "https://fedex.com/track/123456789",
"carrier": "FedEx",
"description": "Shipping departed from warehouse"
},
{
"id": "fulfill_evt_2",
"occurred_at": "2026-02-10T14:00:00Z",
"type": "delivered",
"line_items": [{ "id": "line_1", "quantity": 1 }],
"tracking_number": "123456789",
"tracking_url": "https://fedex.com/track/123456789",
"carrier": "FedEx",
"description": "Package delivered"
}
],
"expectations": [{ "...": "..." }]
},
"permalink_url": "https://merchant.example.com/orders/123"
}
여러 상품 주문 예
다음 예에서는 여러 상품 주문 및 분할 배송의 업데이트를 구성하는 방법을 보여줍니다. 패키지 상태가 파생되는 방법에 관한 규칙은 패키지 상태가 결정되는 방법을 참고하세요.
여러 상품 주문, 동일한 패키지 배송
이 예에서는 여러 상품이 포함된 단일 패키지의 주문 업데이트를 보여줍니다. 모든 광고 항목은 동일한 운송장 번호를 공유하는 단일 shipped 이벤트 내에 그룹화됩니다.
필수 헤더:
Webhook-Id: fulfill_evt_1Webhook-Timestamp: 2026-02-08T10:30:00Z
{
"ucp": {
"version": "2026-04-08",
"capabilities": {
"dev.ucp.shopping.order": [{"version": "2026-04-08"}]
}
},
"id": "order_multi_01",
"checkout_id": "checkout_multi_01",
"currency": "USD",
"line_items": [
{
"id": "line_1",
"item": { "id": "product_1", "title": "Item 1", "price": 5000 },
"quantity": { "total": 1, "fulfilled": 1 },
"totals": [
{"type": "subtotal", "display_text": null, "amount": 5000},
{"type": "total", "display_text": null, "amount": 5000}
],
"status": "fulfilled"
},
{
"id": "line_2",
"item": { "id": "product_2", "title": "Item 2", "price": 5000 },
"quantity": { "total": 1, "fulfilled": 1 },
"totals": [
{"type": "subtotal", "display_text": null, "amount": 5000},
{"type": "total", "display_text": null, "amount": 5000}
],
"status": "fulfilled"
}
],
"totals": [
{"type": "subtotal", "display_text": "Subtotal", "amount": 10000},
{"type": "fee", "display_text": "Shipping", "amount": 500},
{"type": "total", "display_text": "Total", "amount": 10500}
],
"fulfillment": {
"expectations": [
{
"id": "exp_1",
"line_items": [
{ "id": "line_1", "quantity": 1 },
{ "id": "line_2", "quantity": 1 }
],
"method_type": "shipping",
"destination": {
"first_name": "Alice",
"last_name": "Example",
"street_address": "123 Main St",
"address_locality": "Austin",
"address_region": "TX",
"address_country": "US",
"postal_code": "78701"
},
"description": "Standard Shipping",
"fulfillable_on": "now"
}
],
"events": [
{
"id": "fulfill_evt_1",
"occurred_at": "2026-02-08T10:30:00Z",
"type": "shipped",
"line_items": [
{ "id": "line_1", "quantity": 1 },
{ "id": "line_2", "quantity": 1 }
],
"tracking_number": "123456789",
"tracking_url": "https://fedex.com/track/123456789",
"carrier": "FedEx",
"description": "Both items shipped together"
}
]
},
"permalink_url": "https://merchant.example.com/orders/456"
}
여러 상품 주문, 분할 배송
이 예에서는 분할 배송의 주문 업데이트를 보여줍니다. 각각 고유한 운송장 번호가 있는 여러 shipped 이벤트가 있으며, 각 이벤트는 해당 패키지 내의 특정 line_items를 참조합니다. 각 패키지는 고유한 주문 처리 약정 (예: 여러 그룹 결제에서 서로 다른 속도와 비용)을 나타내므로 expectations도 분할됩니다.
필수 헤더:
Webhook-Id: fulfill_evt_2Webhook-Timestamp: 2026-02-09T14:00:00Z
{
"ucp": {
"version": "2026-04-08",
"capabilities": {
"dev.ucp.shopping.order": [{"version": "2026-04-08"}]
}
},
"id": "order_multi_02",
"checkout_id": "checkout_multi_02",
"currency": "USD",
"line_items": [
{
"id": "line_1",
"item": { "id": "product_1", "title": "Item 1", "price": 5000 },
"quantity": { "total": 1, "fulfilled": 1 },
"totals": [
{"type": "subtotal", "display_text": null, "amount": 5000},
{"type": "total", "display_text": null, "amount": 5000}
],
"status": "fulfilled"
},
{
"id": "line_2",
"item": { "id": "product_2", "title": "Item 2", "price": 5000 },
"quantity": { "total": 1, "fulfilled": 1 },
"totals": [
{"type": "subtotal", "display_text": null, "amount": 5000},
{"type": "total", "display_text": null, "amount": 5000}
],
"status": "fulfilled"
}
],
"totals": [
{"type": "subtotal", "display_text": "Subtotal", "amount": 10000},
{"type": "fee", "display_text": "Shipping", "amount": 1500},
{"type": "total", "display_text": "Total", "amount": 11500}
],
"fulfillment": {
"expectations": [
{
"id": "exp_1",
"line_items": [{ "id": "line_1", "quantity": 1 }],
"method_type": "shipping",
"destination": {
"first_name": "Alice",
"last_name": "Example",
"street_address": "123 Main St",
"address_locality": "Austin",
"address_region": "TX",
"address_country": "US",
"postal_code": "78701"
},
"description": "Standard Shipping",
"fulfillable_on": "now"
},
{
"id": "exp_2",
"line_items": [{ "id": "line_2", "quantity": 1 }],
"method_type": "shipping",
"destination": {
"first_name": "Alice",
"last_name": "Example",
"street_address": "123 Main St",
"address_locality": "Austin",
"address_region": "TX",
"address_country": "US",
"postal_code": "78701"
},
"description": "Express Shipping",
"fulfillable_on": "now"
}
],
"events": [
{
"id": "fulfill_evt_1",
"occurred_at": "2026-02-08T10:30:00Z",
"type": "shipped",
"line_items": [{ "id": "line_1", "quantity": 1 }],
"tracking_number": "PKG1_TRACKING",
"tracking_url": "https://fedex.com/track/PKG1_TRACKING",
"carrier": "FedEx",
"description": "First item shipped in package 1"
},
{
"id": "fulfill_evt_2",
"occurred_at": "2026-02-09T14:00:00Z",
"type": "shipped",
"line_items": [{ "id": "line_2", "quantity": 1 }],
"tracking_number": "PKG2_TRACKING",
"tracking_url": "https://fedex.com/track/PKG2_TRACKING",
"carrier": "FedEx",
"description": "Second item shipped in package 2"
}
]
},
"permalink_url": "https://merchant.example.com/orders/457"
}
조정 이벤트 예
다음 예에서는 환불, 반품, 취소의 업데이트를 구성하는 방법을 보여줍니다. 지원되는 이벤트 및 정의 목록은 주문 수명 주기 개요의 조정 이벤트를 참고하세요.
주문 취소 및 환불
이 예에서는 주문이 접수된 직후 상품이 취소되고 환불된 주문을 보여줍니다.
이 예에서 이 버전의 주요 변경사항:
- 이제
cancellation의 영향을 받는 광고 항목은 기본line_items배열에서"status": "removed"를 사용합니다. line_items.status가removed인 경우:line_items.quantity.total이0으로 설정됩니다.- 원래 수량은 새
line_items.quantity.original필드에 저장됩니다.
필수 헤더:
Webhook-Id: adj_refund_1Webhook-Timestamp: 2026-02-09T11:05:00Z
{
"ucp": {
"version": "2026-04-08",
"capabilities": {
"dev.ucp.shopping.order": [{"version": "2026-04-08"}]
}
},
"id": "order_02",
"checkout_id": "checkout_02",
"currency": "USD",
"line_items": [
{
"id": "line_2",
"item": {
"id": "product_456",
"title": "Smart Watch",
"price": 29900
},
"quantity": {
"total": 0, // Item removed from order total.
"original": 1, // Original quantity before removal.
"fulfilled": 0 // Item was not fulfilled before cancellation.
},
"totals": [
{"type": "subtotal", "amount": 29900},
{"type": "tax", "amount": 2400},
{"type": "total", "amount": 32300}
],
"status": "removed" // Item is cancelled, returned, or refunded.
}
],
"totals": [
{"type": "subtotal", "amount": 29900},
{"type": "tax", "amount": 2400},
{"type": "total", "amount": 32300}
],
// Fulfillment expectations should still be present even if cancelled early.
"fulfillment": {
"expectations": [
{
"id": "exp_1",
"line_items": [{ "id": "line_2", "quantity": 1 }],
"method_type": "shipping",
"destination": {
"first_name": "Bob",
"last_name": "Consumer",
"street_address": "456 Oak Ave",
"address_locality": "Anytown",
"address_region": "CA",
"address_country": "US",
"postal_code": "90210"
},
"description": "Standard Shipping",
"fulfillable_on": "now"
}
]
// "events": [] // No fulfillment events occurred before cancellation.
},
"adjustments": [
{
"id": "adj_cancel_1",
"type": "cancellation",
"description": "Customer changed mind",
"line_items": [{ "id": "line_2", "quantity": -1 }],
"occurred_at": "2026-02-09T11:00:00Z",
"status": "completed"
},
{
"id": "adj_refund_1",
"type": "refund",
"description": "Refund for cancelled item",
"line_items": [{ "id": "line_2", "quantity": -1 }],
"totals": [
{"type": "subtotal", "display_text": "Subtotal", "amount": -29900}, // Negative amounts indicate money returned to the buyer. Tax-inclusive markets: Set display_text to "Subtotal (including taxes)". Amount must include tax.
{"type": "tax", "amount": -2400}, // Tax-inclusive markets: Omit this entry.
{"type": "total", "display_text": "Total", "amount": -32300}
],
"occurred_at": "2026-02-09T11:05:00Z",
"status": "completed"
}
],
"permalink_url": "https://merchant.example.com/orders/12345"
}
주문 반품 및 환불
이 예에서는 상품이 발송되고 배송된 후 반품되고 환불된 주문을 보여줍니다.
이 예에서 이 버전의 주요 변경사항:
- 이제
return의 영향을 받는 광고 항목은 기본line_items배열에서"status": "removed"를 사용합니다. line_items.status가removed인 경우:line_items.quantity.total이0으로 설정됩니다.- 원래 수량은 새
line_items.quantity.original필드에 저장됩니다.
return유형의adjustments에서 조정 내의line_items.quantity필드는 음수 값 (예:-1)을 사용하여 반품되는 상품을 나타냅니다.
필수 헤더:
Webhook-Id: adj_refund_2Webhook-Timestamp: 2026-02-10T10:00:00Z
{
"ucp": {
"version": "2026-04-08",
"capabilities": {
"dev.ucp.shopping.order": [{"version": "2026-04-08"}]
}
},
"id": "order_03",
"checkout_id": "checkout_03",
"currency": "USD",
"line_items": [
{
"id": "line_3",
"item": {
"id": "product_789",
"title": "Wireless Earbuds",
"price": 14900
},
"quantity": {
"total": 0, // Item removed from order total.
"original": 1, // Original quantity before removal.
"fulfilled": 1 // Was fulfilled before return.
},
"totals": [
{"type": "subtotal", "amount": 14900},
{"type": "tax", "amount": 1200},
{"type": "total", "amount": 16100}
],
"status": "removed" // Item is cancelled, returned, or refunded.
}
],
"totals": [
{"type": "subtotal", "amount": 14900},
{"type": "tax", "amount": 1200},
{"type": "total", "amount": 16100}
],
"fulfillment": {
"events": [
{
"id": "fulfill_evt_1",
"occurred_at": "2026-02-05T09:00:00Z",
"type": "shipped",
"line_items": [{ "id": "line_3", "quantity": 1 }],
"tracking_number": "987654321",
"tracking_url": "https://fedex.com/track/987654321",
"carrier": "FedEx",
"description": "Item shipped"
},
{
"id": "fulfill_evt_2",
"occurred_at": "2026-02-07T16:00:00Z",
"type": "delivered",
"line_items": [{ "id": "line_3", "quantity": 1 }],
"tracking_number": "987654321",
"tracking_url": "https://fedex.com/track/987654321",
"carrier": "FedEx",
"description": "Item delivered"
},
{
"id": "fulfill_evt_3",
"occurred_at": "2026-02-09T09:00:00Z",
"type": "returned",
"line_items": [{ "id": "line_3", "quantity": 1 }],
"tracking_number": "987654321",
"tracking_url": "https://fedex.com/track/987654321",
"carrier": "FedEx",
"description": "Item returned"
}
],
"expectations": [{ "...": "..." }]
},
"adjustments": [
{
"id": "adj_return_1",
"type": "return", // a matching fulfillment event is also added to represent return shipping.
"description": "Item not compatible",
"line_items": [{ "id": "line_3", "quantity": -1 }], // Uses a negative value (such as -1) to indicate a return.
"occurred_at": "2026-02-09T09:00:00Z",
"status": "completed"
},
{
"id": "adj_refund_2",
"type": "refund",
"description": "Refund for returned item",
"line_items": [{ "id": "line_3", "quantity": -1 }],
"totals": [
{"type": "subtotal", "amount": -14900}, // Negative amounts indicate money returned to the buyer.
{"type": "tax", "amount": -1200},
{"type": "total", "amount": -16100}
],
"occurred_at": "2026-02-10T10:00:00Z",
"status": "completed"
}
],
"permalink_url": "https://merchant.example.com/orders/67890"
}