تنفيذ مراحل نشاط الطلب

يقدّم هذا الدليل مرجع واجهة برمجة التطبيقات الفني ومخططات الحمولة لإرسال آخر المعلومات عن حالة الطلب وأحداث تنفيذ الطلب والتسويات إلى Google باستخدام الويب هوك للإصدار 2026-04-08 من Universal Commerce Protocol (UCP).

قبل إنشاء نقاط النهاية، تأكَّد من مراجعة نظرة عامة على دورة حياة الطلب للتعرّف على المفاهيم العامة والأحداث الإلزامية وتفاصيل نقطة نهاية Webhook.

المصادقة وتوقيع الطلبات

تشمل التغييرات الرئيسية في الإصدار 2026-04-08 طرح عناوين إلزامية جديدة لبرنامج ربط الويب وإجراءات محدّدة لتوقيع الطلبات.

عناوين الويب هوك المطلوبة

عناوين HTTP التالية إلزامية لجميع طلبات "ويب هوك":

  • Webhook-Id: معرّف فريد لحدث webhook هذا. يجب أن يتطابق هذا المعرّف مع id للحدث الأساسي الذي يتم إرساله (على سبيل المثال، معرّف حدث التنفيذ أو معرّف حدث التسوية).
  • Webhook-Timestamp: الطابع الزمني الذي يشير إلى وقت وقوع الحدث.

تحلّ هذه العناوين محلّ الحقلَين id وcreated_time اللذين كانا متوقّعَين سابقًا في حمولة الطلب.

طلب التوقيع

  1. احسب ملخّص SHA-256 لنص الطلب الأولي واضبط العنوان Content-Digest
  2. اختَر مفتاح توقيع من signing_keys في ملفك التجاري على "منصة الشركاء الموحّدة".
  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 في المستوى الأعلى من عنصر الطلب.
  • أصبح الحقل type ضِمن كل عنصر في مصفوفة totals سلسلة مفتوحة (على سبيل المثال، "المجموع الفرعي" أو "الضريبة" أو "الرسوم" أو "المجموع").
  • يحتوي العنوان الإلزامي Webhook-Id على معرّف فريد لحدث webhook. يُرجى العِلم أنّه لا يزال من المطلوب توفير الحقل id في الحمولة التي تحتوي على معرّف تأكيد الطلب.
  • يوفّر العنوان الإلزامي Webhook-Timestamp وقت الإنشاء، ويحلّ محلّ الحقل created_time السابق في الحمولة.

مثال: يعرض هذا المثال طلبًا تم إنشاؤه بعد أن يكمل المشتري عملية الدفع.

العناوين المطلوبة:

  • 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"
}