hubspot.ts93 lines · main
1import 'server-only'
2
3interface HubSpotField {
4 objectTypeId: string
5 name: string
6 value: string
7}
8
9interface HubSpotSubmission {
10 fields: HubSpotField[]
11 context?: {
12 pageUri?: string
13 pageName?: string
14 }
15 legalConsentOptions?: {
16 consent: {
17 consentToProcess: boolean
18 text: string
19 }
20 }
21}
22
23export interface HubSpotConfig {
24 portalId: string
25 formGuid: string
26}
27
28export class HubSpotClient {
29 private portalId: string
30 private formGuid: string
31
32 constructor(config: HubSpotConfig) {
33 if (!config.portalId) throw new Error('HubSpotClient: portalId is required')
34 if (!config.formGuid) throw new Error('HubSpotClient: formGuid is required')
35
36 this.portalId = config.portalId
37 this.formGuid = config.formGuid
38 }
39
40 async submitForm(
41 fields: Record<string, string>,
42 options?: {
43 pageUri?: string
44 pageName?: string
45 consent?: string
46 }
47 ): Promise<void> {
48 const hubspotFields: HubSpotField[] = Object.entries(fields).map(([name, value]) => ({
49 objectTypeId: '0-1',
50 name,
51 value,
52 }))
53
54 const body: HubSpotSubmission = {
55 fields: hubspotFields,
56 }
57
58 if (options?.pageUri || options?.pageName) {
59 body.context = {
60 pageUri: options.pageUri,
61 pageName: options.pageName,
62 }
63 }
64
65 if (options?.consent) {
66 body.legalConsentOptions = {
67 consent: {
68 consentToProcess: true,
69 text: options.consent,
70 },
71 }
72 }
73
74 // portalId comes from env; formGuid is validated at the zod layer to a
75 // UUID-like shape, but encodeURIComponent keeps this safe even if the
76 // client is constructed from an untrusted source.
77 const response = await fetch(
78 `https://api.hsforms.com/submissions/v3/integration/submit/${encodeURIComponent(
79 this.portalId
80 )}/${encodeURIComponent(this.formGuid)}`,
81 {
82 method: 'POST',
83 headers: { 'Content-Type': 'application/json' },
84 body: JSON.stringify(body),
85 }
86 )
87
88 if (!response.ok) {
89 const errorText = await response.text()
90 throw new Error(`HubSpot form submission failed: ${response.status} - ${errorText}`)
91 }
92 }
93}