# دورة حياة العميل (/ar/integrate/checkout-session/customer-lifecycle)

قرّر مين العميل، وإيه اللي الفورم بيجمعه، وإزاي سجل العميل في XPay بيتطوّر بين الدافعين لمرة واحدة والعملاء العائدين.

الـ <ApiLink href="/api-reference/objects/customer">العميل</ApiLink> هو سجل XPay لحد دفعلك. بيحمل اسمه، وإيميله، وتليفونه، وعنوانه، وإجمالي الإنفاق المربوط بالمعرّفات دي. الصفحة دي عن إزاي السجل ده بيتعمل، ويتعبّى مسبقًا، ويتعاد استخدامه عبر سيناريوهات الدمج الثلاثة اللي على الأرجح هتبنيها: العملاء العائدين المسجَّلين، والعملاء المسجَّلين لأول مرة، وعمليات دفع الضيوف.

القاعدة الوحيدة اللي بتحرّك كل قرار تحت: &#x2A;*خزّن الـ `cus_*` مقابل المستخدم المسجَّل بتاعك، مش مقابل ضيف أبدًا.** XPay بيمنع تكرار عمليات دفع الضيوف في السيرفر؛ ولو ثبّتّ `cus_*` لضيف في قاعدة بياناتك هتلاقي نفسك بتحارب منع التكرار ده.

## نوعَي العميل [#نوعَي-العميل]

XPay بيتتبّع نوعين من سجلات العميل.

| النوع      | إمتى بيتعمل                                                                                                                                                                                                           | الاستخدام                                                                                                        |
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| **مسجَّل** | يا إما تظبّط `customerCreation: "always"` على جلسة دفع والعميل يدفع، يا إما التاجر يربط `customerId` كان معاك بالفعل صراحةً. لوحة التحكم بتعدّهم عملاء معروفين؛ وتقدر تربط بيهم طرق دفع محفوظة بعدين (اشتراكات، إلخ). | المستخدم المسجَّل بتاعك دفع. احفظ الـ `cus_*` على صف حسابه.                                                      |
| **ضيف**    | بيتعمل تلقائيًا أثناء الدفع لما مفيش `customerId` متقدّم و`customerCreation` يكون `if_required` (الافتراضي). XPay بيجمّع الضيوف حسب الإيميل، والتليفون، وبصمة البطاقة علشان يتعرّف على نفس الشخص عبر الزيارات.        | دافع لمرة واحدة أو حد ما سجّلش دخوله. &#x2A;*ما تخزّنش الـ `cus_*`**: XPay بيتولّى منع التكرار، وإنت هتحاربه بس. |

النوعين الاتنين بيظهروا في لوحة التحكم. حقول تجميع الضيف (كل إيميل وتليفون استخدمهم، وكل بطاقة دفع بيها) بتتراكم تلقائيًا. لوحة التحكم بتعرض كمان "العملاء المرتبطين" علشان المشغّل يشوف لما سجل ضيف يتقاطع مع سجل مسجَّل.

## ثلاثة أنماط حسب سيناريو التاجر [#ثلاثة-أنماط-حسب-سيناريو-التاجر]

شكل `customerCreation`، و`customerId`، و`customerDetails` اللي بتبعتهم بيعتمد على اللي إنت عارفه عن الشخص اللي بيدفع.

### مستخدم مسجَّل عائد [#مستخدم-مسجَّل-عائد]

عندك `cus_*` متخزّن على صف المستخدم بتاعك. مرّره كـ `customerId`. الفورم بيتعبّى مسبقًا من السجل الموجود. ما تبعتش `customerDetails` (متعارض مع `customerId`). اختياريًا ظبّط `customerUpdate` علشان تكتب تغييرات الفورم رجوعًا للسجل.

