- 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>
84 lines
2.1 KiB
TypeScript
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' });
|
|
}
|
|
}
|