پیاده‌سازی چرخه حیات سفارش، پیاده‌سازی چرخه حیات سفارش

این راهنما، مرجع فنی API و طرحواره‌های بار مفید برای ارسال به‌روزرسانی‌های کامل وضعیت سفارش، رویدادهای تکمیل سفارش و تنظیمات در گوگل با استفاده از وب‌هوک‌ها برای نسخه 2026-04-08 پروتکل تجارت جهانی (UCP) را ارائه می‌دهد.

قبل از ساخت نقاط پایانی خود، مطمئن شوید که نمای کلی چرخه حیات سفارش را برای مفاهیم سطح بالا، رویدادهای اجباری و جزئیات نقطه پایانی وب‌هوک مرور کرده‌اید.

تأیید و امضای درخواست

تغییرات کلیدی در نسخه 2026-04-08 شامل معرفی هدرهای وب‌هوک اجباری جدید و رویه‌های خاص امضای درخواست است.

هدرهای وب‌هوک مورد نیاز

هدرهای HTTP زیر برای همه درخواست‌های وب‌هوک الزامی هستند:

  • Webhook-Id : یک شناسه منحصر به فرد برای این رویداد خاص وب هوک. این شناسه باید با id رویداد اصلی ارسال شده مطابقت داشته باشد (برای مثال، شناسه رویداد تکمیل سفارش یا شناسه رویداد تنظیم سفارش).
  • Webhook-Timestamp : مهر زمانی که نشان می‌دهد رویداد چه زمانی رخ داده است.

این هدرها جایگزین فیلدهای id و created_time می‌شوند که قبلاً در payload سفارش انتظار می‌رفت.

درخواست امضا

  1. خلاصه SHA-256 بدنه درخواست خام را محاسبه کرده و سرآیند Content-Digest را تنظیم کنید.
  2. یک کلید امضا از signing_keys در پروفایل UCP خود انتخاب کنید.
  3. ساخت پایگاه امضا طبق RFC 9421 .
    • مشخصات مربوط به اجزای امضا شده را ببینید
  4. هدرهای UCP-Agent ، Signature-Input و Signature را تنظیم کنید.
    • UCP-Agent لینکی به پروفایل UCP شما با فرمت profile="https://merchant.example.com/.well-known/ucp" است.
    • Signature-Input یک فیلد ساختاریافته‌ی دیکشنری است که اجزای موجود در امضا و همچنین keyid مورد استفاده برای امضا را توصیف می‌کند، که باید با kid کلید امضای انتخابی شما از signing_keys در پروفایل UCP شما مطابقت داشته باشد.
    • سربرگ Signature شامل امضای پایه شماست که با استفاده از کلید خصوصی شما امضا شده و سپس با کد base64 رمزگذاری شده است.

برای اطلاعات بیشتر به دستورالعمل‌های امضا در ucp.dev مراجعه کنید.

رویداد ایجاد شده را سفارش دهید

  • فعال‌سازی: بلافاصله پس از تأیید سفارش ( status: processing ).

تغییرات کلیدی در این نسخه:

  • فیلد currency اکنون در بالاترین سطح شیء سفارش (Order) الزامی است.
  • فیلد type درون هر شیء در آرایه totals اکنون یک رشته باز است (برای مثال، "subtotal"، "tax"، "fee"، "total").
  • هدر اجباری Webhook-Id شامل یک شناسه منحصر به فرد برای رویداد webhook است. توجه داشته باشید که فیلد id در payload حاوی شناسه تأیید سفارش هنوز الزامی است.
  • هدر اجباری Webhook-Timestamp زمان ایجاد را ارائه می‌دهد و جایگزین فیلد created_time قبلی در payload می‌شود.

مثال: این مثال سفارشی را نشان می‌دهد که پس از تکمیل فرآیند پرداخت توسط خریدار ایجاد شده است.

سربرگ‌های مورد نیاز:

  • Webhook-Id: order_01
  • Webhook-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_2
  • Webhook-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_1
  • Webhook-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_2
  • Webhook-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 قرار گرفته‌اند، اکنون از "status": "removed" در آرایه اصلی line_items استفاده می‌کنند.
  • وقتی line_items.status removed می‌شود:
    • مقدار line_items.quantity.total برابر با 0 تنظیم شده است.
    • مقدار اصلی در فیلد جدید line_items.quantity.original ذخیره می‌شود.

سربرگ‌های مورد نیاز:

  • Webhook-Id: adj_refund_1
  • Webhook-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 قرار می‌گیرند، اکنون از "status": "removed" در آرایه اصلی line_items استفاده می‌کنند.
  • وقتی line_items.status removed می‌شود:
    • مقدار line_items.quantity.total برابر با 0 تنظیم شده است.
    • مقدار اصلی در فیلد جدید line_items.quantity.original ذخیره می‌شود.
  • در adjustments از نوع return ، فیلد line_items.quantity درون تنظیمات از یک مقدار منفی (مثلاً -1 ) برای نشان دادن موارد پس گرفته شده استفاده می‌کند.

سربرگ‌های مورد نیاز:

  • Webhook-Id: adj_refund_2
  • Webhook-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"
}
،

