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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
//! Unofficial async Rust SDK for the [GoHighLevel](https://www.gohighlevel.com)
//! (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.
//!
//! ```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.
//!
//! # 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:
//!
//! ```toml
//! ghl-sdk = { version = "0.5", features = ["invoices"] }
//! ```
//!
//! ```ignore
//! 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(¶ms).await?; // typed response
//! println!("{:?} invoices", page.total);
//! ```
//!
//! Every generated method has the same predictable shape:
//!
//! ```text
//! 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`](https://docs.rs/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:
//!
//! ```ignore
//! let dup = ghl.v3().contacts().get_duplicate_contact(¶ms).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](https://github.com/Shahroz/ghl-rs/blob/main/docs/api/README.md)
//! 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::Stream`]s. They live on the same services, so both styles are
//! available together:
//!
//! | Module | Helpers |
//! |---|---|
//! | [`contacts`] | `create`, `get`, `update`, `delete`, `list` (streaming) |
//! | [`opportunities`] | `pipelines`, `create`, `get`, `update`, `update_status`, `delete`, `search` (streaming) |
//! | [`conversations`] | `search`, `messages`, `send_message` |
//! | [`calendars`] | `list`, `free_slots`, `create_appointment`, `get_appointment` |
//! | [`locations`] | `get`, `search` |
//!
//! ## Anything not generated
//!
//! [`Ghl::request_raw`] reaches any endpoint — including all of API v3 — with
//! the same auth, retry, and rate-limit handling:
//!
//! ```ignore
//! 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
//!
//! | 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.
//!
//! # 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 41 is closer to
//! a minute.
//!
//! | Feature | Effect |
//! |---|---|
//! | `<module>` (45 of them, e.g. `invoices`, `payments`, `products`) | That module's generated services (v2 and v3) plus its DTOs |
//! | `full` | Every generated service. Convenient, slow to compile |
//! | `models` | Just the [`ghl-models`](https://docs.rs/ghl-models) re-export, no services |
//! | `webhooks` | RSA signature verification and typed events ([`webhooks`]) |
//!
//! # 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;
// Module docs live in webhooks.rs; a second doc comment here would shadow the
// intra-doc link resolution inside it.
pub use ;
pub use ;
pub use ;