<Tabs items="[&#x22;cURL&#x22;, &#x22;Node.js&#x22;, &#x22;Python&#x22;]">
  <Tab value="cURL">
    ```bash
    curl -X POST https://api.xpay.app/checkout/sessions \
      -H "Authorization: Bearer sk_test_..." \
      -H "Content-Type: application/json" \
      -d '{
        "afterCompletion": { "type": "redirect", "redirect": { "url": "https://yourshop.example/order/{CHECKOUT_SESSION_ID}" } },
        "customerId": "cus_test_AbC123",
        "customerUpdate": { "address": "auto", "shipping": "auto" },
        "lineItems": [ { "price": "price_test_xyz", "quantity": 1 } ]
      }'
    ```
  </Tab>

  <Tab value="Node.js">
    ```typescript
    const session = await fetch("https://api.xpay.app/checkout/sessions", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.XPAY_SECRET_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        afterCompletion: {
          type: "redirect",
          redirect: { url: "https://yourshop.example/order/{CHECKOUT_SESSION_ID}" },
        },
        customerId: user.xpay_customer_id, // stored on your user row
        customerUpdate: { address: "auto", shipping: "auto" },
        lineItems: [{ price: "price_test_xyz", quantity: 1 }],
      }),
    }).then((r) => r.json());
    ```
  </Tab>

  <Tab value="Python">
    ```python
    import os, requests

    session = requests.post(
        "https://api.xpay.app/checkout/sessions",
        headers={
            "Authorization": f"Bearer {os.environ['XPAY_SECRET_KEY']}",
            "Content-Type": "application/json",
        },
        json={
            "afterCompletion": {
                "type": "redirect",
                "redirect": {"url": "https://yourshop.example/order/{CHECKOUT_SESSION_ID}"},
            },
            "customerId": user.xpay_customer_id,  # stored on your user row
            "customerUpdate": {"address": "auto", "shipping": "auto"},
            "lineItems": [{"price": "price_test_xyz", "quantity": 1}],
        },
        timeout=10,
    ).json()
    ```
  </Tab>
</Tabs>

### مستخدم مسجَّل لأول مرة [#مستخدم-مسجَّل-لأول-مرة]

لسه مفيش `cus_*`. ابعت اللي إنت عارفه كـ `customerDetails` للتعبئة المسبقة، وظبّط `customerCreation: "always"` علشان يتعمل عميل مسجَّل وقت الدفع. خُد `data.object.customer.id` من webhook الـ `checkout.session.completed` وخزّنه على صف المستخدم بتاعك.

<Tabs items="[&#x22;cURL&#x22;, &#x22;Node.js&#x22;, &#x22;Python&#x22;]">
  <Tab value="cURL">
    ```bash
    curl -X POST https://api.xpay.app/checkout/sessions \
      -H "Authorization: Bearer sk_test_..." \
      -H "Content-Type: application/json" \
      -d '{
        "afterCompletion": { "type": "redirect", "redirect": { "url": "https://yourshop.example/order/{CHECKOUT_SESSION_ID}" } },
        "customerCreation": "always",
        "customerDetails": {
          "name": "Aya Hassan",
          "email": "aya@example.com",
          "phone": "+201234567890"
        },
        "metadata": { "user_id": "u_42" },
        "lineItems": [ { "price": "price_test_xyz", "quantity": 1 } ]
      }'
    ```
  </Tab>

  <Tab value="Node.js">
    ```typescript
    const session = await fetch("https://api.xpay.app/checkout/sessions", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.XPAY_SECRET_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        afterCompletion: {
          type: "redirect",
          redirect: { url: "https://yourshop.example/order/{CHECKOUT_SESSION_ID}" },
        },
        customerCreation: "always",
        customerDetails: {
          name: user.name,
          email: user.email,
          phone: user.phone,
        },
        metadata: { user_id: user.id },
        lineItems: [{ price: "price_test_xyz", quantity: 1 }],
      }),
    }).then((r) => r.json());
    ```
  </Tab>

  <Tab value="Python">
    ```python
    import os, requests

    session = requests.post(
        "https://api.xpay.app/checkout/sessions",
        headers={
            "Authorization": f"Bearer {os.environ['XPAY_SECRET_KEY']}",
            "Content-Type": "application/json",
        },
        json={
            "afterCompletion": {
                "type": "redirect",
                "redirect": {"url": "https://yourshop.example/order/{CHECKOUT_SESSION_ID}"},
            },
            "customerCreation": "always",
            "customerDetails": {
                "name": user.name,
                "email": user.email,
                "phone": user.phone,
            },
            "metadata": {"user_id": user.id},
            "lineItems": [{"price": "price_test_xyz", "quantity": 1}],
        },
        timeout=10,
    ).json()
    ```
  </Tab>
