> ## Documentation Index
> Fetch the complete documentation index at: https://docs.myfundingmachine.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Ghl sdk v3 raw fetch audit

# GHL SDK v3 Raw Fetch Audit

FUND-1772 migrates high-confidence GHL traffic to `@gohighlevel/api-client@3.0.0` wrappers and documents the raw calls that remain intentional.

## SDK upgrade checklist

When bumping `@gohighlevel/api-client`, verify:

* `bunx tsc --noEmit` still resolves the SaaS DTO deep type import in `lib/ghl-sdk.ts` (`@gohighlevel/api-client/dist/lib/code/saas-api/models/saas-api`). The SDK does not re-export these types from its package root; a build-tool or output-directory change can break the path.

Use this comment pattern next to any new exception:

```ts theme={null}
// GHL RAW FETCH EXCEPTION (FUND-1772): <short reason SDK v3 is missing, unsafe, or disallowed here>.
```

## Migrated in this pass

* `app/api/ghl/send-sms/route.ts` and `app/api/ghl/send-email/route.ts`: conversations send now uses `sendGHLMessage`.
* `app/api/ghl/custom-fields/route.ts`: custom fields now use `getGHLCustomFields`.
* `app/api/ghl/marketplace-charge/route.ts` and `lib/billing.ts`: marketplace charge and has-funds calls now use SDK wrappers.
* `lib/ghl.ts`: products and product prices now use SDK wrappers while preserving exact-name matching.
* `lib/ghl-location-resources.ts`: workflow and pipeline lookups for existing prospecting locations now use SDK-backed helpers.
* `lib/ghl-sdk.ts`: contact upsert now uses `client.contacts.upsertContact`.

## Date-shape requirements for follow-up migrations

Keep these shapes explicit in any PR 2 migration snippet that moves form, payment, or calendar reads to the SDK. GHL accepts multiple date-looking values but applies date-range filtering differently by endpoint.

```ts theme={null}
const isoDay = (timeMs: number) => format(new Date(timeMs), 'yyyy-MM-dd');
```

* Forms submissions must pass day-only strings in `YYYY-MM-DD` format, e.g. `startAt: isoDay(startMs)` and `endAt: isoDay(endMs)`. Do not pass raw `Date#toISOString()` timestamps.
* Transactions and orders must also pass day-only strings for `startAt` and `endAt` via `isoDay(...)`, matching the current `getAllGHLOrders` call shape in `app/api/admin-tracking/analytics/route.ts`.
* Calendar events must keep millisecond epoch values for `startTime` and `endTime`, matching `getGHLCalendarEvents` and the current admin analytics implementation. Do not convert calendar event ranges to `YYYY-MM-DD` day strings or ISO timestamps.

## v3 breaking-change hardening

* `monetaryValue` (opportunities): v3 changed the `upsertOpportunity` body's `monetaryValue` from a number to an object, and read responses are not guaranteed to stay a primitive number across endpoints. `lib/ghl-monetary.ts` (`normalizeMonetaryValue` / `monetaryValueOrZero`) coerces number | numeric-string | `{ amount }`-style object to a finite number. It is applied at the read source in both `searchGHLOpportunities` and `searchGHLOpportunitiesCursor` (`lib/ghl-sdk.ts`) and in the opportunity-value arithmetic in `components/contact/ContactPageOverlays.tsx`. `parseNumericValue` in `lib/operatorInvoices.ts` and the `typeof === 'number'` guard in `app/api/ghl/crm-activity/route.ts` already tolerate non-number inputs. Covered by `tests/ghlMonetaryValue.test.ts`.

## v3 net-new field adoption

* Opportunities `lostReasonId` + `externalObjectId`: v3 returns both on opportunity responses and accepts `lostReasonId` on the update body. `GHLOpportunity` (`lib/ghl.ts`) now types `externalObjectId` (`lostReasonId` was already present), so both surface through the read mappings in `searchGHLOpportunitiesCursor` and `searchGHLOpportunities` (which spread the raw opportunity). `updateGHLOpportunity` (`lib/ghl-sdk.ts`) accepts an optional `lostReasonId` that rides the existing `as any` cast into the update body (the SDK's `UpdateOpportunityDto` does not yet type it).

## Intentional raw exceptions

* Convex V8 runtime files such as `convex/lib/ghlApi.ts`, `convex/underwriting.ts`, `convex/creditReports.ts`, `convex/leadNotifications.ts`, `convex/prospecting/reportsEmail.ts`, and `convex/ghlInstallations.ts` must not import the SDK because it pulls Node-only dependencies.
* Convex seed and migration utilities such as `convex/seedDemoData.ts`, `convex/migrations/stageMapping.ts`, and `convex/migrations/creditReportMigration.ts` are one-off or operational scripts; leave them raw unless they are moved behind Node-runtime helpers.
* OAuth/session plumbing in `lib/ghl-auth.ts` and `convex/lib/ghlApi.ts` keeps raw token calls to preserve the app's existing refresh, persistence, and location-token exchange behavior.
* Legacy migration/import tooling such as `lib/zoho-migration/loader.ts` remains raw because it is not new app traffic and has custom reconciliation behavior.
* Specialized endpoints without safe SDK coverage remain raw, including live-chat typing, call recording upload/attachment, and selected chat/webhook fallbacks.

## Retired exceptions

* Advanced opportunity POST search (`POST /opportunities/search`): now routed through the SDK's `client.opportunities.searchOpportunitiesAdvanced` in `searchGHLOpportunities` (`lib/ghl-sdk.ts`, re-exported from `lib/ghl.ts`). The SDK's generated `OpportunitySearchBodyDTO` omits `filters`/`sort`/`page`, so the hand-built body is forwarded via a cast (the SDK passes the body to axios verbatim). `User-Agent: curl/8.7.1` is passed via the call's `options.headers` since the SDK does not set it. Rate-limit handling uses the SDK-aware `withGHLRateLimit` in `lib/ghl-sdk.ts` (the `lib/ghl-auth.ts` variant only catches `GHLRateLimitError`, not axios 429s). Returned opportunities now apply `normalizeMonetaryValue` at the read source (same as `searchGHLOpportunitiesCursor`) so v3 object/string shapes are coerced before callers consume them.
