> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dodopayments.com/llms.txt
> Use this file to discover all available pages before exploring further.

# GoHighLevel

> no-code payment links, overlay checkout 또는 inline checkout을 사용하여 Dodo Payments를 GoHighLevel(GHL)과 통합하고, webhooks로 fulfillment를 자동화하세요.

## 소개

[GoHighLevel](https://www.gohighlevel.com/) (GHL)은 funnels, websites, email/SMS 및 automation("Workflows")을 제공하는 all-in-one CRM 및 marketing 플랫폼입니다. GHL은 Dodo Payments를 기본 processor로 등록하지 않으므로, checkout을 얼마나 자연스럽게 embedded할지와 코딩 가능한 수준에 따라 다음 세 가지 방법 중 하나로 두 서비스를 연결해야 합니다.

모든 접근 방식에서 fulfillment는 동일한 방식으로 처리됩니다. Dodo는 [webhook events](/developer-resources/webhooks)를 GHL **Inbound Webhook Workflow**로 전송하고, 이 workflow가 contact에 tag를 추가하고 access를 부여하며 confirmation을 전송합니다.

## 접근 방식 선택

| 접근 방식                   | 필요한 코드                | Checkout 경험                           | 적합한 대상                                  |
| ----------------------- | --------------------- | ------------------------------------- | --------------------------------------- |
| **A. Payment Links**    | 없음 (no-code)          | 고객이 Dodo의 hosted checkout으로 redirect됨 | 대부분의 GHL 사용자, 빠른 launch                 |
| **B. Overlay Checkout** | Custom code 및 backend | GHL 페이지 위에 modal이 열림                  | funnel을 벗어나지 않고 on-page checkout을 원하는 팀 |
| **C. Inline Checkout**  | Custom code 및 backend | 페이지 내부에 checkout form이 embedded됨      | 완전히 embedded된 branded UX                |

<Info>
  처음 사용하시나요? \*\*접근 방식 A(Payment Links)\*\*부터 시작하세요. no-code 방식이며 모든 GHL 사용자에게 작동하고 몇 분이면 설정할 수 있습니다. 접근 방식 B와 C는 [checkout sessions](/api-reference/checkout-sessions/create)을 생성할 backend가 필요하며, 코드 사용에 익숙한 팀을 위한 방식입니다.
</Info>

## 사전 요구 사항

* 하나 이상의 **product**가 생성된 Dodo Payments account.
* funnel, website 또는 workflow가 있는 GoHighLevel account.
* Dodo dashboard의 **Settings → Webhooks**(API key에는 **Settings → Developer**)에 대한 access.
* 접근 방식 B와 C의 경우: checkout sessions를 생성할 소규모 **backend 또는 serverless endpoint**.

<Note>
  GHL에서 funnel을 *publish*하려면 **connected domain**이 필요합니다. 구축 중에는 funnel의 **Preview**를 사용하여 테스트하세요. Custom JavaScript(접근 방식 B와 C)는 일반적으로 Preview가 아니라 **실제 domain의 published page**에서만 실행됩니다.
</Note>

## webhooks를 사용한 fulfillment(모든 접근 방식)

이 부분이 automation layer입니다. 한 번 설정하면 어떤 checkout 접근 방식을 선택하든 작동합니다.

<Steps>
  <Step title="Create the workflow">
    GHL **sub-account**에서 왼쪽 메뉴의 **Automation**을 엽니다(그러면 **Workflows** tab으로 이동합니다). **Create workflow**를 클릭한 다음 **Start from Scratch**를 선택합니다.
  </Step>

  <Step title="Add the Inbound Webhook trigger">
    Builder에서 **Add new trigger**를 클릭합니다. **Add trigger** panel에서 **webhook**을 검색하고 **Inbound webhook**(**Triggers → Events** 아래에 표시됨)을 선택합니다. 생성된 **Webhook URL**을 복사합니다.
  </Step>

  <Step title="Register the webhook in Dodo">
    Dodo dashboard에서 **Settings → Webhooks**로 이동하여 새 endpoint를 추가하고 GHL Inbound Webhook URL을 붙여넣습니다. 테스트 구매를 진행하여 GHL이 sample payload를 수집하도록 하면 field(customer email, product, amount, status)를 매핑할 수 있습니다.
  </Step>

  <Step title="Add fulfillment actions">
    GHL workflow로 돌아가 event에 따른 action을 추가합니다. 예를 들면 **find/create contact by email**, **add a tag**, **grant course/membership access**, **send a confirmation email** 등이 있습니다. 그런 다음 workflow를 **Publish**합니다.
  </Step>
</Steps>

<Warning>
  Payments는 Dodo에서 처리되므로 GHL의 Payments tab에 **표시되지 않습니다**. 위의 webhook workflow를 사용하여 GHL에 반영하고, access 부여의 **source of truth로 webhook**을 사용하세요. 고객이 돌아오기 전에 tab을 닫을 수 있으므로 browser redirect를 기준으로 삼아서는 안 됩니다.
</Warning>

## 접근 방식 A: Payment Links(no-code)

GHL button, funnel CTA, order-page button, email 또는 SMS에 Dodo payment link를 연결합니다.

<Steps>
  <Step title="Create a product and copy its payment link">
    Dodo dashboard에서 **Products → Add Product**로 이동하여 **name**과 **price**를 설정하고 **one-time** 또는 **subscription**을 선택한 후 **Save**합니다. Product를 열고 **Payment Link**를 복사합니다(format: `https://checkout.dodopayments.com/buy/{product_id}`).
  </Step>

  <Step title="Add the link to your GHL button">
    Funnel 또는 website page를 편집하고 **Buy / Checkout button**을 선택한 다음 action을 **Open URL / Website**로 설정하고 Dodo payment link를 붙여넣습니다.
  </Step>

  <Step title="Set a success page (optional)">
    Dodo에서 product의 **return URL**을 GHL thank-you page로 설정하여 고객이 결제 후 funnel로 돌아오도록 합니다.
  </Step>
</Steps>

<Tip>
  [payment-link query parameters](/features/checkout)을 사용하여 customer details를 미리 입력하고 잠그거나 tracking을 추가할 수 있습니다. 이를 통해 funnel 또는 offer ID를 metadata로 전달하고 webhook에서 다시 읽어올 수 있습니다.
</Tip>

## 접근 방식 B: Overlay Checkout(custom code)

CDN을 통한 [Checkout SDK](/developer-resources/overlay-checkout)를 사용하여 GHL page에서 Dodo checkout을 **modal overlay**로 엽니다. [checkout session](/api-reference/checkout-sessions/create)을 생성하고 `checkoutUrl`을 반환할 backend가 필요합니다.

<Steps>
  <Step title="Create a backend endpoint that calls the Checkout Sessions API">
    이 단계는 **선택 사항이 아닙니다**. SDK에는 live `checkoutUrl`이 필요하며, 이를 생성하려면 **secret API key**가 필요합니다. GHL은 static page만 호스팅하므로 이 server-side call을 대신 실행할 수 없습니다. 또한 page source에 secret key가 노출되므로 browser에서 [Create Checkout Session API](/api-reference/checkout-sessions/create)를 직접 호출해서는 안 됩니다. 따라서 overlay 및 inline checkout은 **GHL만으로 작동할 수 없으며**, session을 생성하고 URL만 반환하는 backend가 필요합니다.

    어떤 소규모 backend든 사용할 수 있습니다. 예를 들어 serverless function(Cloudflare Workers, Vercel Functions, AWS Lambda, Supabase Edge Functions 등)이나 이미 운영 중인 server의 endpoint를 사용할 수 있습니다. 어디서나 logic은 동일합니다. request를 수신하고, secret key로 Dodo API를 호출한 다음 `checkout_url`을 반환합니다.

    사용 중인 platform에 맞게 조정할 수 있는 example handler logic:

    ```js theme={null}
    async function createCheckout(env) {
      const res = await fetch("https://test.dodopayments.com/checkouts", {
        method: "POST",
        headers: {
          "Authorization": `Bearer ${env.DODO_API_KEY}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          product_cart: [{ product_id: "pdt_your_product_id", quantity: 1 }],
        }),
      });

      const data = await res.json();
      return { checkoutUrl: data.checkout_url };
    }
    ```

    배포하는 platform에 Dodo API key를 secret으로 저장하고(코드에 절대 commit하지 마세요), GHL domain의 request를 허용하며(CORS), 관리하는 domain 아래에 endpoint를 routing합니다(예: `https://api.example.com/create-checkout`). live mode로 전환하면 `https://live.dodopayments.com/checkouts`로 변경합니다.
  </Step>

  <Step title="Add a Custom Code element in the GHL page builder">
    GHL page builder에서 funnel step 또는 website page를 연 다음 다음을 수행합니다:

    1. Builder의 왼쪽 상단에서 **+** icon을 클릭하여 **Quick Add**를 엽니다.
    2. 왼쪽 category list에서 **Elements**를 선택합니다.
    3. **Custom Code**(HTML로도 표시됨)를 찾아 페이지로 drag합니다.
    4. 아래 code를 element의 code editor에 붙여넣고 저장합니다.

    ```html theme={null}
    <!-- Load the Dodo Checkout SDK -->
    <script src="https://cdn.jsdelivr.net/npm/dodopayments-checkout@latest/dist/index.js"></script>
    <script>
      DodoPaymentsCheckout.DodoPayments.Initialize({
        mode: "test", // change to "live" in production
        displayType: "overlay",
        onEvent: (event) => console.log("Checkout event:", event),
      });

      async function openDodoCheckout() {
        // calls the backend endpoint from the previous step, creating a fresh session per click
        const res = await fetch("https://api.example.com/create-checkout", { method: "POST" });
        const { checkoutUrl } = await res.json();

        DodoPaymentsCheckout.DodoPayments.Checkout.open({ checkoutUrl });
      }
    </script>

    <button onclick="openDodoCheckout()">Pay Now</button>
    ```
  </Step>

  <Step title="Publish and test on your domain">
    Custom JS는 항상 Preview가 아니라 \*\*published page(connected domain)\*\*에서 실행됩니다. Publish한 후 **Pay Now**를 클릭하여 overlay가 열리는지 확인합니다.
  </Step>