</Tabs>

### دفع ضيف [#دفع-ضيف]

مفيش مستخدم مسجَّل. سيب `customerId` واترك `customerCreation` على الافتراضي (`if_required`). XPay بينشئ أو بيطابق سجل ضيف بالإيميل، والتليفون، وبصمة البطاقة. مش محتاج تتبّع الـ `cus_*` على ناحيتك. لوحة التحكم بتجمّع الضيوف تلقائيًا.

<Tabs items="[&#x22;cURL&#x22;, &#x22;Node.js&#x22;, &#x22;Python&#x22;]">
  <Tab value="cURL">
    ```bash
    curl -X POST https://api.xpay.app/checkout/sessions \
      -H "Authorization: Bearer sk_test_..." \
      -H "Content-Type: application/json" \
      -d '{
        "afterCompletion": { "type": "redirect", "redirect": { "url": "https://yourshop.example/order/{CHECKOUT_SESSION_ID}" } },
        "lineItems": [ { "price": "price_test_xyz", "quantity": 1 } ]
      }'
    ```
  </Tab>

  <Tab value="Node.js">
    ```typescript
    const session = await fetch("https://api.xpay.app/checkout/sessions", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.XPAY_SECRET_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        afterCompletion: {
          type: "redirect",
          redirect: { url: "https://yourshop.example/order/{CHECKOUT_SESSION_ID}" },
        },
        lineItems: [{ price: "price_test_xyz", quantity: 1 }],
      }),
    }).then((r) => r.json());
    ```
  </Tab>

  <Tab value="Python">
    ```python
    import os, requests

    session = requests.post(
        "https://api.xpay.app/checkout/sessions",
        headers={
            "Authorization": f"Bearer {os.environ['XPAY_SECRET_KEY']}",
            "Content-Type": "application/json",
        },
        json={
            "afterCompletion": {
                "type": "redirect",
                "redirect": {"url": "https://yourshop.example/order/{CHECKOUT_SESSION_ID}"},
            },
            "lineItems": [{"price": "price_test_xyz", "quantity": 1}],
        },
        timeout=10,
    ).json()
    ```
  </Tab>
</Tabs>

الـ webhook اللي بيتطلق عند النجاح (`checkout.session.completed`) بيحمل العميل المستقرّ في `data.object.customer`. لحالة المسجَّل لأول مرة، ده المكان اللي بتاخد منه الـ `cus_*` الجديد علشان تحفظه على صف المستخدم بتاعك.

## `customerId` مقابل `customerDetails` [#customerid-مقابل-customerdetails]

دول الطريقتين المتعارضتين لتحديد العميل على الجلسة.

| الحقل             | بيعمل إيه                                                                                                                                                | النوع المطلوب |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `customerId`      | بيشير لعميل موجود (`cus_*`). الفورم بيتعبّى مسبقًا بالاسم، والإيميل، والتليفون، وعنوان الفوترة، والشحن من السجل ده.                                      | مسجَّل        |
| `customerDetails` | بيانات تواصل وعنوان مضمَّنة (`name`، `email`، `phone`، `billingDetails.address`، `shipping`). بتعبّي الفورم مسبقًا. بتُستخدم لإنشاء عميل جديد وقت الدفع. | لا ينطبق      |

إرسال الاتنين بيتم رفضه. إرسال ولا واحدة كويس: الفورم بيبقى فاضي والعميل بيملاه.

`customerId` لازم يشير لعميل **مسجَّل**. تمرير `cus_*` بتاع ضيف بيفشل بخطأ واضح. الضيوف للدفع بس؛ مفيش مسار لربطهم بجلسة مستقبلية.

### قواعد التعبئة المسبقة [#قواعد-التعبئة-المسبقة]

لما الصفحة تتعرض، الفورم بيتعبّى مسبقًا بترتيب أولوية:

1. `customerDetails.{name, email, phone}` لو متقدّم.
2. `name`، و`email`، و`phone`، و`address`، و`shipping` بتوع العميل الموجود لو `customerId` اتظبّط.
3. فاضي غير كده. العميل بيملاه.

