Skip to main content

ghl-api-extended (Python)

A GHL client covering the internal search-v2 endpoints GHL's own UI uses for Contacts, Opportunities, and Appointments/Calendar filtering — plus a self-contained OAuth token store, so it works standalone without any other project's auth.

This is the Python port of ghl-api-extended (the Node/TypeScript package). One difference: the JS package is a drop-in subclass of the official @gohighlevel/api-client SDK, so it inherits every official route (.contacts, .opportunities, .calendars, ...) for free. No official GHL SDK exists for Python, so HighLevel here only covers auth + these search-v2 endpoints — for any other GHL route, call ghl.request(method, url, ...) directly (see http.HighLevelClient.request).

These search-v2 endpoints aren't in GHL's public API docs; the field/operator behavior in docs/filters-reference.md and the per-endpoint docs was reverse-engineered by probing a live account. Check those before filtering on anything not already covered by the fetch_*_by_date_range helpers below.

Install

pip install ghl-api-extended

Usage

from ghl_api_extended import HighLevel

ghl = HighLevel(location_access_token=location_access_token)  # however you already obtain it

# Filter + auto-paginate the way the GHL UI's Contacts tab does.
contacts = ghl.fetch_contacts_by_date_range(ContactsByDateRangeParams(
    location_id=location_id,
    start_date="2026-01-01",
    end_date="2026-01-31",
    filters=[Filter(field="tags", operator="contains", value=["confirmed"])],
))
from ghl_api_extended import OpportunitiesByDateRangeParams, AppointmentsByDateRangeParams, Filter

opportunities = ghl.fetch_opportunities_by_date_range(OpportunitiesByDateRangeParams(
    location_id=location_id,
    date_field="last_stage_change_date",  # default: date_added
    start_date="2026-01-01",
    end_date="2026-01-31",
    filters=[Filter(field="pipeline_id", operator="eq", value=[pipeline_id])],
))

appointments = ghl.fetch_appointments_by_date_range(AppointmentsByDateRangeParams(
    location_id=location_id,
    start_date="2026-01-01",  # ranges over startTime by default
    end_date="2026-01-31",
    filters=[Filter(field="appoinmentStatus", operator="eq", value="confirmed")],
))

The fetch_*_by_date_range methods auto-paginate to exhaustion, same as scrolling a filtered list in the GHL UI — no separate page-loop needed. Each *ByDateRangeParams dataclass takes max_results/max_pages/page_limit if you want to bound that. For a single page, or full control over sort/pagination/aggregations, use ghl.search_contacts(...) / ghl.search_opportunities(...) / ghl.search_appointments(...) directly.

The same behavior is also available as standalone functions (search_contacts(client, location_id, ...), fetch_contacts_by_date_range(client, params), ...) that take any object with a compatible .request(method, url, ...) method — useful if you're not using the HighLevel class directly.

No existing auth? Use the built-in OAuth flow

Copy .env.example to .env, fill in your GHL marketplace app's GHL_CLIENT_ID / GHL_CLIENT_SECRET / GHL_REDIRECT_URI, then:

ghl-authorize

This opens the GHL OAuth consent screen, catches the redirect on a local server, and saves the company session to .tokens.json (gitignored). Location tokens are minted and cached automatically as you use them.

from ghl_api_extended import find_most_recent_company_id, get_authorized_location_client

company_id = find_most_recent_company_id()
ghl = get_authorized_location_client(company_id, location_id)  # a HighLevel instance

Filters

filters is a list of leaf Filter(field, operator, value) or FilterGroup(group="AND" | "OR", filters=[...]), nestable arbitrarily. Multiple entries at the top level are implicitly ANDed together — see docs/filters-reference.md for the full field/operator map per endpoint, including the traps (opportunities filter fields are snake_case and don't all mechanically match the response's camelCase names; contacts/appointments custom fields need a customFields.<key> dot-path — use contact_custom_field(key, operator, value) / opportunity_custom_field(...)).

Invalid fields are rejected client-side before the network call (GhlFilterFieldError); operator/value-shape errors from GHL itself are classified into GhlFilterOperatorError / GhlFilterValueError so you can branch on them instead of parsing message strings.

License

Apache-2.0

Release files for ghl-api-extended 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ghl-api-extended 0.1.0
File Size Uploaded
ghl_api_extended-0.1.0.tar.gz 27.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ghl-api-extended 0.1.0
File Interpreter ABI Platform
ghl_api_extended-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 51.1 kB

Release files / ghl_api_extended-0.1.0.tar.gz

Download URL ghl_api_extended-0.1.0.tar.gz
Size 27.0 kB
Tags Source
SHA-256 checksum
How to use checksums
ae455ba9b9357c62359844725788676d4533dc6b4fd86bd986be78c40c23e0ea
BLAKE2b-256 checksum
How to use checksums
4d30579ce82ba8c2396d7849be16ba63ff02ff54e4d7c89c3839d22d019331ac
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 21, 2026.

Transparency log

Release files / ghl_api_extended-0.1.0-py3-none-any.whl

Download URL ghl_api_extended-0.1.0-py3-none-any.whl
Size 24.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fb52b0ec39729b8b42193e5c0a5db25782d734ac9fc94682dfcd6242833526e0
BLAKE2b-256 checksum
How to use checksums
4f1ade1822891ebe6fe57a3ae66e6fa39805e592a5e282c85e02c35616d98a02
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 21, 2026.

Transparency log

Release history Release notifications | RSS feed

0.1.1

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page