geodedo 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +414 -0
- package/dist/index.cjs +1077 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1157 -0
- package/dist/index.d.ts +1157 -0
- package/dist/index.js +1021 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
# GeoDedo TypeScript SDK
|
|
2
|
+
|
|
3
|
+
Official TypeScript/JavaScript SDK for the [GeoDedo API](https://geodedo-api.vercel.app) — a white-label GTM outreach platform covering contact search, email/LinkedIn/Instagram/SMS messaging, AI chat, and more.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install geodedo
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
> Requires Node.js 18+ (uses the built-in `fetch` API).
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { GeoDedo } from 'geodedo';
|
|
17
|
+
|
|
18
|
+
const client = new GeoDedo({ apiKey: 'gd_live_xxx' });
|
|
19
|
+
|
|
20
|
+
const contacts = await client.contacts.search({ titles: ['CEO'], locations: ['San Francisco'] });
|
|
21
|
+
console.log(contacts.data);
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Authentication
|
|
25
|
+
|
|
26
|
+
Get your API key at [geodedo-api.vercel.app](https://geodedo-api.vercel.app) — sign up, go to Dashboard, and copy your key.
|
|
27
|
+
|
|
28
|
+
Pass the key directly:
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
const client = new GeoDedo({ apiKey: 'gd_live_xxx' });
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Or set the `GEODEDO_API_KEY` environment variable and omit the option:
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
const client = new GeoDedo();
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Multi-User Support
|
|
41
|
+
|
|
42
|
+
If you are building a platform on top of GeoDedo and need to scope API calls to individual end-users, pass a `userId`:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
const client = new GeoDedo({
|
|
46
|
+
apiKey: 'gd_live_xxx',
|
|
47
|
+
userId: 'user_abc123',
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The `userId` is sent as an `X-User-Id` header on every request. You can also override it per-request:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
const contacts = await client.contacts.list(undefined, { userId: 'user_other' });
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Configuration
|
|
58
|
+
|
|
59
|
+
| Option | Type | Default | Description |
|
|
60
|
+
|--------|------|---------|-------------|
|
|
61
|
+
| `apiKey` | `string` | `process.env.GEODEDO_API_KEY` | API key for authentication |
|
|
62
|
+
| `userId` | `string` | — | Default user ID for user-scoped operations |
|
|
63
|
+
| `baseURL` | `string` | `https://geodedo-api.vercel.app` | API base URL |
|
|
64
|
+
| `maxRetries` | `number` | `2` | Max retries on 429/5xx and network errors |
|
|
65
|
+
| `timeout` | `number` | `60000` | Request timeout in milliseconds |
|
|
66
|
+
| `dangerouslyAllowBrowser` | `boolean` | `false` | Allow usage in browser environments |
|
|
67
|
+
|
|
68
|
+
## Resources
|
|
69
|
+
|
|
70
|
+
### Contacts
|
|
71
|
+
|
|
72
|
+
Search, enrich, import, and list contacts.
|
|
73
|
+
|
|
74
|
+
| Method | Signature | Credits | Description |
|
|
75
|
+
|--------|-----------|---------|-------------|
|
|
76
|
+
| `search` | `search(params: ContactSearchParams): Promise<Page<Contact>>` | 10 | Search contacts by ICP criteria |
|
|
77
|
+
| `enrich` | `enrich(params: ContactEnrichParams): Promise<Contact>` | 25 | Enrich a single contact |
|
|
78
|
+
| `importCsv` | `importCsv(params: ContactImportParams): Promise<ImportResult>` | 1 | Import a batch of contacts |
|
|
79
|
+
| `list` | `list(params?): Promise<Page<StoredContact>>` | 1 | List stored contacts (paginated) |
|
|
80
|
+
| `csvLists` | `csvLists(): Promise<CsvList[]>` | 1 | List all CSV import lists |
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
// Search for VP-level contacts in tech
|
|
84
|
+
const page = await client.contacts.search({
|
|
85
|
+
titles: ['VP Engineering', 'VP Product'],
|
|
86
|
+
locations: ['New York'],
|
|
87
|
+
employeeRanges: ['51-200'],
|
|
88
|
+
perPage: 10,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Enrich a contact by email
|
|
92
|
+
const contact = await client.contacts.enrich({ email: 'jane@example.com' });
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Sequences
|
|
96
|
+
|
|
97
|
+
Create and manage automated outreach sequences.
|
|
98
|
+
|
|
99
|
+
| Method | Signature | Credits | Description |
|
|
100
|
+
|--------|-----------|---------|-------------|
|
|
101
|
+
| `create` | `create(params: SequenceCreateParams): Promise<Sequence>` | 5 | Create a new sequence |
|
|
102
|
+
| `list` | `list(params?): Promise<Page<SequenceWithStats>>` | 1 | List all sequences (paginated) |
|
|
103
|
+
| `get` | `get(sequenceId: string): Promise<SequenceWithStats>` | 1 | Get a sequence by ID |
|
|
104
|
+
| `pause` | `pause(sequenceId: string): Promise<Sequence>` | 1 | Pause a running sequence |
|
|
105
|
+
| `resume` | `resume(sequenceId: string): Promise<Sequence>` | 1 | Resume a paused sequence |
|
|
106
|
+
| `stop` | `stop(sequenceId: string): Promise<Sequence>` | 1 | Stop (terminate) a sequence |
|
|
107
|
+
| `status` | `status(sequenceId: string): Promise<SequenceWithStats>` | 1 | Get sequence status with stats |
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
const seq = await client.sequences.create({
|
|
111
|
+
name: 'Q2 Outreach',
|
|
112
|
+
icp: 'SaaS founders, Series A, US-based',
|
|
113
|
+
channelType: 'email',
|
|
114
|
+
contactsPerDay: 50,
|
|
115
|
+
startHour: 9,
|
|
116
|
+
endHour: 17,
|
|
117
|
+
activeDays: ['mon', 'tue', 'wed', 'thu', 'fri'],
|
|
118
|
+
timezone: 'America/New_York',
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
const status = await client.sequences.status(seq.id);
|
|
122
|
+
console.log(status.stats); // { sent: 12, replied: 3 }
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Drafts
|
|
126
|
+
|
|
127
|
+
Generate AI-written outreach drafts, review, approve, and send them.
|
|
128
|
+
|
|
129
|
+
| Method | Signature | Credits | Description |
|
|
130
|
+
|--------|-----------|---------|-------------|
|
|
131
|
+
| `generate` | `generate(params: DraftGenerateParams): Promise<DraftBatchResult>` | 20 | Generate drafts for contacts |
|
|
132
|
+
| `list` | `list(params?): Promise<Page<Draft>>` | 1 | List drafts (paginated, filterable) |
|
|
133
|
+
| `update` | `update(draftId: string, params: DraftUpdateParams): Promise<Draft>` | 1 | Edit a draft's subject/body |
|
|
134
|
+
| `approve` | `approve(params: DraftApproveParams): Promise<DraftApproveResult>` | 1 | Approve drafts by ID |
|
|
135
|
+
| `send` | `send(params: DraftSendParams): Promise<DraftSendResult>` | 2 | Send approved drafts |
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
const batch = await client.drafts.generate({
|
|
139
|
+
contacts: [
|
|
140
|
+
{ fullName: 'Jane Smith', title: 'CTO', company: 'Acme', email: 'jane@acme.com' },
|
|
141
|
+
],
|
|
142
|
+
channel: 'email',
|
|
143
|
+
context: 'Introducing our developer tools platform',
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Review and send
|
|
147
|
+
await client.drafts.approve({ draftIds: batch.drafts.map(d => d.id) });
|
|
148
|
+
const result = await client.drafts.send({ draftIds: batch.drafts.map(d => d.id) });
|
|
149
|
+
console.log(`Sent: ${result.sent}, Failed: ${result.failed}`);
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Messages
|
|
153
|
+
|
|
154
|
+
Send messages directly across channels.
|
|
155
|
+
|
|
156
|
+
| Method | Signature | Credits | Description |
|
|
157
|
+
|--------|-----------|---------|-------------|
|
|
158
|
+
| `sendEmail` | `sendEmail(params: EmailSendParams): Promise<EmailResult>` | 2 | Send an email |
|
|
159
|
+
| `sendLinkedIn` | `sendLinkedIn(params: LinkedInSendParams): Promise<LinkedInResult>` | 10 | Send a LinkedIn message |
|
|
160
|
+
| `sendInstagram` | `sendInstagram(params: InstagramSendParams): Promise<InstagramResult>` | 10 | Send an Instagram DM |
|
|
161
|
+
| `sendSms` | `sendSms(params: SmsSendParams): Promise<SmsResult>` | 5 | Send an SMS |
|
|
162
|
+
| `inbox` | `inbox(channel: InboxChannel): Promise<Record<string, unknown>>` | 2 | Get unified inbox for a channel |
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
const result = await client.messages.sendEmail({
|
|
166
|
+
to: 'lead@example.com',
|
|
167
|
+
subject: 'Quick question',
|
|
168
|
+
body: 'Hi, I wanted to reach out about...',
|
|
169
|
+
provider: 'gmail',
|
|
170
|
+
});
|
|
171
|
+
console.log(result.sent); // true
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Chat
|
|
175
|
+
|
|
176
|
+
Interact with the GeoDedo AI assistant. Conversations persist across messages.
|
|
177
|
+
|
|
178
|
+
| Method | Signature | Credits | Description |
|
|
179
|
+
|--------|-----------|---------|-------------|
|
|
180
|
+
| `create` | `create(params: ChatCreateParams): Promise<ChatResponse>` | 5 | Send a message to the AI |
|
|
181
|
+
| `conversations.list` | `conversations.list(): Promise<Conversation[]>` | 1 | List all conversations |
|
|
182
|
+
| `conversations.get` | `conversations.get(id: string): Promise<ConversationMessage[]>` | 1 | Get messages in a conversation |
|
|
183
|
+
| `conversations.delete` | `conversations.delete(id: string): Promise<void>` | 0 | Delete a conversation |
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
// Start a conversation
|
|
187
|
+
const chat = await client.chat.create({ message: 'Find me SaaS CTOs in NYC' });
|
|
188
|
+
console.log(chat.response);
|
|
189
|
+
|
|
190
|
+
// Continue the conversation
|
|
191
|
+
const followUp = await client.chat.create({
|
|
192
|
+
message: 'Now create an email sequence for them',
|
|
193
|
+
conversationId: chat.conversationId,
|
|
194
|
+
});
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Channels
|
|
198
|
+
|
|
199
|
+
Connect and manage outreach channels (Gmail, LinkedIn, Instagram, AgentMail, SMS).
|
|
200
|
+
|
|
201
|
+
| Method | Signature | Credits | Description |
|
|
202
|
+
|--------|-----------|---------|-------------|
|
|
203
|
+
| `status` | `status(): Promise<ChannelStatus>` | 0 | Get status of all channels |
|
|
204
|
+
| `disconnect` | `disconnect(channel: ChannelName): Promise<void>` | 0 | Disconnect a channel |
|
|
205
|
+
| `gmail.connect` | `gmail.connect(): Promise<GmailConnectResult>` | 0 | Start Gmail OAuth flow |
|
|
206
|
+
| `linkedin.connect` | `linkedin.connect(params): Promise<ConnectionResult>` | 0 | Connect LinkedIn |
|
|
207
|
+
| `linkedin.checkpoint` | `linkedin.checkpoint(params): Promise<ConnectionResult>` | 0 | Resolve LinkedIn 2FA |
|
|
208
|
+
| `instagram.connect` | `instagram.connect(params): Promise<ConnectionResult>` | 0 | Connect Instagram |
|
|
209
|
+
| `instagram.checkpoint` | `instagram.checkpoint(params): Promise<ConnectionResult>` | 0 | Resolve Instagram 2FA |
|
|
210
|
+
| `agentmail.create` | `agentmail.create(params): Promise<AgentMailCreateResult>` | 0 | Create an AgentMail address |
|
|
211
|
+
| `sms.verify` | `sms.verify(params): Promise<SmsVerifyResult>` | 0 | Start SMS verification |
|
|
212
|
+
| `sms.confirm` | `sms.confirm(params): Promise<SmsVerifyResult>` | 0 | Confirm SMS with code |
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
// Check which channels are connected
|
|
216
|
+
const status = await client.channels.status();
|
|
217
|
+
console.log(status.gmail.connected); // true
|
|
218
|
+
|
|
219
|
+
// Connect Gmail (returns an OAuth URL)
|
|
220
|
+
const gmail = await client.channels.gmail.connect();
|
|
221
|
+
console.log(gmail.authUrl); // User visits this URL
|
|
222
|
+
|
|
223
|
+
// Create an AgentMail address
|
|
224
|
+
const mail = await client.channels.agentmail.create({ username: 'outreach' });
|
|
225
|
+
console.log(mail.email); // outreach@agentmail.geodedo.com
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Documents
|
|
229
|
+
|
|
230
|
+
Upload and manage documents for AI context.
|
|
231
|
+
|
|
232
|
+
| Method | Signature | Credits | Description |
|
|
233
|
+
|--------|-----------|---------|-------------|
|
|
234
|
+
| `upload` | `upload(params: DocumentUploadParams): Promise<Document>` | 1 | Upload a document |
|
|
235
|
+
| `list` | `list(params?): Promise<Page<Document>>` | 1 | List documents (paginated) |
|
|
236
|
+
| `delete` | `delete(documentId: string): Promise<void>` | 0 | Delete a document |
|
|
237
|
+
|
|
238
|
+
```ts
|
|
239
|
+
const doc = await client.documents.upload({
|
|
240
|
+
filename: 'product-overview.txt',
|
|
241
|
+
content: 'Our platform helps sales teams...',
|
|
242
|
+
});
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Recommendations
|
|
246
|
+
|
|
247
|
+
Get AI-powered recommendations for your outreach strategy.
|
|
248
|
+
|
|
249
|
+
| Method | Signature | Credits | Description |
|
|
250
|
+
|--------|-----------|---------|-------------|
|
|
251
|
+
| `icpAnalysis` | `icpAnalysis(): Promise<ICPAnalysis>` | 5 | Analyze ideal customer profile |
|
|
252
|
+
| `channel` | `channel(): Promise<ChannelRecommendation>` | 5 | Get channel recommendation |
|
|
253
|
+
| `sequenceStrategy` | `sequenceStrategy(): Promise<SequenceStrategy>` | 5 | Get sequence strategy advice |
|
|
254
|
+
|
|
255
|
+
```ts
|
|
256
|
+
const icp = await client.recommendations.icpAnalysis();
|
|
257
|
+
console.log(icp.recommendation);
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Billing
|
|
261
|
+
|
|
262
|
+
Check credit balance and track usage.
|
|
263
|
+
|
|
264
|
+
| Method | Signature | Credits | Description |
|
|
265
|
+
|--------|-----------|---------|-------------|
|
|
266
|
+
| `balance` | `balance(): Promise<CreditBalance>` | 0 | Get current credit balance |
|
|
267
|
+
| `usage` | `usage(params?: UsageListParams): Promise<Page<UsageEntry>>` | 0 | List usage entries (paginated) |
|
|
268
|
+
| `usageSummary` | `usageSummary(): Promise<UsageSummary>` | 0 | Get aggregated usage summary |
|
|
269
|
+
|
|
270
|
+
```ts
|
|
271
|
+
const balance = await client.billing.balance();
|
|
272
|
+
console.log(`${balance.credits_remaining} credits remaining`);
|
|
273
|
+
|
|
274
|
+
const summary = await client.billing.usageSummary();
|
|
275
|
+
for (const entry of summary.summary) {
|
|
276
|
+
console.log(`${entry.operation}: ${entry.total_calls} calls, ${entry.total_credits} credits`);
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Users
|
|
281
|
+
|
|
282
|
+
Register and manage user profiles.
|
|
283
|
+
|
|
284
|
+
| Method | Signature | Credits | Description |
|
|
285
|
+
|--------|-----------|---------|-------------|
|
|
286
|
+
| `register` | `register(params: UserRegisterParams): Promise<User>` | 0 | Register a new user |
|
|
287
|
+
| `me` | `me(): Promise<User>` | 0 | Get current user profile |
|
|
288
|
+
| `update` | `update(params: UserUpdateParams): Promise<User>` | 0 | Update user profile |
|
|
289
|
+
|
|
290
|
+
```ts
|
|
291
|
+
const user = await client.users.register({
|
|
292
|
+
externalUserId: 'usr_12345',
|
|
293
|
+
aboutMe: 'Sales leader at Acme Corp',
|
|
294
|
+
icp: 'SaaS CTOs at Series A startups',
|
|
295
|
+
cta: 'Book a 15-min demo call',
|
|
296
|
+
});
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## Pagination
|
|
300
|
+
|
|
301
|
+
List endpoints return a `Page<T>` object that supports async iteration:
|
|
302
|
+
|
|
303
|
+
### Async Iteration (recommended)
|
|
304
|
+
|
|
305
|
+
Automatically fetches all pages:
|
|
306
|
+
|
|
307
|
+
```ts
|
|
308
|
+
for await (const contact of await client.contacts.search({ titles: ['CEO'] })) {
|
|
309
|
+
console.log(contact.fullName);
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### Manual Page Access
|
|
314
|
+
|
|
315
|
+
```ts
|
|
316
|
+
const page = await client.contacts.list({ page: 1, perPage: 25 });
|
|
317
|
+
console.log(page.data); // items on this page
|
|
318
|
+
console.log(page.total); // total items across all pages
|
|
319
|
+
console.log(page.page); // current page number (1-indexed)
|
|
320
|
+
|
|
321
|
+
if (page.hasNextPage()) {
|
|
322
|
+
const next = await page.getNextPage();
|
|
323
|
+
console.log(next.data);
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
## Error Handling
|
|
328
|
+
|
|
329
|
+
All errors extend `GeoDedoError`. API errors include the HTTP status code and response body:
|
|
330
|
+
|
|
331
|
+
```ts
|
|
332
|
+
import {
|
|
333
|
+
GeoDedo,
|
|
334
|
+
APIError,
|
|
335
|
+
AuthenticationError,
|
|
336
|
+
InsufficientCreditsError,
|
|
337
|
+
RateLimitError,
|
|
338
|
+
ValidationError,
|
|
339
|
+
NotFoundError,
|
|
340
|
+
} from 'geodedo';
|
|
341
|
+
|
|
342
|
+
try {
|
|
343
|
+
await client.contacts.search({ titles: ['CEO'] });
|
|
344
|
+
} catch (err) {
|
|
345
|
+
if (err instanceof InsufficientCreditsError) {
|
|
346
|
+
console.log(`Need ${err.creditsRequired} credits, have ${err.creditsRemaining}`);
|
|
347
|
+
} else if (err instanceof AuthenticationError) {
|
|
348
|
+
console.log('Invalid API key');
|
|
349
|
+
} else if (err instanceof RateLimitError) {
|
|
350
|
+
console.log(`Rate limited — retry after ${err.retryAfter}s`);
|
|
351
|
+
} else if (err instanceof ValidationError) {
|
|
352
|
+
console.log('Invalid request:', err.message);
|
|
353
|
+
} else if (err instanceof NotFoundError) {
|
|
354
|
+
console.log('Resource not found');
|
|
355
|
+
} else if (err instanceof APIError) {
|
|
356
|
+
console.log(`API error ${err.status}: ${err.message}`);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### Error Classes
|
|
362
|
+
|
|
363
|
+
| Class | Status | Description |
|
|
364
|
+
|-------|--------|-------------|
|
|
365
|
+
| `GeoDedoError` | — | Base class for all SDK errors |
|
|
366
|
+
| `APIError` | any | Generic API error with status/body |
|
|
367
|
+
| `AuthenticationError` | 401 | Invalid or missing API key |
|
|
368
|
+
| `InsufficientCreditsError` | 402 | Not enough credits |
|
|
369
|
+
| `PermissionDeniedError` | 403 | Not authorized for this operation |
|
|
370
|
+
| `NotFoundError` | 404 | Resource not found |
|
|
371
|
+
| `ValidationError` | 422 | Invalid request parameters |
|
|
372
|
+
| `RateLimitError` | 429 | Rate limit exceeded (has `retryAfter`) |
|
|
373
|
+
| `InternalServerError` | 5xx | Server error |
|
|
374
|
+
| `APIConnectionError` | — | Network-level failure |
|
|
375
|
+
| `APITimeoutError` | — | Request timed out |
|
|
376
|
+
|
|
377
|
+
## Per-Request Options
|
|
378
|
+
|
|
379
|
+
Every method accepts an optional `RequestOptions` object as the last argument:
|
|
380
|
+
|
|
381
|
+
```ts
|
|
382
|
+
await client.contacts.search(
|
|
383
|
+
{ titles: ['CEO'] },
|
|
384
|
+
{
|
|
385
|
+
apiKey: 'gd_live_override', // Override API key
|
|
386
|
+
userId: 'user_override', // Override user ID
|
|
387
|
+
timeout: 30000, // Override timeout (ms)
|
|
388
|
+
headers: { 'X-Custom': '1' }, // Additional headers
|
|
389
|
+
signal: AbortSignal.timeout(5000), // Cancel with AbortSignal
|
|
390
|
+
},
|
|
391
|
+
);
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
## Retries
|
|
395
|
+
|
|
396
|
+
The SDK automatically retries on:
|
|
397
|
+
- HTTP 429 (rate limit), 409, 500, 502, 503, 504
|
|
398
|
+
- Network connection errors
|
|
399
|
+
- Request timeouts
|
|
400
|
+
|
|
401
|
+
Retries use exponential backoff with jitter (500ms base, 5s max). Configure with `maxRetries` (default: 2).
|
|
402
|
+
|
|
403
|
+
## Examples
|
|
404
|
+
|
|
405
|
+
See the [`examples/`](./examples) directory for complete working scripts:
|
|
406
|
+
|
|
407
|
+
- [`search-contacts.ts`](./examples/search-contacts.ts) — Search and enrich contacts
|
|
408
|
+
- [`create-sequence.ts`](./examples/create-sequence.ts) — Create and monitor a sequence
|
|
409
|
+
- [`send-email.ts`](./examples/send-email.ts) — Send an email and check balance
|
|
410
|
+
- [`ai-chat.ts`](./examples/ai-chat.ts) — Chat with the AI assistant
|
|
411
|
+
|
|
412
|
+
## License
|
|
413
|
+
|
|
414
|
+
MIT
|