Skip to main content

Crate ghl_sdk

Crate ghl_sdk 

Source
Expand description

Unofficial async Rust SDK for the GoHighLevel (HighLevel) CRM API.

Every endpoint has a typed Rust method — 1,203 operations across 45 modules, in API v2 and v3, each with generated request/response types, so you never have to leave the library to read HighLevel’s docs.

use ghl_sdk::{contacts::CreateContact, Ghl};

// Reads GHL_PIT_TOKEN (or GHL_ACCESS_TOKEN) from the environment.
let ghl = Ghl::from_env()?;

let contact = ghl.contacts().create(CreateContact {
    location_id: "LOCATION_ID".into(),
    email: Some("ada@example.com".into()),
    first_name: Some("Ada".into()),
    ..Default::default()
}).await?;

println!("created {}", contact.id);

§What you get

  • Auth — Private Integration Tokens, raw OAuth access tokens, or full OAuth 2.0 with automatic single-flight refresh and a pluggable TokenStore. Agency→location token exchange via Ghl::as_location. See the auth module.
  • Resilience — 429s retried honoring Retry-After; 5xx and transport failures retried with exponential backoff + jitter, idempotent methods only, so a POST is never silently duplicated.
  • Rate-limit awareness — live headroom from response headers via Ghl::rate_status.
  • Pagination — GoHighLevel’s cursor scheme handled for you and exposed as futures_util::Streams.
  • Config by env var or parameterGhl::from_env or Ghl::builder; explicit parameters always win.
  • Secret hygiene — tokens live in secrecy types and are redacted from all Debug output.
  • Forward-compatible types — unknown response fields are preserved in an extra map instead of failing deserialization.

§Generated services — every endpoint, typed

Enable the cargo feature named after an API module and its whole surface appears on the client, with generated parameter and body types:

ghl-sdk = { version = "0.5", features = ["invoices"] }
use ghl_sdk::services::invoices::ListInvoicesParams;

// Required query params are constructor arguments; optional ones are setters.
let params = ListInvoicesParams::new(&location_id, "location", "20", "0")
    .status("draft");

let page = ghl.invoices().list_invoices(&params).await?;   // typed response
println!("{:?} invoices", page.total);

Every generated method has the same predictable shape:

async fn <name>(&self, <path params…>, params: &XParams, body: &Dto) -> Result<Response>
  • Path parameters are positional &str arguments, in URL order.
  • Query parameters collapse into one XParams struct — required fields are new() arguments, optional ones are chainable setters. The argument is absent entirely when an endpoint takes no query parameters.
  • Bodies take the generated DTO from ghl-models.
  • Returns the response type the spec names (about 3 in 4 endpoints), else serde_json::Value.

§API v3

v3 is a parallel, newer surface (627 operations) reached through Ghl::v3, which sends Version: v3 for you:

let dup = ghl.v3().contacts().get_duplicate_contact(&params).await?;

It has modules v2 lacks — ad-publishing, social-planner, saas, chat-widget — and renames three others.

See services for the module list, and the API reference for the Rust method behind every endpoint.

§Hand-written helpers

Five modules also carry curated helpers that go beyond a 1:1 endpoint mapping — they unwrap response envelopes and turn cursor pagination into futures_util::Streams. They live on the same services, so both styles are available together:

ModuleHelpers
contactscreate, get, update, delete, list (streaming)
opportunitiespipelines, create, get, update, update_status, delete, search (streaming)
conversationssearch, messages, send_message
calendarslist, free_slots, create_appointment, get_appointment
locationsget, search

§Anything not generated

Ghl::request_raw reaches any endpoint — including all of API v3 — with the same auth, retry, and rate-limit handling:

let dup = ghl.request_raw(
    "GET", "/contacts/search/duplicate",
    &[("locationId".into(), loc), ("email".into(), email)],
    None,
    Some("v3"),          // v3 endpoints need their own Version header
).await?;

§Strict on send, lenient on receive

Request types keep the spec’s required fields non-Option, so a missing mandatory field is a compile error. Response types make everything optional: GoHighLevel sometimes omits fields its own spec marks required, and a strict response type would turn that into an unrecoverable deserialization failure.

§Authentication at a glance

SituationUse
Internal tool, one sub-accountAuth::private_integration (a pit-… token)
You ran OAuth yourselfAuth::access_token (used as-is, never refreshed)
Marketplace appAuth::oauth with a TokenStore — auto-refresh
Agency, many sub-accountsAuth::oauth with UserType::Company, then Ghl::as_location

GoHighLevel rotates the refresh token on every use, so a TokenStore implementation must persist durably — MemoryTokenStore loses the session on restart.

§Webhooks

With the webhooks feature, webhooks::verify checks HighLevel’s RSA-SHA256 signature and webhooks::WebhookEvent types the envelope its 58 event types share. Verify the raw bytes before parsing. See the webhooks module.

§Errors

Error distinguishes Error::Api (the API said no, with status and message), Error::RateLimited (retries exhausted), Error::Auth, Error::Transport, Error::Decode, and Error::Config. GoHighLevel returns message as either a string or an array of strings; both normalize into Error::Api’s message.

§Cargo features

Nothing is on by default. Each API module is its own feature so you compile only the surface you use — one module is a second or two, all 45 is closer to a minute.

FeatureEffect
<module> (45 of them, e.g. invoices, payments, products)That module’s generated services (v2 and v3) plus its DTOs
fullEvery generated service. Convenient, slow to compile
modelsJust the ghl-models re-export, no services
webhooksRSA signature verification and typed events (webhooks)

§Further reading

  • Usage guide — auth decision tree, per-module cookbook, pagination, rate limits, multi-location, v2 vs v3, troubleshooting
  • Full API reference — all 45 modules: every endpoint, struct, and enum value
  • ghl-mcp — MCP server built on this SDK, exposing GoHighLevel to AI agents

Not affiliated with HighLevel Inc. “GoHighLevel” and “HighLevel” are trademarks of their respective owners.

Re-exports§

pub use auth::Auth;
pub use auth::MemoryTokenStore;
pub use auth::OAuthConfig;
pub use auth::TokenSet;
pub use auth::TokenStore;
pub use auth::UserType;
pub use ghl_models as models;models

Modules§

auth
Authentication: Private Integration Tokens and OAuth 2.0 with automatic refresh.
calendars
Calendars — list calendars, find free slots, and book appointments.
contacts
Contacts — create, read, update, delete, and stream contact records.
conversations
Conversations — search threads, read messages, and send SMS/email.
locations
Locations (sub-accounts) — fetch one, or list those a credential can see.
opportunities
Opportunities — pipeline deals, their stages, and status transitions.
services
Generated typed services — one per GoHighLevel API module, each covering every operation that module exposes.
webhookswebhooks
Webhook signature verification and typed events.

Structs§

Ghl
Async client for the GoHighLevel API 2.0.
GhlBuilder
Builder for Ghl.
RateStatus
A snapshot of the most recently observed rate-limit headers.

Enums§

Error
All errors returned by this crate.

Constants§

API_VERSION
The Version header value used by most API 2.0 modules.
DEFAULT_BASE_URL
Production API base URL.

Type Aliases§

Result
Crate-wide result alias.