# ITLoop Connect — GoHighLevel setup

This guide connects an ITLoop Connect widget to your GoHighLevel (GHL) sub-account
so that every "Continue with LinkedIn" sign-in creates a contact automatically.

There are two dispatch modes. **Webhook is the recommended path** — it carries no
API key, so nothing sensitive is stored.

---

## Option A — Inbound Webhook (recommended)

1. In GHL, open **Automation → Workflows → Create Workflow**.
2. Add the trigger **Inbound Webhook**. Copy the generated webhook URL.
3. In your ITLoop Connect admin (`/connect/admin`), set **Dispatch mode = Webhook**
   and paste the URL into **GHL Webhook URL**. Save.
4. Back in the workflow, add a **Create/Update Contact** action and map the fields:

   | Incoming field | Map to GHL |
   | --- | --- |
   | `email` | Email |
   | `firstName` | First Name |
   | `lastName` | Last Name |
   | `name` | Full Name |
   | `companyName` | Company (optional, only if the visitor shared it) |
   | `title` | Job Title (optional, only if shared) |
   | `source` | Source (value: `ITLoop Connect`) |
   | `tags` | Tags (includes `itloop-connect`) |
   | `linkedin_id` | Custom field (optional) |
   | `photo_url` | Custom field (optional) |

5. Publish the workflow. Use **Send test lead** in the admin to confirm a
   `SAMPLE` contact arrives (it is tagged `itloop-test`).

## Option B — Private Integration Token (GHL v2 API)

Use only if you cannot use a webhook. Contacts are upserted via
`POST https://services.leadconnectorhq.com/contacts/upsert`.

1. In GHL, go to **Settings → Private Integrations** and create a token with the
   **Contacts (write)** scope.
2. In `/connect/admin`, set **Dispatch mode = GHL API**, paste the token, and set
   your **Location ID**. Save.

The token is **encrypted at rest** (AES-256-GCM) and is never displayed again or
logged. Rotate it in GHL and re-paste to replace it.

---

## What data is captured

The LinkedIn "Sign In with OpenID Connect" product returns only:

- Name (given + family)
- Verified email address
- Profile photo URL
- LinkedIn member ID (`sub`)
- Locale

**Job title and company are NOT returned by LinkedIn.** If you enable the optional
step, the visitor may type them in after signing in; otherwise those fields are
empty. Never configure copy that implies title/company come from LinkedIn.

## Allowlists (required for live use)

In the admin, set:

- **Allowed origins** — the site(s) where you embed the widget iframe (e.g.
  `https://acme-msp.com`). Used to restrict where sign-in results are posted.
- **Allowed redirects** — the exact URL(s) you send visitors to after sign-in.
  This prevents open-redirect abuse.
