interface SalesBldrConfig { apiUrl: string; apiKey: string; } interface QuoteItem { id: string; category?: object; cost?: number; mpn?: string; markup?: number; deliveryDate?: string; discount?: number; unit?: string; term?: string; name: string; price?: number; quantity: number; shortDescription?: string; } interface Quote { id: string; title: string; number: string; status: string; createdAt: string; sentAt?: string; expiresAt?: string; approvedAt?: string; company?: { id: string; name: string; externalIdentifier?: string; }; contact?: object; owner?: object; items?: QuoteItem[]; opportunity?: { id: string; name: string; description?: string; }; } interface QuoteSearchResponse { results: Quote[]; total: number; filters?: any[]; sortOptions?: any[]; } export class SalesBldrClient { private config: SalesBldrConfig; constructor(config?: SalesBldrConfig) { this.config = config || { apiUrl: process.env.SALESBLDR_API_URL || '', apiKey: process.env.SALESBLDR_API_KEY || '' }; } private ensureConfig() { if (!this.config.apiUrl || !this.config.apiKey) { throw new Error('SalesBldr API URL and API Key are required'); } } private async request( endpoint: string, options: RequestInit = {} ): Promise { this.ensureConfig(); const url = `${this.config.apiUrl}${endpoint}`; const headers: HeadersInit = { 'api-key': this.config.apiKey, 'Content-Type': 'application/json', ...options.headers, }; const response = await fetch(url, { ...options, headers, }); if (!response.ok) { const errorText = await response.text(); throw new Error( `SalesBldr API error: ${response.status} ${response.statusText} - ${errorText}` ); } return response.json(); } async getQuotes(params?: { sort?: string; filters?: string; query?: string; size?: number; from?: number; }): Promise { const queryParams = new URLSearchParams(); if (params?.sort) queryParams.append('sort', params.sort); if (params?.filters) queryParams.append('filters', params.filters); if (params?.query) queryParams.append('query', params.query); if (params?.size !== undefined) queryParams.append('size', params.size.toString()); if (params?.from !== undefined) queryParams.append('from', params.from.toString()); const endpoint = `/public-api/quote${queryParams.toString() ? `?${queryParams.toString()}` : ''}`; return this.request(endpoint); } async getOpenQuotes(size: number = 10): Promise { return this.getQuotes({ filters: 'status:sent|draft', sort: '-createdAt', size }); } async getApprovedQuotes(size: number = 10): Promise { const endpoint = `/public-api/quote/approved`; return this.request(endpoint); } async getOpportunities(params?: { sort?: string; filters?: string; query?: string; size?: number; from?: number; }): Promise { const queryParams = new URLSearchParams(); if (params?.sort) queryParams.append('sort', params.sort); if (params?.filters) queryParams.append('filters', params.filters); if (params?.query) queryParams.append('query', params.query); if (params?.size !== undefined) queryParams.append('size', params.size.toString()); if (params?.from !== undefined) queryParams.append('from', params.from.toString()); const endpoint = `/public-api/opportunity${queryParams.toString() ? `?${queryParams.toString()}` : ''}`; return this.request(endpoint); } async getProducts(params?: { includeBundles?: boolean; sort?: string; filters?: string; query?: string; size?: number; from?: number; }): Promise { const queryParams = new URLSearchParams(); if (params?.includeBundles !== undefined) queryParams.append('includeBundles', params.includeBundles.toString()); if (params?.sort) queryParams.append('sort', params.sort); if (params?.filters) queryParams.append('filters', params.filters); if (params?.query) queryParams.append('query', params.query); if (params?.size !== undefined) queryParams.append('size', params.size.toString()); if (params?.from !== undefined) queryParams.append('from', params.from.toString()); const endpoint = `/public-api/product${queryParams.toString() ? `?${queryParams.toString()}` : ''}`; return this.request(endpoint); } async getCompanies(params?: { sort?: string; filters?: string; query?: string; size?: number; from?: number; }): Promise { const queryParams = new URLSearchParams(); if (params?.sort) queryParams.append('sort', params.sort); if (params?.filters) queryParams.append('filters', params.filters); if (params?.query) queryParams.append('query', params.query); if (params?.size !== undefined) queryParams.append('size', params.size.toString()); if (params?.from !== undefined) queryParams.append('from', params.from.toString()); const endpoint = `/public-api/company${queryParams.toString() ? `?${queryParams.toString()}` : ''}`; return this.request(endpoint); } async getContacts(params?: { sort?: string; filters?: string; query?: string; size?: number; from?: number; }): Promise { const queryParams = new URLSearchParams(); if (params?.sort) queryParams.append('sort', params.sort); if (params?.filters) queryParams.append('filters', params.filters); if (params?.query) queryParams.append('query', params.query); if (params?.size !== undefined) queryParams.append('size', params.size.toString()); if (params?.from !== undefined) queryParams.append('from', params.from.toString()); const endpoint = `/public-api/contact${queryParams.toString() ? `?${queryParams.toString()}` : ''}`; return this.request(endpoint); } } export const salesBldrClient = new SalesBldrClient();