این راهنما، مرجع فنی API و طرحواره‌های بار مفید برای ارسال به‌روزرسانی‌های کامل وضعیت سفارش، رویدادهای تکمیل سفارش و تنظیمات در گوگل با استفاده از وب‌هوک‌ها برای نسخه 2026-04-08 پروتکل تجارت جهانی (UCP) را ارائه می‌دهد.

قبل از ساخت نقاط پایانی خود، مطمئن شوید که نمای کلی چرخه حیات سفارش را برای مفاهیم سطح بالا، رویدادهای اجباری و جزئیات نقطه پایانی وب‌هوک مرور کرده‌اید.

تأیید و امضای درخواست

تغییرات کلیدی در نسخه 2026-04-08 شامل معرفی هدرهای وب‌هوک اجباری جدید و رویه‌های خاص امضای درخواست است.

هدرهای وب‌هوک مورد نیاز

هدرهای HTTP زیر برای همه درخواست‌های وب‌هوک الزامی هستند:

  • Webhook-Id : یک شناسه منحصر به فرد برای این رویداد خاص وب هوک. این شناسه باید با id رویداد اصلی ارسال شده مطابقت داشته باشد (برای مثال، شناسه رویداد تکمیل سفارش یا شناسه رویداد تنظیم سفارش).
  • Webhook-Timestamp : مهر زمانی که نشان می‌دهد رویداد چه زمانی رخ داده است.

این هدرها جایگزین فیلدهای id و created_time می‌شوند که قبلاً در payload سفارش انتظار می‌رفت.

درخواست امضا

  1. خلاصه SHA-256 بدنه درخواست خام را محاسبه کرده و سرآیند Content-Digest را تنظیم کنید.
  2. یک کلید امضا از signing_keys در پروفایل UCP خود انتخاب کنید.
  3. ساخت پایگاه امضا طبق RFC 9421 .
    • مشخصات مربوط به اجزای امضا شده را ببینید
  4. هدرهای UCP-Agent ، Signature-Input و Signature را تنظیم کنید.
    • UCP-Agent لینکی به پروفایل UCP شما با فرمت profile="https://merchant.example.com/.well-known/ucp" است.
    • Signature-Input یک فیلد ساختاریافته‌ی دیکشنری است که اجزای موجود در امضا و همچنین keyid مورد استفاده برای امضا را توصیف می‌کند، که باید با kid کلید امضای انتخابی شما از signing_keys در پروفایل UCP شما مطابقت داشته باشد.
    • سربرگ Signature شامل امضای پایه شماست که با استفاده از کلید خصوصی شما امضا شده و سپس با کد base64 رمزگذاری شده است.

برای اطلاعات بیشتر به دستورالعمل‌های امضا در ucp.dev مراجعه کنید.

رویداد ایجاد شده را سفارش دهید

  • فعال‌سازی: بلافاصله پس از تأیید سفارش ( status: processing ).

تغییرات کلیدی در این نسخه:

  • فیلد currency اکنون در بالاترین سطح شیء سفارش (Order) الزامی است.
  • فیلد type درون هر شیء در آرایه totals اکنون یک رشته باز است (برای مثال، "subtotal"، "tax"، "fee"، "total").
  • هدر اجباری Webhook-Id شامل یک شناسه منحصر به فرد برای رویداد webhook است. توجه داشته باشید که فیلد id در payload حاوی شناسه تأیید سفارش هنوز الزامی است.
  • هدر اجباری Webhook-Timestamp زمان ایجاد را ارائه می‌دهد و جایگزین فیلد created_time قبلی در payload می‌شود.

مثال: این مثال سفارشی را نشان می‌دهد که پس از تکمیل فرآیند پرداخت توسط خریدار ایجاد شده است.

سربرگ‌های مورد نیاز:

  • Webhook-Id: order_01
  • Webhook-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_2
  • Webhook-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_1
  • Webhook-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_2
  • Webhook-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 قرار گرفته‌اند، اکنون از "status": "removed" در آرایه اصلی line_items استفاده می‌کنند.
  • وقتی line_items.status removed می‌شود:
    • مقدار line_items.quantity.total برابر با 0 تنظیم شده است.
    • مقدار اصلی در فیلد جدید line_items.quantity.original ذخیره می‌شود.

سربرگ‌های مورد نیاز:

  • Webhook-Id: adj_refund_1
  • Webhook-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 قرار می‌گیرند، اکنون از "status": "removed" در آرایه اصلی line_items استفاده می‌کنند.
  • وقتی line_items.status removed می‌شود:
    • مقدار line_items.quantity.total برابر با 0 تنظیم شده است.
    • مقدار اصلی در فیلد جدید line_items.quantity.original ذخیره می‌شود.
  • در adjustments از نوع return ، فیلد line_items.quantity درون تنظیمات از یک مقدار منفی (مثلاً -1 ) برای نشان دادن موارد پس گرفته شده استفاده می‌کند.

سربرگ‌های مورد نیاز:

  • Webhook-Id: adj_refund_2
  • Webhook-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"
}