> ## 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

> Integrate Dodo Payments with GoHighLevel (GHL) using no-code payment links, overlay checkout, or inline checkout, and automate fulfillment with webhooks.

## Introduction

Connect Dodo Payments to [GoHighLevel](https://www.gohighlevel.com/) (GHL) to sell from your GHL funnels, websites, emails, and SMS, and to fulfill orders with GHL automation. GHL is a CRM and marketing platform with funnels, websites, email and SMS, and automation (**Workflows**). GHL doesn't list Dodo Payments as a built-in payment processor, so you connect the two in one of three ways. Pick one based on how embedded you want checkout to be and how much code you can write.

Every approach handles fulfillment the same way: Dodo Payments sends [webhook events](/developer-resources/webhooks) to a GHL **Inbound Webhook** workflow, which tags the contact, grants access, and sends confirmations.

## Choose Your Approach

The three approaches differ in the code they need and in where the customer pays:

| Approach | Code needed | Checkout experience | Best for |
| - | - | - | - |
| **A. Payment Links** | None (no-code) | The customer goes to the Dodo Payments hosted checkout | Most GHL users, fastest to launch |
| **B. Overlay Checkout** | Custom code plus a backend | A modal opens over your GHL page | Teams who want checkout on the page without leaving the funnel |
| **C. Inline Checkout** | Custom code plus a backend | The checkout form is embedded in the page | A fully embedded, branded checkout |

<Info>
  If you're new to Dodo Payments, start with **Approach A (Payment Links)**. It needs no code and works for every GHL user. Approaches B and C need a backend that creates [checkout sessions](/api-reference/checkout-sessions/create), so they suit teams that are comfortable with code.
</Info>

## Prerequisites

Before you start, you need:

* A Dodo Payments account with at least one **product**.
* A GoHighLevel account with a funnel, website, or workflow.
* Access to **Developer → Webhooks** in the Dodo Payments dashboard, and to **Developer → API Keys** if you need an API key.
* For Approaches B and C: a small **backend or serverless endpoint** that creates checkout sessions.

<Note>
  GHL requires a **connected domain** to *publish* a funnel. While you build, use the funnel's **Preview** to test. Custom JavaScript (Approaches B and C) generally runs only on the **published page on a real domain**, not in Preview.
</Note>

## Fulfillment with Webhooks (All Approaches)

The webhook workflow is the automation layer. Set it up once, and it works with every checkout approach.

<Steps>
  <Step title="Create the Workflow">
    In your GHL **sub-account**, open **Automation** in the left menu. It opens on the **Workflows** tab. Click **Create workflow**, then choose **Start from Scratch**.
  </Step>

  <Step title="Add the Inbound Webhook Trigger">
    In the builder, click **Add new trigger**. In the **Add trigger** panel, search for **webhook** and select **Inbound webhook**, listed under **Triggers → Events**. Copy the **Webhook URL** that it generates.
  </Step>

  <Step title="Register the Webhook in Dodo Payments">
    In the Dodo Payments dashboard, go to **Developer → Webhooks** and click **Add endpoint**. Paste the GHL Inbound Webhook URL into **Endpoint URL** and click **Create endpoint**. Then give GHL a sample payload to map fields from, such as the customer email, product, amount, and status. Either make a test purchase, or open the endpoint's **Testing** tab, select an event type, and click **Send example**.
  </Step>

  <Step title="Add Fulfillment Actions">
    In the GHL workflow, add actions for the event, such as **find/create contact by email**, **add a tag**, **grant course/membership access**, and **send a confirmation email**. Then **Publish** the workflow.
  </Step>
</Steps>

<Warning>
  Dodo Payments processes the payments, so they **don't** appear in the GHL **Payments** tab. Record them in GHL with the webhook workflow above. Grant access from the **webhook**, not from the browser redirect, because a customer can close the tab before the redirect completes.
</Warning>

## Approach A: Payment Links (No-Code)

Add a Dodo Payments payment link to any GHL button, funnel call to action, order page button, email, or SMS. Customers pay on the Dodo Payments hosted checkout. For what the checkout supports, see [Checkout Features](/features/checkout).

<Steps>
  <Step title="Create a Product and Copy Its Payment Link">
    In the Dodo Payments dashboard, go to **Products** and click **Add Product**. Set the **name** and **price**, choose **one-time** or **subscription**, and save the product. On the product's row, click **Share**, then click **Copy payment link**. The link has the format `https://checkout.dodopayments.com/buy/{product_id}`.
  </Step>

  <Step title="Add the Link to Your GHL Button">
    Edit your funnel or website page and select the **Buy / Checkout button**. Set its action to **Open URL / Website** and paste your payment link.
  </Step>

  <Step title="Set a Success Page (Optional)">
    To bring customers back to your funnel after they pay, enter your GHL thank-you page in **Redirect URL** in the product's **Share** sheet before you copy the link. The link then carries it as the `redirect_url` parameter.
  </Step>
</Steps>

<Tip>
  Payment link query parameters can prefill and lock customer details, or add tracking. For example, pass a funnel or offer ID as a `metadata_*` parameter and read it back from the webhook. See [Static Payment Links](/developer-resources/integration-guide#static-payment-links) for every parameter.
</Tip>

## Approach B: Overlay Checkout (Custom Code)

Approach B opens Dodo Payments checkout as a **modal overlay** on your GHL page, using the [Checkout SDK](/developer-resources/overlay-checkout) from a CDN. It needs a backend that creates a [checkout session](/api-reference/checkout-sessions/create) and returns its `checkoutUrl`.

<Steps>
  <Step title="Create a Backend Endpoint That Calls the Checkout Sessions API">
    This step is **required**. The SDK needs a checkout session URL, and creating a session requires your **secret API key**. GHL hosts pages only and can't make this server-side call for you. Never call the [Create Checkout Session API](/api-reference/checkout-sessions/create) from the browser, because that exposes your secret key in the page source. Overlay and inline checkout therefore **can't work with GHL alone**: you need a backend you control that creates the session and returns only the URL.

    Any small backend works: a serverless function (Cloudflare Workers, Vercel Functions, AWS Lambda, Supabase Edge Functions, and similar), or an endpoint on a server you already run. The logic is the same on every platform: receive the request, call the Dodo Payments API with your secret key, and return the `checkout_url`.

    Example handler logic, to adapt to your platform:

    ```js theme={null}
    async function createCheckout(env) {
      const res = await fetch("https://test.dodopayments.com/checkouts", {
        method: "POST",
        headers: {
          "Authorization": `Bearer ${env.DODO_PAYMENTS_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 };
    }
    ```

    Store your API key as a secret in the `DODO_PAYMENTS_API_KEY` environment variable on the platform you deploy to, and never commit it to code. Allow requests from your GHL domain (CORS), and serve the endpoint from a domain you control, for example `https://api.example.com/create-checkout`. When you move to live mode, switch the URL to `https://live.dodopayments.com/checkouts`.
  </Step>

  <Step title="Add a Custom Code Element in the GHL Page Builder">
    Open your funnel step or website page in the GHL page builder, then:

    1. Click the **+** icon at the top left of the builder to open **Quick Add**.
    2. Select **Elements** from the category list on the left.
    3. Find **Custom Code** (also shown as HTML) and drag it onto the page.
    4. Paste the code below into the element's code editor, then save it.

    ```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 JavaScript runs on the **published** page on your connected domain, and may not run in Preview. Publish the page, then click **Pay Now** to confirm that the overlay opens.
  </Step>
</Steps>

## Approach C: Inline (Embedded) Checkout

Approach C embeds the checkout form **inside** your GHL page, with no redirect and no popup. It uses the same SDK with a container element to mount into. Like Approach B, it needs a backend to create the session.

<Steps>
  <Step title="Create a Backend Endpoint That Calls the Checkout Sessions API">
    This step is **required**, as it is for overlay checkout. Creating a session needs your secret API key, so it must happen on a server, and GHL can't do this on its own. Reuse the backend endpoint from the **Overlay Checkout** section above: any small serverless function or server you control that calls the [Create Checkout Session API](/api-reference/checkout-sessions/create) and returns `{ checkoutUrl }`.
  </Step>

  <Step title="Add a Container and SDK via Custom Code">
    In the GHL page builder:

    1. Click the **+** icon at the top left of the builder to open **Quick Add**.
    2. Select **Elements** from the category list on the left.
    3. Find **Custom Code** (also shown as HTML) and drag it onto the page where you want the checkout form to appear.
    4. Paste the code below into the element's code editor, then save it.

    ```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)">
    To offer Apple Pay in inline checkout, [verify your domain](/features/payment-methods/digital-wallets#apple-pay). In the Dodo Payments dashboard, go to **Settings → Payment Methods** and click **Manage domains** on the **Apple Pay** row. Download the domain association file, host it on your domain, and register the domain. Apple Pay isn't available in overlay checkout (Approach B).

    A GHL-hosted domain can't host the domain association file. Apple Pay in inline checkout needs a domain you control that can serve `/.well-known/apple-developer-merchantid-domain-association`. On GHL-hosted pages, use the hosted checkout from Payment Links (Approach A) or skip Apple Pay.
  </Step>
</Steps>

<Warning>
  Inline checkout is the most involved option in GHL. It needs custom code, a backend, a published page on a real domain, and, for Apple Pay, domain verification. If you don't need a fully embedded form, use Approach A or B instead.
</Warning>

## Events to Handle

Subscribe the GHL endpoint to the events your workflow acts on. The table suggests a GHL action for each:

| Dodo Payments event | When it fires | Suggested GHL action |
| - | - | - |
| `payment.succeeded` | A payment succeeds | Tag the contact as paid, grant access, send a confirmation |
| `subscription.active` | A subscription is activated | Grant membership, start the onboarding workflow |
| `subscription.renewed` | A subscription renews for the next billing period | Extend access for the next cycle |
| `subscription.past_due` | A renewal fails and the grace period opens. The customer keeps access until the deadline | Start the dunning or reminder workflow while the customer still has access |
| `subscription.on_hold` | The subscription is put on hold after a failed renewal | Pause access, escalate the reminder sequence |
| `subscription.cancelled` / `subscription.expired` | The subscription ends | Remove access, tag as churned |

Payment and subscription events include the **customer email** in `data.customer.email`. Use GHL's **find/create contact by email** action to match the payment to the right contact. For every event, see the [Webhook Event Guide](/developer-resources/webhooks/intents/webhook-events-guide).

## Testing & Going Live

<Steps>
  <Step title="Test in Test Mode">
    Keep the **Live Mode** switch in the Dodo Payments sidebar off, so you work in test mode. Complete a purchase with the test card `4242 4242 4242 4242` (expiry `06/32`, CVV `123`), and confirm that the GHL workflow runs and applies the tag or access.
  </Step>

  <Step title="Go Live">
    Turn on the **Live Mode** switch and add the GHL Inbound Webhook URL as an endpoint in live mode. What else changes depends on your approach:

    * **Payment Links (A):** Replace the link with the product's **live** payment link.
    * **Overlay checkout (B):** Point your backend at `https://live.dodopayments.com/checkouts` with your **live** API key, and set `mode` to `"live"` in the SDK's `Initialize` call.
    * **Inline checkout (C):** Make the same changes as for overlay checkout, since it uses the same backend endpoint and SDK initialization.

    Then make one real purchase from start to finish to confirm the setup.
  </Step>
</Steps>

## Tips

<Tip>
  Treat the **webhook as the source of truth** for granting access. Act on `payment.succeeded` or `subscription.active`, not on the browser redirect.
</Tip>

<Tip>
  A GHL Inbound Webhook can't verify the `webhook-signature` header. So that only genuine Dodo Payments events trigger fulfillment in GHL, point the Dodo Payments webhook endpoint at your own backend, verify each event there ([Webhooks](/developer-resources/webhooks)), and then forward it to the GHL Inbound Webhook URL.
</Tip>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Payment succeeded but nothing happened in GHL">
    Check that the Dodo Payments webhook endpoint points to the correct GHL Inbound Webhook URL, that the workflow is **published**, and that the trigger captured a sample payload, so the field mapping exists.
  </Accordion>

  <Accordion title="Overlay or inline button does nothing">
    Custom JavaScript usually runs only on the **published page on a real domain**, not in Preview. Confirm that the page is published, that the SDK `<script>` loaded, and that `checkoutUrl` is a valid session URL from your backend.
  </Accordion>

  <Accordion title="Contact not created or not matched">
    Check that your workflow uses **find/create contact by email** and that the email field is mapped from the webhook payload.
  </Accordion>

  <Accordion title="Payment isn't showing in GHL's Payments tab">
    This is expected. Dodo Payments processes the payments, so record them in GHL with the webhook workflow.
  </Accordion>
</AccordionGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.