حقول الإيميل والتليفون بتبقى **مقفولة** (للقراءة بس) لما `customerId` يكون متظبّط والسجل الموجود يحملها. العميل مينفعش يغيّر إيميل أو تليفون حد تاني في وسط الدفع.

## `customerCreation` [#customercreation]

بيتحكم في إمتى XPay بينشئ سجل عميل وقت الدفع. قيمتين؛ الافتراضي `if_required`.

| القيمة        | بيعمل إيه                                                                                                                                                               |
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `if_required` | الافتراضي. لو العميل ملا إيميل أو تليفون، بيتعمل أو بيتطابق عميل **ضيف**. ولو ما ملاش حاجة والتاجر ما ظبّطش `customerId`، مفيش سجل عميل بيتعمل خالص.                    |
| `always`      | بيتعمل عميل **مسجَّل** من `customerDetails` وقت الدفع، حتى لو كتب اسم بس. استخدمه لما تكون عايز حساب معروف محفوظ (زيارات عائدة، إيميلات بعد الشراء، اشتراكات مستقبلية). |

`customerCreation` متعارض مع `customerId: "cus_..."` لقيمة `always`. لو عندك عميل بالفعل، فإنت مش بتطلب من XPay إنه يعمل واحد تاني.

## `customerUpdate` [#customerupdate]

لما `customerId` يكون متظبّط، البيانات اللي اتجمعت من الفورم **مش** بتتكتب رجوعًا للعميل الموجود افتراضيًا. ظبّط `customerUpdate` علشان تختار التحديث لكل حقل. كل علم فرعي بيبقى `auto` (يكتب) أو `never` (الافتراضي، ما يكتبش).

```jsonc
{
  "customerId": "cus_test_AbC123",
  "customerUpdate": {
    "name": "auto", // overwrite customer.name with the form value
    "address": "auto", // overwrite customer.address with the billing address
    "shipping": "auto", // overwrite customer.shipping with the shipping address
  },
}
```

`customerUpdate` ليه معنى بس لما `customerId` يكون متقدّم. إرساله من غير `customerId` بيبقى خطأ تحقّق.

