cre-sync/lib/ghl/client.ts
BusyBee3333 4e6467ffb0 Add CRESync CRM application with Setup page
- Build complete Next.js CRM for commercial real estate
- Add authentication with JWT sessions and role-based access
- Add GoHighLevel API integration for contacts, conversations, opportunities
- Add AI-powered Control Center with tool calling
- Add Setup page with onboarding checklist (/setup)
- Add sidebar navigation with Setup menu item
- Fix type errors in onboarding API, GHL services, and control center tools
- Add Prisma schema with SQLite for local development
- Add UI components with clay morphism design system

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 17:30:55 -05:00

84 lines
2.1 KiB
TypeScript

import { GHLError } from './errors';
export interface GHLClientConfig {
accessToken: string;
locationId: string;
version?: string;
}
export class GHLClient {
// v2 API endpoint for OAuth/Private Integration tokens
private baseUrl = 'https://services.leadconnectorhq.com';
private accessToken: string;
private locationId: string;
private version: string;
constructor(config: GHLClientConfig) {
this.accessToken = config.accessToken;
this.locationId = config.locationId;
// v2 API version - use latest stable version
this.version = config.version || '2021-07-28';
}
get locationID() {
return this.locationId;
}
async request<T>(
endpoint: string,
options: RequestInit = {}
): Promise<T> {
const url = `${this.baseUrl}${endpoint}`;
const response = await fetch(url, {
...options,
headers: {
'Authorization': `Bearer ${this.accessToken}`,
'Version': this.version,
'Content-Type': 'application/json',
'Accept': 'application/json',
...options.headers,
},
});
if (!response.ok) {
const errorBody = await response.text();
throw new GHLError(
response.status,
`GHL API Error: ${response.statusText}`,
errorBody
);
}
// Handle empty responses
const text = await response.text();
if (!text) return {} as T;
return JSON.parse(text) as T;
}
async get<T>(endpoint: string, params?: Record<string, string>): Promise<T> {
const searchParams = new URLSearchParams(params);
const url = params ? `${endpoint}?${searchParams}` : endpoint;
return this.request<T>(url, { method: 'GET' });
}
async post<T>(endpoint: string, body?: unknown): Promise<T> {
return this.request<T>(endpoint, {
method: 'POST',
body: body ? JSON.stringify(body) : undefined,
});
}
async put<T>(endpoint: string, body?: unknown): Promise<T> {
return this.request<T>(endpoint, {
method: 'PUT',
body: body ? JSON.stringify(body) : undefined,
});
}
async delete<T>(endpoint: string): Promise<T> {
return this.request<T>(endpoint, { method: 'DELETE' });
}
}