</Steps>

## 접근 방식 C: Inline(embedded) Checkout

동일한 SDK와 mount container를 사용하여 GHL page **내부에** checkout form을 embedded합니다(redirect 없음, popup 없음). 접근 방식 B와 마찬가지로 session을 생성할 backend가 필요합니다.

<Steps>
  <Step title="Create a backend endpoint that calls the Checkout Sessions API">
    Overlay와 동일한 요구 사항이며 역시 **선택 사항이 아닙니다**. session 생성에는 secret API key가 필요하므로 server-side에서 처리해야 합니다. GHL은 자체적으로 이를 수행할 수 없습니다. 위의 **Overlay Checkout** section에서 설명한 동일한 backend endpoint(관리하는 소규모 serverless function 또는 server)를 재사용하세요. 이 endpoint는 [Create Checkout Session API](/api-reference/checkout-sessions/create)를 호출하고 `{ checkoutUrl }`을 반환합니다.
  </Step>

  <Step title="Add a container and SDK via Custom Code">
    GHL page builder에서 다음을 수행합니다:

    1. Builder의 왼쪽 상단에서 **+** icon을 클릭하여 **Quick Add**를 엽니다.
    2. 왼쪽 category list에서 **Elements**를 선택합니다.
    3. **Custom Code**(HTML로도 표시됨)를 찾아 checkout form을 표시할 페이지 위치로 drag합니다.
    4. 아래 code를 element의 code editor에 붙여넣고 저장합니다.

    ```html theme={null}
    <script src="https://cdn.jsdelivr.net/npm/dodopayments-checkout@latest/dist/index.js"></script>

    <div id="dodo-inline-checkout"></div>

    <script>
      DodoPaymentsCheckout.DodoPayments.Initialize({
        mode: "test",
        displayType: "inline",
        onEvent: (event) => console.log("Checkout event:", event),
      });

      async function mountDodoCheckout() {
        // calls the backend endpoint from the previous step
        const res = await fetch("https://api.example.com/create-checkout", { method: "POST" });
        const { checkoutUrl } = await res.json();

        DodoPaymentsCheckout.DodoPayments.Checkout.open({
          checkoutUrl,
          elementId: "dodo-inline-checkout",
        });
      }

      mountDodoCheckout();
    </script>
    ```
  </Step>

  <Step title="Verify your domain for wallets (Apple Pay)">
    Inline checkout에서 Apple Pay를 사용하려면 [domain을 verify](/features/payment-methods/digital-wallets#apple-pay)하세요. Association file을 호스팅하고 dashboard에 domain을 등록합니다.
  </Step>
</Steps>

<Warning>
  Inline은 GHL에서 가장 복잡한 option입니다. Custom code, backend, 실제 domain의 published page, 그리고 Apple Pay의 경우 domain verification이 필요합니다. 완전히 embedded된 form이 필요하지 않다면 접근 방식 A 또는 B를 사용하세요.
</Warning>

## 처리할 Events

| Dodo event                                        | 발생 시점                    | 권장 GHL action                                      |
| ------------------------------------------------- | ------------------------ | -------------------------------------------------- |
| `payment.succeeded`                               | Payment가 captured됨       | Contact를 paid로 tag하고 access를 부여한 후 confirmation 전송 |
| `subscription.active`                             | Subscription이 activated됨 | Membership을 부여하고 onboarding workflow 시작            |
| `subscription.renewed`                            | Renewal payment가 처리됨     | 다음 cycle에 대한 access 연장                             |
| `subscription.on_hold`                            | Renewal이 failed됨         | Dunning 또는 reminder workflow 실행                    |
| `subscription.cancelled` / `subscription.expired` | Subscription이 종료됨        | Access 제거 및 churned로 tag                           |

모든 webhook에는 **customer email**이 포함됩니다. GHL의 **find/create contact by email** action을 사용하여 payment를 올바른 contact에 연결하세요. 전체 목록은 [Webhook Event Guide](/developer-resources/webhooks/intents/webhook-events-guide)를 참조하세요.

## Testing 및 Live 전환

<Steps>
  <Step title="Test in test mode">
    Dodo를 **Test Mode**로 유지하고 test card `4242 4242 4242 4242`(임의의 미래 expiry 및 CVC)을 사용하여 purchase를 완료한 다음 GHL workflow가 실행되고 tag 또는 access를 적용하는지 확인합니다.
  </Step>

  <Step title="Go live">
    Dodo를 **Live Mode**로 전환하고 live-mode webhook endpoint를 업데이트합니다. 그 외 변경 사항은 접근 방식에 따라 다릅니다:

    * **Payment Links(A):** product의 **live** payment link로 교체합니다.
    * **Overlay checkout(B):** backend가 `https://live.dodopayments.com/checkouts`를 사용하도록 하고 **live** API key를 설정한 다음, `Initialize` call에서 SDK의 `mode`를 `"live"`로 설정합니다.
    * **Inline checkout(C):** 동일한 backend endpoint와 SDK initialization을 사용하므로 overlay와 동일합니다.

    그런 다음 실제 end-to-end purchase를 한 번 실행하여 확인합니다.
  </Step>
</Steps>

## Tips

<Tip>
  Access 부여의 **source of truth로 webhook**을 사용하세요. Browser redirect가 아니라 `payment.succeeded` / `subscription.active`에 따라 처리합니다.
</Tip>

<Tip>
  `webhook-signature` header([Standard Webhooks](/developer-resources/webhooks))를 사용하여 webhook authenticity를 verify하세요. 그러면 genuine Dodo event만 GHL에서 fulfillment를 trigger할 수 있습니다.
</Tip>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Payment succeeded but nothing happened in GHL">
    Dodo webhook endpoint가 올바른 GHL Inbound Webhook URL을 가리키는지, workflow가 **published** 상태인지, 그리고 field mapping이 생성되도록 trigger가 sample payload를 수집했는지 확인합니다.
  </Accordion>

  <Accordion title="Overlay or inline button does nothing">
    Custom JS는 일반적으로 Preview가 아니라 \*\*published page(real domain)\*\*에서만 실행됩니다. Page가 published 상태인지, SDK `<script>`가 loaded되었는지, `checkoutUrl`가 backend에서 반환된 유효한 session URL인지 확인합니다.
  </Accordion>

  <Accordion title="Contact not created or not matched">
    Workflow가 **find/create contact by email**을 사용하고 email field가 webhook payload에서 mapping되었는지 확인합니다.
  </Accordion>

  <Accordion title="Payment isn't showing in GHL's Payments tab">
    정상적인 동작입니다. Payments는 Dodo에서 처리되므로 webhook workflow를 사용하여 GHL에 반영합니다.
  </Accordion>
</AccordionGroup>
