1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
//! Unofficial async Rust SDK for the [GoHighLevel](https://www.gohighlevel.com)
//! (HighLevel) CRM API — covering **1,203 operations across 45 API modules** in
//! both API v2 and v3.
//!
//! ```no_run
//! use ghl_sdk::{contacts::CreateContact, Ghl};
//!
//! # async fn demo() -> Result<(), ghl_sdk::Error> {
//! // 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);
//! # Ok(()) }
//! ```
//!
//! # 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::Stream`]s.
//! - **Config by env var or parameter** — [`Ghl::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.
//!
//! # Three coverage tiers
//!
//! The guarantees differ by tier — know which one you're using:
//!
//! | Tier | Covers | What you get |
//! |---|---|---|
//! | **1.** Typed services (below) | 5 modules, 21 methods | Real Rust types, compile-time field checks, parsed responses, paginated `Stream`s |
//! | **2.** [`Ghl::request_raw`] + [`ghl-models`](https://docs.rs/ghl-models) DTOs | all 45 modules, 2,417 structs | Typed bodies you serialize; you supply the path |
//! | **3.** [`ghl-mcp`](https://crates.io/crates/ghl-mcp) meta-tools | all 1,203 operations | For AI agents; params validated, body passed through |
//!
//! ## Tier 1 — typed service modules
//!
//! | Module | Service | Methods |
//! |---|---|---|
//! | [`contacts`] | [`Ghl::contacts`] | `create`, `get`, `update`, `delete`, `list` (streaming) |
//! | [`opportunities`] | [`Ghl::opportunities`] | `pipelines`, `create`, `get`, `update`, `update_status`, `delete`, `search` (streaming) |
//! | [`conversations`] | [`Ghl::conversations`] | `search`, `messages`, `send_message` |
//! | [`calendars`] | [`Ghl::calendars`] | `list`, `free_slots`, `create_appointment`, `get_appointment` |
//! | [`locations`] | [`Ghl::locations`] | `get`, `search` |
//!
//! ## Tier 2 — every other endpoint
//!
//! [`Ghl::request_raw`] reaches any endpoint with the same auth, retry, and
//! rate-limit handling. Pair it with a generated DTO for a typed body:
//!
//! ```ignore
//! use ghl_models::v2::invoices::CreateInvoiceDto;
//!
//! let body = serde_json::to_value(CreateInvoiceDto {
//! alt_id: location_id.clone(),
//! alt_type: "location".into(), // the only legal value
//! name: "August retainer".into(),
//! currency: "USD".into(),
//! ..Default::default()
//! })?;
//!
//! let created = ghl.request_raw("POST", "/invoices/", &[], Some(&body), None).await?;
//! ```
//!
//! To call an **API v3** endpoint, pass the version override:
//!
//! ```ignore
//! let dup = ghl.request_raw(
//! "GET", "/contacts/search/duplicate",
//! &[("locationId".into(), loc), ("email".into(), email)],
//! None,
//! Some("v3"),
//! ).await?;
//! ```
//!
//! # Authentication at a glance
//!
//! | Situation | Use |
//! |---|---|
//! | Internal tool, one sub-account | [`Auth::private_integration`] (a `pit-…` token) |
//! | You ran OAuth yourself | [`Auth::access_token`] (used as-is, never refreshed) |
//! | Marketplace app | [`Auth::oauth`] with a [`TokenStore`] — auto-refresh |
//! | Agency, many sub-accounts | [`Auth::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.
//!
//! # 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
//!
//! | Feature | Default | Effect |
//! |---|---|---|
//! | `models` | no | Re-exports [`ghl-models`](https://docs.rs/ghl-models) as [`models`], giving typed DTOs for every API module |
//!
//! # Further reading
//!
//! - [Usage guide](https://github.com/Shahroz/ghl-rs/blob/main/docs/GUIDE.md) —
//! auth decision tree, per-module cookbook, pagination, rate limits,
//! multi-location, v2 vs v3, troubleshooting
//! - [Full API reference](https://github.com/Shahroz/ghl-rs/blob/main/docs/api/README.md)
//! — all 45 modules: every endpoint, struct, and enum value
//! - [`ghl-mcp`](https://crates.io/crates/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.*
/// Generated data models (DTOs) for the whole GoHighLevel API, re-exported from
/// the [`ghl-models`](https://docs.rs/ghl-models) crate.
///
/// Enable the `models` feature, then pick the API modules you need through
/// `ghl-models`' own per-module features:
///
/// ```toml
/// ghl-sdk = { version = "0.3", features = ["models"] }
/// ghl-models = { version = "0.3", features = ["invoices", "payments"] }
/// ```
///
/// Types live under `models::v2::*` and `models::v3::*`.
pub use ghl_models as models;
pub use ;
pub use ;
pub use ;