`email` و`phone` مش موجودين في `customerUpdate` لأنهم مقفولين على مستوى الفورم لما العميل الموجود يحملهم. ينفع بس يتـ**ملّوا** لما يكونوا ناقصين (شوف [إزاي XPay بيتعامل مع العملاء الضيوف](#إزاي-xpay-بيتعامل-مع-العملاء-الضيوف)).

## إيه اللي الفورم بيجمعه [#إيه-اللي-الفورم-بيجمعه]

أربعة مفاتيح منطقية بتتحكم في أنهي حقول الفورم المستضاف بيطلبها من العميل. كلها افتراضيًا `false`.

| المفتاح                     | بيطلب إيه                                                           | مطلوب عند الإرسال؟                                                                            |
| --------------------------- | ------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| `nameCollection`            | اسم العميل الكامل.                                                  | نعم لما يكون مفعّل.                                                                           |
| `phoneNumberCollection`     | تليفون العميل مع رمز الدولة.                                        | نعم لما يكون مفعّل. الإرسال بيفشل بـ `parameter_missing` على `customerDetails.phone` لو فاضي. |
| `billingAddressCollection`  | اسم حامل البطاقة وعنوان الفوترة الكامل (الشارع، المدينة، المحافظة). | نعم لما يكون مفعّل. الإرسال بيفشل لو `customerDetails.billingDetails.address.line1` ناقص.     |
| `shippingAddressCollection` | اسم المستلِم وعنوان الشحن.                                          | نعم لما يكون مفعّل. الإرسال بيفشل لو `customerDetails.shipping.address.line1` ناقص.           |

الإيميل بيتطلب دايمًا ومطلوب دايمًا. هو وجهة الإيصال والمعرّف الأساسي لمنع تكرار الضيوف.

تسمية زر الإرسال بتتظبّط لوحدها عن طريق `submitType` (`pay` / `subscribe` / `book` / `donate`).

### الحقول المخصّصة [#الحقول-المخصّصة]

محتاج تطلب رقم ضريبي، أو ملاحظة على الطلب، أو تفضيل توصيل؟ `customFields` مصفوفة لحد 3 إدخالات. كل واحد بيعرض حقل إدخال على الفورم وإجابة العميل بترجع في رد الجلسة وحمولة الـ webhook.

| نوع الحقل  | الإدخال المعروض                             | التحقّق                                                                      |
| ---------- | ------------------------------------------- | ---------------------------------------------------------------------------- |
| `TEXT`     | حقل نص سطر واحد.                            | `minCharacters` / `maxCharacters` اختياري عن طريق `hasLimits` + `limitType`. |
| `NUMBER`   | حقل أرقام بس.                               | نفس حدود الأحرف بتنطبق.                                                      |
| `DROPDOWN` | قائمة بـ `dropdownOptions` بيحدّدها التاجر. | خيارين على الأقل مطلوبين.                                                    |
| `CHECKBOX` | مربع اختيار واحد العميل بيعلّمه.            | مفيش حدود أحرف.                                                              |

```jsonc
{
  "customFields": [
    {
      "label": "Tax ID",
      "type": "TEXT",
      "isOptional": false,
      "hasLimits": true,
      "limitType": "BETWEEN",
      "minCharacters": 9,
      "maxCharacters": 15,
    },
    {
      "label": "Delivery preference",
      "type": "DROPDOWN",
      "dropdownOptions": [{ "label": "Leave at door" }, { "label": "Hand to recipient" }],
    },
  ],
}
```

كل حقل بياخد `key` ثابت في السيرفر (مشتق من `label`) علشان الإجابة ترجع على نفس المفتاح في حمولة الرد. القيمة المجمَّعة بتعيش في الخانة المطابقة `text` / `numeric` / `dropdown` على كل إدخال.

## إزاي XPay بيتعامل مع العملاء الضيوف [#إزاي-xpay-بيتعامل-مع-العملاء-الضيوف]

مسار الدفع الافتراضي (من غير `customerId`، و`customerCreation: "if_required"`) بينشئ عميل ضيف أول مرة حد يدفع. &#x2A;*نفس الضيف بيتطابق في الزيارات اللي بعدها لما أي معرّف يتقاطع.** مش بتكتب أي كود لده.

XPay بيطابق بـ:

* **الإيميل**، من غير حساسية للأحرف الكبيرة/الصغيرة ومتشال منه الفراغات.
* **التليفون**، متطبّع (رمز الدولة، وبادئة `00` بتتحوّل لـ `+`).
* **بصمة البطاقة**، بتتلتقط بعد عملية دفع ناجحة. لو ضيف دفع ببطاقة اتشافت على سجل ضيف تاني، XPay بيدمج الاتنين وبيوحّد الإنفاق، وسجل الدفع، والأجهزة على السجل الباقي.

ده بيديك إيه في لوحة التحكم:

* ملف الضيف بيتراكم فيه كل إيميل، وتليفون، وبطاقة استخدمهم على مدار الوقت.
* إنفاق الضيف، والمبالغ المستردة، وعدد عمليات الدفع بتبقى دقيقة حتى لو دفع تلات مرات بثلاث فورمات مختلفة شوية.
* قسم "العملاء المرتبطين" في ملف العميل المسجَّل بيعرض سجلات الضيوف اللي بتشاركه بيانات التواصل، علشان المشغّل يربط بينهم.

اللي العملاء الضيوف مينفعش يعملوه:

* **مينفعش يبقى ليهم طريقة دفع محفوظة مربوطة لعمليات خصم مستقبلية.** كل دفع ضيف هو إدخال بطاقة جديد. لو منتجك محتاج بطاقات محفوظة (اشتراكات، إعادة طلب بضغطة واحدة)، لازم تظبّط `customerCreation: "always"` علشان تعمل عميل مسجَّل بدلًا منه.

## تجنّب تكرار سجلات العميل [#تجنّب-تكرار-سجلات-العميل]

أكبر طريقة بيقع فيها التجار: إعادة إنشاء عميل XPay مع كل تسجيل دخول أو كل طلب، بدل إعادة استخدام اللي عندك بالفعل. النمط اللي تحت بيتجنّب ده.

<Steps>
  <Step>
    ### خزّن الـ `cus_*` مقابل المستخدم المسجَّل بتاعك [#خزّن-الـ-cus_-مقابل-المستخدم-المسجَّل-بتاعك]

    لما مستخدم مسجَّل دخوله يعمل أول عملية دفع، ظبّط `customerCreation: "always"` وخُد `data.object.customer.id` من webhook الـ `checkout.session.completed`. احفظ الـ `cus_*` ده على صف المستخدم في قاعدة بياناتك.

    ```typescript
    // In your webhook handler
    if (event.type === "checkout.session.completed") {
      const session = event.data.object;
      const userId = session.metadata?.user_id; // you set this on session create
      const customerId = session.customer?.id; // cus_test_...

      if (userId && customerId) {
        await db.users.update(userId, { xpay_customer_id: customerId });
      }
    }
    ```
  </Step>

  <Step>
    ### مرّره كـ `customerId` على كل جلسة بعد كده [#مرّره-كـ-customerid-على-كل-جلسة-بعد-كده]

    لكل عملية دفع بعد كده من نفس المستخدم، ظبّط `customerId: "cus_test_..."`. الفورم بيتعبّى مسبقًا، مفيش عميل جديد بيتعمل، والإنفاق بيتجمّع تحت نفس السجل.

    ```typescript
    const session = await fetch("https://api.xpay.app/checkout/sessions", {
      method: "POST",
      headers: { Authorization: `Bearer ${process.env.XPAY_SECRET_KEY}`, "Content-Type": "application/json" },
      body: JSON.stringify({
        afterCompletion: { type: "redirect", redirect: { url: returnUrl } },
        customerId: user.xpay_customer_id, // re-use, don't recreate
        lineItems: [...],
      }),
    });
    ```
  </Step>

  <Step>
    ### ما تخزّنش `cus_*` بتاع ضيف على صفوف المستخدمين [#ما-تخزّنش-cus_-بتاع-ضيف-على-صفوف-المستخدمين]

    لو مستخدم دفع كضيف الأول (قبل ما يسجّل) وبعدين عمل حساب، الصح إنك تبدأ قصة الـ `cus_*` من أول عملية دفع **مسجَّلة** ليه. ما تحاولش تنقل `cus_*` بتاع الضيف على حسابه. الضيوف بيتمنع تكرارهم في السيرفر؛ والمشغّل يقدر يشوف الربط في قسم "العملاء المرتبطين" في لوحة التحكم.
  </Step>

  <Step>
    ### استخدم `metadata` علشان تمرّر معرّف المستخدم بتاعك إنت [#استخدم-metadata-علشان-تمرّر-معرّف-المستخدم-بتاعك-إنت]

    ظبّط `metadata: { user_id: "..." }` على كل جلسة بتنشئها. بترجعلك في حمولة الـ webhook، وفي رد استرجاع الجلسة، وعلى الـ Payment Intent. بيخلّي معالِج الـ webhook بتاعك بسيط جدًا: حمولة الجلسة بتقولك بالظبط أنهي مستخدم دفع.
  </Step>
</Steps>

النتيجة: عميل XPay مسجَّل واحد لكل مستخدم مسجَّل، والإنفاق على مدار الوقت بيتجمّع صح، والضيوف بيتتبّعوا لوحدهم من غير ما تضطر تديرهم.

## رايح فين بعد كده [#رايح-فين-بعد-كده]

<Cards>
  <Card icon="<TimerReset />" title="بعد إتمام الدفع" href="/integrate/checkout-session/after-completion">
    اظبط مكان وصول العميل بعد ما يدفع.
  </Card>

  <Card icon="<SlidersHorizontal />" title="الإعدادات المتقدّمة" href="/integrate/checkout-session/advanced-configuration">
    العلامة التجارية، واللغة، وطرق الدفع، والرسوم، والبيانات الوصفية.
  </Card>

  <Card icon="<Webhook />" title="إعداد نقطة نهاية webhook" href="/integrate/webhooks/setting-up-an-endpoint">
    استقبل `checkout.session.completed` علشان تقدر تاخد `data.object.customer.id`.
  </Card>
</Cards>