customerio.ts57 lines · main
1import 'server-only'
2
3export interface CustomerIOConfig {
4 siteId: string
5 apiKey: string
6}
7
8export class CustomerIOClient {
9 private baseUrl = 'https://track.customer.io/api/v1'
10 private auth: string
11
12 constructor(config: CustomerIOConfig) {
13 if (!config.siteId) throw new Error('CustomerIOClient: siteId is required')
14 if (!config.apiKey) throw new Error('CustomerIOClient: apiKey is required')
15
16 this.auth = btoa(`${config.siteId}:${config.apiKey}`)
17 }
18
19 private async makeRequest(
20 endpoint: string,
21 method: 'GET' | 'POST' | 'PUT',
22 body?: unknown
23 ): Promise<void> {
24 const response = await fetch(`${this.baseUrl}${endpoint}`, {
25 method,
26 headers: {
27 Authorization: `Basic ${this.auth}`,
28 'Content-Type': 'application/json',
29 },
30 body: body ? JSON.stringify(body) : undefined,
31 })
32
33 if (!response.ok) {
34 const errorText = await response.text()
35 throw new Error(`Customer.io API request failed: ${response.status} - ${errorText}`)
36 }
37 }
38
39 async identify(email: string, attributes: Record<string, unknown> = {}): Promise<void> {
40 await this.makeRequest(`/customers/${encodeURIComponent(email)}`, 'PUT', {
41 email,
42 ...attributes,
43 })
44 }
45
46 async track(
47 email: string,
48 event: string,
49 properties: Record<string, unknown> = {}
50 ): Promise<void> {
51 await this.makeRequest(`/customers/${encodeURIComponent(email)}/events`, 'POST', {
52 name: event,
53 data: properties,
54 timestamp: Math.floor(Date.now() / 1000),
55 })
56 }
57}