Este guia fornece a referência técnica da API e os esquemas de payload para enviar atualizações completas do status do pedido, eventos de fulfillment e ajustes ao Google usando webhooks para a versão 2026-04-08 do Universal Commerce Protocol (UCP).
Antes de criar seus endpoints, consulte a Visão geral do ciclo de vida do pedido para conferir os conceitos gerais , eventos obrigatórios e detalhes do endpoint do webhook.
Autenticação e assinatura de solicitação
As principais mudanças na versão 2026-04-08 incluem a introdução de novos cabeçalhos de webhook obrigatórios e procedimentos específicos de assinatura de solicitação.
Cabeçalhos de webhook obrigatórios
Os seguintes cabeçalhos HTTP são obrigatórios para todas as solicitações de webhook:
Webhook-Id: um identificador exclusivo para esse evento de webhook específico. Esse ID precisa corresponder aoiddo evento principal que está sendo enviado (por exemplo, o ID do evento de fulfillment ou o ID do evento de ajuste).Webhook-Timestamp: o carimbo de data/hora que indica quando o evento ocorreu.
Esses cabeçalhos substituem os campos id e created_time esperados anteriormente no payload do pedido.
Assinatura de solicitação
- Calcule o resumo SHA-256 do corpo da solicitação bruta e defina o cabeçalho
Content-Digest. - Selecione uma chave de assinatura em
signing_keysno seu perfil do UCP. - Crie a base de assinatura de acordo com RFC
9421.
- Consulte a especificação de componentes assinados.
- Defina os cabeçalhos
UCP-Agent,Signature-InputeSignature.UCP-Agenté um link para seu perfil do UCP no formatoprofile="https://merchant.example.com/.well-known/ucp".Signature-Inputé um campo estruturado de dicionário que descreve os componentes contidos na assinatura, bem como okeyidusado para assinar, que precisa corresponder aokidda chave de assinatura selecionada emsigning_keysno seu perfil do UCP.- O cabeçalho
Signaturecontém sua base de assinatura, que é assinada usando sua chave privada e codificada em base64.
Consulte as instruções de assinatura em ucp.dev para mais informações.
Evento de pedido criado
- Acionador: imediatamente após a confirmação do pedido (
status: processing).
Principais mudanças nesta versão :
- O campo
currencyagora é obrigatório no nível superior do objeto Order. - O campo
typeem cada objeto na matriztotalsagora é uma string aberta (por exemplo, "subtotal", "tax", "fee", "total"). - O cabeçalho obrigatório
Webhook-Idcontém um identificador exclusivo para o evento de webhook. O campoidno payload que contém o ID de confirmação do pedido ainda é obrigatório. - O cabeçalho obrigatório
Webhook-Timestampfornece o horário de criação, substituindo o campocreated_timeanterior no payload.
Exemplo: este exemplo mostra um pedido criado depois que um comprador conclui o checkout.
Cabeçalhos obrigatórios :
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"
}
Eventos de fulfillment
Esses eventos são enviados como parte da matriz fulfillment.events.
Pedido enviado
Quando os itens do pedido foram enviados. Os campos tracking_number e tracking_url são obrigatórios para eventos enviados, porque são necessários para agrupar os itens na página "Meus pedidos" com precisão.
Pedido entregue
Quando os itens do pedido foram entregues.
Exemplo (shipped e delivered) : este exemplo mostra uma atualização de pedido depois que o item foi enviado e entregue.
Cabeçalhos obrigatórios :
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"
}
Exemplos de pedidos com vários itens
Os exemplos a seguir demonstram como estruturar atualizações para pedidos com vários itens e envios divididos. Para conferir as regras sobre como os status dos pacotes são derivados, consulte Como o status do pacote é determinado.
Pedido com vários itens, entrega do mesmo pacote
Este exemplo mostra uma atualização de pedido para um único pacote que contém vários itens. Todos os itens de linha são agrupados em um único evento shipped que compartilha o mesmo número de rastreamento.
Cabeçalhos obrigatórios :
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"
}
Pedido com vários itens, envio dividido
Este exemplo mostra uma atualização de pedido para envios divididos. Há vários eventos shipped, cada um referenciando os line_items específicos dentro do pacote respectivo, com números de rastreamento distintos. Como cada pacote representa um compromisso de fulfillment distinto (por exemplo, velocidades e custos diferentes de um checkout de vários grupos), as expectations também são divididas.
Cabeçalhos obrigatórios :
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"
}
Exemplos de eventos de ajuste
Os exemplos a seguir demonstram como estruturar atualizações para reembolsos, devoluções e cancelamentos. Para conferir uma lista de eventos compatíveis e as definições deles, consulte Eventos de ajuste na Visão geral do ciclo de vida do pedido.
Cancelamento e reembolso do pedido
Este exemplo mostra um pedido em que o item foi cancelado e reembolsado logo após a realização do pedido.
Principais mudanças nesta versão neste exemplo :
- Os itens de linha afetados por um
cancellationagora usam"status": "removed"na matrizline_itemsprincipal. - Quando
line_items.statuséremoved:- O
line_items.quantity.totalé definido como0. - A quantidade original é armazenada no novo campo
line_items.quantity.original.
- O
Cabeçalhos obrigatórios :
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"
}
Devolução e reembolso do pedido
Este exemplo mostra um pedido em que o item foi enviado, entregue e, em seguida, devolvido e reembolsado.
Principais mudanças nesta versão neste exemplo :
- Os itens de linha afetados por um
returnagora usam"status": "removed"na matriz principalline_items. - Quando
line_items.statuséremoved:- O
line_items.quantity.totalé definido como0. - A quantidade original é armazenada no novo campo
line_items.quantity.original.
- O
- Em
adjustmentsdo tiporeturn, o campoline_items.quantitydentro do ajuste usa um valor negativo (por exemplo,-1) para indicar os itens que estão sendo devolvidos.
Cabeçalhos obrigatórios :
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"
}