@brewedops-ghl/cli
v0.1.0
Published
GHL CLI - GoHighLevel internal API from the command line (token-id auth, auto-refresh, account audit)
Readme
ghl CLI
GoHighLevel from the command line. Zero dependencies (Node 18+ global fetch).
Uses the live-verified universal token-id auth, with Firebase auto-refresh wired in.
Install (developer way)
# published (from anywhere):
npm install -g @brewedops-ghl/cli
# or from this folder (local dev):
cd packs/ghl/cli
npm install -g . # or: npm linkRequires Node.js 18+. The installed command is ghl (the package is
@brewedops-ghl/cli; the command name is separate).
First run
ghl login tokens.json # paste the Key Grabber JSON (file or stdin)
# Windows: Get-Clipboard | ghl login
# macOS: pbpaste | ghl login
ghl whoami # confirm: company, locations, token expiryTokens are stored at ~/.ghl/config.json (mode 0600) — never in any repo.
No Key Grabber extension? Two ways without it
The extension is just a convenience for copying the session token. You don't need it.
Option 1 — Browser DevTools (full CLI, no install). Yields the same session token, so every command works:
- Open GHL in the browser, logged in.
- Press F12 → Network tab.
- Click around so a request to
backend.leadconnectorhq.comappears, click it. - Under Request Headers, copy the
token-idvalue and theauthorization: Bearer …value (that's the rs256 token). - Build a small JSON and log in:
{ "tokenId": "<token-id value>", "rs256Bearer": "<bearer value>", "locationId": "<sub-account id>", "companyId": "<agency id>" }ghl login tokens.json
Option 2 — Private Integration Token (official, nothing to scrape). In the
sub-account: Settings → Private Integrations → Create, scope it, copy the token.
A PIT is long-lived and needs no browser session. It powers the official v2 / MCP lane
(contacts, opportunities, calendars, payments, conversations, locations) — see
../knowledge/v2-mcp-catalog.md. Note: a PIT does not reach the internal-only
endpoints (full workflow JSON, email builder, funnel internals); those need a session
token (Option 1 or the extension). Full --pit support in this CLI is a planned add.
Use
ghl audit # full read-only audit of the default location -> markdown
ghl audit <locationId> --out report.md
ghl whoami
ghl fields <locationId> # custom fields
ghl workflows # workflow list (uses default location)
ghl tags --json
ghl get /locations/<loc>/customValues # raw GET (backend host)
ghl get /surveys/?locationId=<loc> --services # raw GET (services host)Read subcommands: users pipelines workflows fields values tags calendars forms surveys funnels products contacts. loc defaults to the location saved at login; add --json for raw output.
Auto-refresh (retire Key Grabber)
The token from ghl login lasts ~1 hour. To make the CLI self-renewing, capture the
refresh token + Firebase key once and enable it:
ghl set-refresh <AMf-refreshToken> <firebaseWebApiKey>After that, every command checks token expiry and mints a fresh one automatically
(securetoken.googleapis.com exchange), and retries once on a 401. No more pasting.
The refresh exchange is standard Firebase but unverified for GHL accounts until we capture a real
AMf-token + key. That validation is the make-or-break: if it works, Key Grabber is retired; if not,ghl loginper session still beats hourly pasting.
How it maps to the knowledge pack
- Auth + headers:
../knowledge/auth-and-tokens.md - Endpoints + param traps + error catalog:
../knowledge/endpoint-map.md - The official MCP alternative (PIT, no token dance):
../knowledge/v2-mcp-catalog.md - Design rationale + roadmap:
./DESIGN.md
Files
src/index.mjs argv parse + dispatch + help
src/config.mjs ~/.ghl/config.json load/save
src/auth.mjs JWT decode, expiry, header set, Firebase refresh
src/client.mjs authenticated GET, refresh-on-expiry, retry-on-401, firstArray()
src/commands.mjs login, set-refresh, whoami, get, audit, convenience reads