@sendly/node 3.12.2 → 3.13.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/dist/index.d.mts +845 -1
- package/dist/index.d.ts +845 -1
- package/dist/index.js +759 -0
- package/dist/index.mjs +759 -0
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1460,6 +1460,65 @@ var AccountResource = class {
|
|
|
1460
1460
|
path: `/account/keys/${encodeURIComponent(id)}`
|
|
1461
1461
|
});
|
|
1462
1462
|
}
|
|
1463
|
+
/**
|
|
1464
|
+
* Rename an API key
|
|
1465
|
+
*
|
|
1466
|
+
* @param id - API key ID
|
|
1467
|
+
* @param name - New name for the API key
|
|
1468
|
+
* @returns Updated API key
|
|
1469
|
+
*
|
|
1470
|
+
* @example
|
|
1471
|
+
* ```typescript
|
|
1472
|
+
* const key = await sendly.account.renameApiKey('key_xxx', 'Production Key');
|
|
1473
|
+
* console.log(`Renamed to: ${key.name}`);
|
|
1474
|
+
* ```
|
|
1475
|
+
*/
|
|
1476
|
+
async renameApiKey(id, name) {
|
|
1477
|
+
if (!id) {
|
|
1478
|
+
throw new Error("API key ID is required");
|
|
1479
|
+
}
|
|
1480
|
+
if (!name) {
|
|
1481
|
+
throw new Error("New name is required");
|
|
1482
|
+
}
|
|
1483
|
+
const key = await this.http.request({
|
|
1484
|
+
method: "PATCH",
|
|
1485
|
+
path: `/account/keys/${encodeURIComponent(id)}/rename`,
|
|
1486
|
+
body: { name }
|
|
1487
|
+
});
|
|
1488
|
+
return key;
|
|
1489
|
+
}
|
|
1490
|
+
/**
|
|
1491
|
+
* Rotate an API key
|
|
1492
|
+
*
|
|
1493
|
+
* Creates a new key while optionally keeping the old one active for a grace period.
|
|
1494
|
+
*
|
|
1495
|
+
* @param id - API key ID to rotate
|
|
1496
|
+
* @param options - Rotation options
|
|
1497
|
+
* @returns New API key with the full key value
|
|
1498
|
+
*
|
|
1499
|
+
* @example
|
|
1500
|
+
* ```typescript
|
|
1501
|
+
* // Rotate immediately (old key stops working instantly)
|
|
1502
|
+
* const { newKey, key } = await sendly.account.rotateApiKey('key_xxx');
|
|
1503
|
+
* console.log(`New key: ${key}`); // Save this!
|
|
1504
|
+
*
|
|
1505
|
+
* // Rotate with 24-hour grace period (both keys work for 24h)
|
|
1506
|
+
* const { newKey, key } = await sendly.account.rotateApiKey('key_xxx', {
|
|
1507
|
+
* gracePeriodHours: 24
|
|
1508
|
+
* });
|
|
1509
|
+
* ```
|
|
1510
|
+
*/
|
|
1511
|
+
async rotateApiKey(id, options) {
|
|
1512
|
+
if (!id) {
|
|
1513
|
+
throw new Error("API key ID is required");
|
|
1514
|
+
}
|
|
1515
|
+
const response = await this.http.request({
|
|
1516
|
+
method: "POST",
|
|
1517
|
+
path: `/account/keys/${encodeURIComponent(id)}/rotate`,
|
|
1518
|
+
body: options?.gracePeriodHours ? { gracePeriodHours: options.gracePeriodHours } : {}
|
|
1519
|
+
});
|
|
1520
|
+
return response;
|
|
1521
|
+
}
|
|
1463
1522
|
};
|
|
1464
1523
|
|
|
1465
1524
|
// src/resources/verify.ts
|
|
@@ -1910,6 +1969,37 @@ var TemplatesResource = class {
|
|
|
1910
1969
|
path: `/templates/${id}`
|
|
1911
1970
|
});
|
|
1912
1971
|
}
|
|
1972
|
+
/**
|
|
1973
|
+
* Clone a template
|
|
1974
|
+
*
|
|
1975
|
+
* Creates a copy of an existing template (including presets).
|
|
1976
|
+
*
|
|
1977
|
+
* @param id - Template ID to clone
|
|
1978
|
+
* @param options - Optional clone options
|
|
1979
|
+
* @returns The cloned template (as draft)
|
|
1980
|
+
*
|
|
1981
|
+
* @example
|
|
1982
|
+
* ```typescript
|
|
1983
|
+
* // Clone a preset template
|
|
1984
|
+
* const myOtp = await sendly.templates.clone('tpl_preset_otp', {
|
|
1985
|
+
* name: 'My Custom OTP'
|
|
1986
|
+
* });
|
|
1987
|
+
*
|
|
1988
|
+
* // Modify and publish
|
|
1989
|
+
* await sendly.templates.update(myOtp.id, {
|
|
1990
|
+
* text: 'Your {{app_name}} code: {{code}}. Expires in 5 min.'
|
|
1991
|
+
* });
|
|
1992
|
+
* await sendly.templates.publish(myOtp.id);
|
|
1993
|
+
* ```
|
|
1994
|
+
*/
|
|
1995
|
+
async clone(id, options) {
|
|
1996
|
+
const response = await this.http.request({
|
|
1997
|
+
method: "POST",
|
|
1998
|
+
path: `/templates/${id}/clone`,
|
|
1999
|
+
body: options?.name ? { name: options.name } : {}
|
|
2000
|
+
});
|
|
2001
|
+
return this.transformTemplate(response);
|
|
2002
|
+
}
|
|
1913
2003
|
transformTemplate(t) {
|
|
1914
2004
|
return {
|
|
1915
2005
|
id: t.id,
|
|
@@ -1931,6 +2021,632 @@ var TemplatesResource = class {
|
|
|
1931
2021
|
}
|
|
1932
2022
|
};
|
|
1933
2023
|
|
|
2024
|
+
// src/resources/campaigns.ts
|
|
2025
|
+
var CampaignsResource = class {
|
|
2026
|
+
http;
|
|
2027
|
+
constructor(http) {
|
|
2028
|
+
this.http = http;
|
|
2029
|
+
}
|
|
2030
|
+
/**
|
|
2031
|
+
* Create a new campaign
|
|
2032
|
+
*
|
|
2033
|
+
* @param request - Campaign details
|
|
2034
|
+
* @returns The created campaign (as draft)
|
|
2035
|
+
*
|
|
2036
|
+
* @example
|
|
2037
|
+
* ```typescript
|
|
2038
|
+
* const campaign = await sendly.campaigns.create({
|
|
2039
|
+
* name: 'Black Friday Sale',
|
|
2040
|
+
* text: 'Hi {{name}}! 50% off everything today only. Shop now!',
|
|
2041
|
+
* contactListIds: ['lst_customers', 'lst_subscribers']
|
|
2042
|
+
* });
|
|
2043
|
+
* ```
|
|
2044
|
+
*/
|
|
2045
|
+
async create(request) {
|
|
2046
|
+
const response = await this.http.request({
|
|
2047
|
+
method: "POST",
|
|
2048
|
+
path: "/campaigns",
|
|
2049
|
+
body: {
|
|
2050
|
+
name: request.name,
|
|
2051
|
+
text: request.text,
|
|
2052
|
+
templateId: request.templateId,
|
|
2053
|
+
contactListIds: request.contactListIds
|
|
2054
|
+
}
|
|
2055
|
+
});
|
|
2056
|
+
return this.transformCampaign(response);
|
|
2057
|
+
}
|
|
2058
|
+
/**
|
|
2059
|
+
* List campaigns with optional filtering
|
|
2060
|
+
*
|
|
2061
|
+
* @param options - Filter and pagination options
|
|
2062
|
+
* @returns List of campaigns
|
|
2063
|
+
*
|
|
2064
|
+
* @example
|
|
2065
|
+
* ```typescript
|
|
2066
|
+
* // List all campaigns
|
|
2067
|
+
* const { campaigns } = await sendly.campaigns.list();
|
|
2068
|
+
*
|
|
2069
|
+
* // List only scheduled campaigns
|
|
2070
|
+
* const { campaigns } = await sendly.campaigns.list({ status: 'scheduled' });
|
|
2071
|
+
*
|
|
2072
|
+
* // Paginate
|
|
2073
|
+
* const { campaigns, total } = await sendly.campaigns.list({ limit: 10, offset: 20 });
|
|
2074
|
+
* ```
|
|
2075
|
+
*/
|
|
2076
|
+
async list(options = {}) {
|
|
2077
|
+
const params = new URLSearchParams();
|
|
2078
|
+
if (options.limit) params.set("limit", String(options.limit));
|
|
2079
|
+
if (options.offset) params.set("offset", String(options.offset));
|
|
2080
|
+
if (options.status) params.set("status", options.status);
|
|
2081
|
+
const queryString = params.toString();
|
|
2082
|
+
const response = await this.http.request({
|
|
2083
|
+
method: "GET",
|
|
2084
|
+
path: `/campaigns${queryString ? `?${queryString}` : ""}`
|
|
2085
|
+
});
|
|
2086
|
+
return {
|
|
2087
|
+
campaigns: response.campaigns.map((c) => this.transformCampaign(c)),
|
|
2088
|
+
total: response.total,
|
|
2089
|
+
limit: response.limit,
|
|
2090
|
+
offset: response.offset
|
|
2091
|
+
};
|
|
2092
|
+
}
|
|
2093
|
+
/**
|
|
2094
|
+
* Get a campaign by ID
|
|
2095
|
+
*
|
|
2096
|
+
* @param id - Campaign ID
|
|
2097
|
+
* @returns The campaign
|
|
2098
|
+
*
|
|
2099
|
+
* @example
|
|
2100
|
+
* ```typescript
|
|
2101
|
+
* const campaign = await sendly.campaigns.get('cmp_xxx');
|
|
2102
|
+
* console.log(`Status: ${campaign.status}`);
|
|
2103
|
+
* console.log(`Delivered: ${campaign.deliveredCount}/${campaign.recipientCount}`);
|
|
2104
|
+
* ```
|
|
2105
|
+
*/
|
|
2106
|
+
async get(id) {
|
|
2107
|
+
const response = await this.http.request({
|
|
2108
|
+
method: "GET",
|
|
2109
|
+
path: `/campaigns/${id}`
|
|
2110
|
+
});
|
|
2111
|
+
return this.transformCampaign(response);
|
|
2112
|
+
}
|
|
2113
|
+
/**
|
|
2114
|
+
* Update a campaign (draft or scheduled only)
|
|
2115
|
+
*
|
|
2116
|
+
* @param id - Campaign ID
|
|
2117
|
+
* @param request - Fields to update
|
|
2118
|
+
* @returns The updated campaign
|
|
2119
|
+
*
|
|
2120
|
+
* @example
|
|
2121
|
+
* ```typescript
|
|
2122
|
+
* const campaign = await sendly.campaigns.update('cmp_xxx', {
|
|
2123
|
+
* name: 'Updated Campaign Name',
|
|
2124
|
+
* text: 'New message text with {{variable}}'
|
|
2125
|
+
* });
|
|
2126
|
+
* ```
|
|
2127
|
+
*/
|
|
2128
|
+
async update(id, request) {
|
|
2129
|
+
const response = await this.http.request({
|
|
2130
|
+
method: "PATCH",
|
|
2131
|
+
path: `/campaigns/${id}`,
|
|
2132
|
+
body: {
|
|
2133
|
+
...request.name && { name: request.name },
|
|
2134
|
+
...request.text && { text: request.text },
|
|
2135
|
+
...request.templateId !== void 0 && {
|
|
2136
|
+
template_id: request.templateId
|
|
2137
|
+
},
|
|
2138
|
+
...request.contactListIds && {
|
|
2139
|
+
contact_list_ids: request.contactListIds
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
});
|
|
2143
|
+
return this.transformCampaign(response);
|
|
2144
|
+
}
|
|
2145
|
+
/**
|
|
2146
|
+
* Delete a campaign
|
|
2147
|
+
*
|
|
2148
|
+
* Only draft and cancelled campaigns can be deleted.
|
|
2149
|
+
*
|
|
2150
|
+
* @param id - Campaign ID
|
|
2151
|
+
*
|
|
2152
|
+
* @example
|
|
2153
|
+
* ```typescript
|
|
2154
|
+
* await sendly.campaigns.delete('cmp_xxx');
|
|
2155
|
+
* ```
|
|
2156
|
+
*/
|
|
2157
|
+
async delete(id) {
|
|
2158
|
+
await this.http.request({
|
|
2159
|
+
method: "DELETE",
|
|
2160
|
+
path: `/campaigns/${id}`
|
|
2161
|
+
});
|
|
2162
|
+
}
|
|
2163
|
+
/**
|
|
2164
|
+
* Preview a campaign before sending
|
|
2165
|
+
*
|
|
2166
|
+
* Returns recipient count, credit estimate, and breakdown by country.
|
|
2167
|
+
*
|
|
2168
|
+
* @param id - Campaign ID
|
|
2169
|
+
* @returns Campaign preview with cost estimate
|
|
2170
|
+
*
|
|
2171
|
+
* @example
|
|
2172
|
+
* ```typescript
|
|
2173
|
+
* const preview = await sendly.campaigns.preview('cmp_xxx');
|
|
2174
|
+
*
|
|
2175
|
+
* console.log(`Recipients: ${preview.recipientCount}`);
|
|
2176
|
+
* console.log(`Estimated cost: ${preview.estimatedCredits} credits`);
|
|
2177
|
+
* console.log(`Your balance: ${preview.currentBalance} credits`);
|
|
2178
|
+
*
|
|
2179
|
+
* if (!preview.hasEnoughCredits) {
|
|
2180
|
+
* console.log('Not enough credits! Please top up.');
|
|
2181
|
+
* }
|
|
2182
|
+
* ```
|
|
2183
|
+
*/
|
|
2184
|
+
async preview(id) {
|
|
2185
|
+
const response = await this.http.request({
|
|
2186
|
+
method: "GET",
|
|
2187
|
+
path: `/campaigns/${id}/preview`
|
|
2188
|
+
});
|
|
2189
|
+
return {
|
|
2190
|
+
id: response.id,
|
|
2191
|
+
recipientCount: response.recipient_count,
|
|
2192
|
+
estimatedSegments: response.estimated_segments,
|
|
2193
|
+
estimatedCredits: response.estimated_credits,
|
|
2194
|
+
currentBalance: response.current_balance,
|
|
2195
|
+
hasEnoughCredits: response.has_enough_credits,
|
|
2196
|
+
breakdown: response.breakdown?.map((b) => ({
|
|
2197
|
+
country: b.country,
|
|
2198
|
+
count: b.count,
|
|
2199
|
+
creditsPerMessage: b.credits_per_message,
|
|
2200
|
+
totalCredits: b.total_credits
|
|
2201
|
+
}))
|
|
2202
|
+
};
|
|
2203
|
+
}
|
|
2204
|
+
/**
|
|
2205
|
+
* Send a campaign immediately
|
|
2206
|
+
*
|
|
2207
|
+
* @param id - Campaign ID
|
|
2208
|
+
* @returns The updated campaign (status: sending)
|
|
2209
|
+
*
|
|
2210
|
+
* @example
|
|
2211
|
+
* ```typescript
|
|
2212
|
+
* const campaign = await sendly.campaigns.send('cmp_xxx');
|
|
2213
|
+
* console.log(`Campaign is now ${campaign.status}`);
|
|
2214
|
+
* ```
|
|
2215
|
+
*/
|
|
2216
|
+
async send(id) {
|
|
2217
|
+
const response = await this.http.request({
|
|
2218
|
+
method: "POST",
|
|
2219
|
+
path: `/campaigns/${id}/send`
|
|
2220
|
+
});
|
|
2221
|
+
return this.transformCampaign(response);
|
|
2222
|
+
}
|
|
2223
|
+
/**
|
|
2224
|
+
* Schedule a campaign for later
|
|
2225
|
+
*
|
|
2226
|
+
* @param id - Campaign ID
|
|
2227
|
+
* @param request - Schedule details
|
|
2228
|
+
* @returns The updated campaign (status: scheduled)
|
|
2229
|
+
*
|
|
2230
|
+
* @example
|
|
2231
|
+
* ```typescript
|
|
2232
|
+
* const campaign = await sendly.campaigns.schedule('cmp_xxx', {
|
|
2233
|
+
* scheduledAt: '2024-01-15T10:00:00Z',
|
|
2234
|
+
* timezone: 'America/New_York'
|
|
2235
|
+
* });
|
|
2236
|
+
*
|
|
2237
|
+
* console.log(`Scheduled for ${campaign.scheduledAt}`);
|
|
2238
|
+
* ```
|
|
2239
|
+
*/
|
|
2240
|
+
async schedule(id, request) {
|
|
2241
|
+
const response = await this.http.request({
|
|
2242
|
+
method: "POST",
|
|
2243
|
+
path: `/campaigns/${id}/schedule`,
|
|
2244
|
+
body: {
|
|
2245
|
+
scheduledAt: request.scheduledAt,
|
|
2246
|
+
timezone: request.timezone
|
|
2247
|
+
}
|
|
2248
|
+
});
|
|
2249
|
+
return this.transformCampaign(response);
|
|
2250
|
+
}
|
|
2251
|
+
/**
|
|
2252
|
+
* Cancel a scheduled campaign
|
|
2253
|
+
*
|
|
2254
|
+
* @param id - Campaign ID
|
|
2255
|
+
* @returns The updated campaign (status: cancelled)
|
|
2256
|
+
*
|
|
2257
|
+
* @example
|
|
2258
|
+
* ```typescript
|
|
2259
|
+
* const campaign = await sendly.campaigns.cancel('cmp_xxx');
|
|
2260
|
+
* console.log(`Campaign cancelled`);
|
|
2261
|
+
* ```
|
|
2262
|
+
*/
|
|
2263
|
+
async cancel(id) {
|
|
2264
|
+
const response = await this.http.request({
|
|
2265
|
+
method: "POST",
|
|
2266
|
+
path: `/campaigns/${id}/cancel`
|
|
2267
|
+
});
|
|
2268
|
+
return this.transformCampaign(response);
|
|
2269
|
+
}
|
|
2270
|
+
/**
|
|
2271
|
+
* Clone a campaign
|
|
2272
|
+
*
|
|
2273
|
+
* Creates a new draft campaign with the same settings.
|
|
2274
|
+
*
|
|
2275
|
+
* @param id - Campaign ID to clone
|
|
2276
|
+
* @returns The new campaign (as draft)
|
|
2277
|
+
*
|
|
2278
|
+
* @example
|
|
2279
|
+
* ```typescript
|
|
2280
|
+
* const cloned = await sendly.campaigns.clone('cmp_xxx');
|
|
2281
|
+
* console.log(`Created clone: ${cloned.id}`);
|
|
2282
|
+
* ```
|
|
2283
|
+
*/
|
|
2284
|
+
async clone(id) {
|
|
2285
|
+
const response = await this.http.request({
|
|
2286
|
+
method: "POST",
|
|
2287
|
+
path: `/campaigns/${id}/clone`
|
|
2288
|
+
});
|
|
2289
|
+
return this.transformCampaign(response);
|
|
2290
|
+
}
|
|
2291
|
+
transformCampaign(raw) {
|
|
2292
|
+
return {
|
|
2293
|
+
id: raw.id,
|
|
2294
|
+
name: raw.name,
|
|
2295
|
+
text: raw.text,
|
|
2296
|
+
templateId: raw.template_id,
|
|
2297
|
+
contactListIds: raw.contact_list_ids || [],
|
|
2298
|
+
status: raw.status,
|
|
2299
|
+
recipientCount: raw.recipient_count || 0,
|
|
2300
|
+
sentCount: raw.sent_count || 0,
|
|
2301
|
+
deliveredCount: raw.delivered_count || 0,
|
|
2302
|
+
failedCount: raw.failed_count || 0,
|
|
2303
|
+
estimatedCredits: raw.estimated_credits || 0,
|
|
2304
|
+
creditsUsed: raw.credits_used || 0,
|
|
2305
|
+
scheduledAt: raw.scheduled_at,
|
|
2306
|
+
timezone: raw.timezone,
|
|
2307
|
+
startedAt: raw.started_at,
|
|
2308
|
+
completedAt: raw.completed_at,
|
|
2309
|
+
createdAt: raw.created_at,
|
|
2310
|
+
updatedAt: raw.updated_at
|
|
2311
|
+
};
|
|
2312
|
+
}
|
|
2313
|
+
};
|
|
2314
|
+
|
|
2315
|
+
// src/resources/contacts.ts
|
|
2316
|
+
var ContactsResource = class {
|
|
2317
|
+
http;
|
|
2318
|
+
lists;
|
|
2319
|
+
constructor(http) {
|
|
2320
|
+
this.http = http;
|
|
2321
|
+
this.lists = new ContactListsResource(http);
|
|
2322
|
+
}
|
|
2323
|
+
/**
|
|
2324
|
+
* List contacts with optional filtering
|
|
2325
|
+
*
|
|
2326
|
+
* @param options - Filter and pagination options
|
|
2327
|
+
* @returns List of contacts
|
|
2328
|
+
*
|
|
2329
|
+
* @example
|
|
2330
|
+
* ```typescript
|
|
2331
|
+
* // List all contacts
|
|
2332
|
+
* const { contacts, total } = await sendly.contacts.list();
|
|
2333
|
+
*
|
|
2334
|
+
* // Search contacts
|
|
2335
|
+
* const { contacts } = await sendly.contacts.list({ search: 'john' });
|
|
2336
|
+
*
|
|
2337
|
+
* // List contacts in a specific list
|
|
2338
|
+
* const { contacts } = await sendly.contacts.list({ listId: 'lst_xxx' });
|
|
2339
|
+
* ```
|
|
2340
|
+
*/
|
|
2341
|
+
async list(options = {}) {
|
|
2342
|
+
const params = new URLSearchParams();
|
|
2343
|
+
if (options.limit) params.set("limit", String(options.limit));
|
|
2344
|
+
if (options.offset) params.set("offset", String(options.offset));
|
|
2345
|
+
if (options.search) params.set("search", options.search);
|
|
2346
|
+
if (options.listId) params.set("list_id", options.listId);
|
|
2347
|
+
const queryString = params.toString();
|
|
2348
|
+
const response = await this.http.request({
|
|
2349
|
+
method: "GET",
|
|
2350
|
+
path: `/contacts${queryString ? `?${queryString}` : ""}`
|
|
2351
|
+
});
|
|
2352
|
+
return {
|
|
2353
|
+
contacts: response.contacts.map((c) => this.transformContact(c)),
|
|
2354
|
+
total: response.total,
|
|
2355
|
+
limit: response.limit,
|
|
2356
|
+
offset: response.offset
|
|
2357
|
+
};
|
|
2358
|
+
}
|
|
2359
|
+
/**
|
|
2360
|
+
* Get a contact by ID
|
|
2361
|
+
*
|
|
2362
|
+
* @param id - Contact ID
|
|
2363
|
+
* @returns The contact with associated lists
|
|
2364
|
+
*
|
|
2365
|
+
* @example
|
|
2366
|
+
* ```typescript
|
|
2367
|
+
* const contact = await sendly.contacts.get('cnt_xxx');
|
|
2368
|
+
* console.log(`${contact.name}: ${contact.phoneNumber}`);
|
|
2369
|
+
* console.log(`In ${contact.lists?.length || 0} lists`);
|
|
2370
|
+
* ```
|
|
2371
|
+
*/
|
|
2372
|
+
async get(id) {
|
|
2373
|
+
const response = await this.http.request({
|
|
2374
|
+
method: "GET",
|
|
2375
|
+
path: `/contacts/${id}`
|
|
2376
|
+
});
|
|
2377
|
+
return this.transformContact(response);
|
|
2378
|
+
}
|
|
2379
|
+
/**
|
|
2380
|
+
* Create a new contact
|
|
2381
|
+
*
|
|
2382
|
+
* @param request - Contact details
|
|
2383
|
+
* @returns The created contact
|
|
2384
|
+
*
|
|
2385
|
+
* @example
|
|
2386
|
+
* ```typescript
|
|
2387
|
+
* const contact = await sendly.contacts.create({
|
|
2388
|
+
* phoneNumber: '+15551234567',
|
|
2389
|
+
* name: 'Jane Smith',
|
|
2390
|
+
* email: 'jane@example.com',
|
|
2391
|
+
* metadata: { source: 'signup_form', plan: 'premium' }
|
|
2392
|
+
* });
|
|
2393
|
+
* ```
|
|
2394
|
+
*/
|
|
2395
|
+
async create(request) {
|
|
2396
|
+
const response = await this.http.request({
|
|
2397
|
+
method: "POST",
|
|
2398
|
+
path: "/contacts",
|
|
2399
|
+
body: {
|
|
2400
|
+
phone_number: request.phoneNumber,
|
|
2401
|
+
name: request.name,
|
|
2402
|
+
email: request.email,
|
|
2403
|
+
metadata: request.metadata
|
|
2404
|
+
}
|
|
2405
|
+
});
|
|
2406
|
+
return this.transformContact(response);
|
|
2407
|
+
}
|
|
2408
|
+
/**
|
|
2409
|
+
* Update a contact
|
|
2410
|
+
*
|
|
2411
|
+
* @param id - Contact ID
|
|
2412
|
+
* @param request - Fields to update
|
|
2413
|
+
* @returns The updated contact
|
|
2414
|
+
*
|
|
2415
|
+
* @example
|
|
2416
|
+
* ```typescript
|
|
2417
|
+
* const contact = await sendly.contacts.update('cnt_xxx', {
|
|
2418
|
+
* name: 'Jane Doe',
|
|
2419
|
+
* metadata: { plan: 'enterprise' }
|
|
2420
|
+
* });
|
|
2421
|
+
* ```
|
|
2422
|
+
*/
|
|
2423
|
+
async update(id, request) {
|
|
2424
|
+
const response = await this.http.request({
|
|
2425
|
+
method: "PATCH",
|
|
2426
|
+
path: `/contacts/${id}`,
|
|
2427
|
+
body: {
|
|
2428
|
+
name: request.name,
|
|
2429
|
+
email: request.email,
|
|
2430
|
+
metadata: request.metadata
|
|
2431
|
+
}
|
|
2432
|
+
});
|
|
2433
|
+
return this.transformContact(response);
|
|
2434
|
+
}
|
|
2435
|
+
/**
|
|
2436
|
+
* Delete a contact
|
|
2437
|
+
*
|
|
2438
|
+
* @param id - Contact ID
|
|
2439
|
+
*
|
|
2440
|
+
* @example
|
|
2441
|
+
* ```typescript
|
|
2442
|
+
* await sendly.contacts.delete('cnt_xxx');
|
|
2443
|
+
* ```
|
|
2444
|
+
*/
|
|
2445
|
+
async delete(id) {
|
|
2446
|
+
await this.http.request({
|
|
2447
|
+
method: "DELETE",
|
|
2448
|
+
path: `/contacts/${id}`
|
|
2449
|
+
});
|
|
2450
|
+
}
|
|
2451
|
+
transformContact(raw) {
|
|
2452
|
+
return {
|
|
2453
|
+
id: raw.id,
|
|
2454
|
+
phoneNumber: raw.phone_number,
|
|
2455
|
+
name: raw.name,
|
|
2456
|
+
email: raw.email,
|
|
2457
|
+
metadata: raw.metadata,
|
|
2458
|
+
optedOut: raw.opted_out,
|
|
2459
|
+
createdAt: raw.created_at,
|
|
2460
|
+
updatedAt: raw.updated_at,
|
|
2461
|
+
lists: raw.lists?.map((l) => ({ id: l.id, name: l.name }))
|
|
2462
|
+
};
|
|
2463
|
+
}
|
|
2464
|
+
};
|
|
2465
|
+
var ContactListsResource = class {
|
|
2466
|
+
http;
|
|
2467
|
+
constructor(http) {
|
|
2468
|
+
this.http = http;
|
|
2469
|
+
}
|
|
2470
|
+
/**
|
|
2471
|
+
* List all contact lists
|
|
2472
|
+
*
|
|
2473
|
+
* @returns All contact lists
|
|
2474
|
+
*
|
|
2475
|
+
* @example
|
|
2476
|
+
* ```typescript
|
|
2477
|
+
* const { lists } = await sendly.contacts.lists.list();
|
|
2478
|
+
* for (const list of lists) {
|
|
2479
|
+
* console.log(`${list.name}: ${list.contactCount} contacts`);
|
|
2480
|
+
* }
|
|
2481
|
+
* ```
|
|
2482
|
+
*/
|
|
2483
|
+
async list() {
|
|
2484
|
+
const response = await this.http.request({
|
|
2485
|
+
method: "GET",
|
|
2486
|
+
path: "/contact-lists"
|
|
2487
|
+
});
|
|
2488
|
+
return {
|
|
2489
|
+
lists: response.lists.map((l) => this.transformList(l))
|
|
2490
|
+
};
|
|
2491
|
+
}
|
|
2492
|
+
/**
|
|
2493
|
+
* Get a contact list by ID
|
|
2494
|
+
*
|
|
2495
|
+
* @param id - Contact list ID
|
|
2496
|
+
* @param options - Pagination options for contacts
|
|
2497
|
+
* @returns The contact list with members
|
|
2498
|
+
*
|
|
2499
|
+
* @example
|
|
2500
|
+
* ```typescript
|
|
2501
|
+
* const list = await sendly.contacts.lists.get('lst_xxx');
|
|
2502
|
+
* console.log(`${list.name}: ${list.contactCount} contacts`);
|
|
2503
|
+
*
|
|
2504
|
+
* // Get list with paginated contacts
|
|
2505
|
+
* const list = await sendly.contacts.lists.get('lst_xxx', { limit: 100 });
|
|
2506
|
+
* console.log(`Showing ${list.contacts?.length} of ${list.contactsTotal}`);
|
|
2507
|
+
* ```
|
|
2508
|
+
*/
|
|
2509
|
+
async get(id, options = {}) {
|
|
2510
|
+
const params = new URLSearchParams();
|
|
2511
|
+
if (options.limit) params.set("limit", String(options.limit));
|
|
2512
|
+
if (options.offset) params.set("offset", String(options.offset));
|
|
2513
|
+
const queryString = params.toString();
|
|
2514
|
+
const response = await this.http.request({
|
|
2515
|
+
method: "GET",
|
|
2516
|
+
path: `/contact-lists/${id}${queryString ? `?${queryString}` : ""}`
|
|
2517
|
+
});
|
|
2518
|
+
return this.transformList(response);
|
|
2519
|
+
}
|
|
2520
|
+
/**
|
|
2521
|
+
* Create a new contact list
|
|
2522
|
+
*
|
|
2523
|
+
* @param request - List details
|
|
2524
|
+
* @returns The created list
|
|
2525
|
+
*
|
|
2526
|
+
* @example
|
|
2527
|
+
* ```typescript
|
|
2528
|
+
* const list = await sendly.contacts.lists.create({
|
|
2529
|
+
* name: 'VIP Customers',
|
|
2530
|
+
* description: 'High-value customers for priority messaging'
|
|
2531
|
+
* });
|
|
2532
|
+
* ```
|
|
2533
|
+
*/
|
|
2534
|
+
async create(request) {
|
|
2535
|
+
const response = await this.http.request({
|
|
2536
|
+
method: "POST",
|
|
2537
|
+
path: "/contact-lists",
|
|
2538
|
+
body: {
|
|
2539
|
+
name: request.name,
|
|
2540
|
+
description: request.description
|
|
2541
|
+
}
|
|
2542
|
+
});
|
|
2543
|
+
return this.transformList(response);
|
|
2544
|
+
}
|
|
2545
|
+
/**
|
|
2546
|
+
* Update a contact list
|
|
2547
|
+
*
|
|
2548
|
+
* @param id - Contact list ID
|
|
2549
|
+
* @param request - Fields to update
|
|
2550
|
+
* @returns The updated list
|
|
2551
|
+
*
|
|
2552
|
+
* @example
|
|
2553
|
+
* ```typescript
|
|
2554
|
+
* const list = await sendly.contacts.lists.update('lst_xxx', {
|
|
2555
|
+
* name: 'Premium Subscribers',
|
|
2556
|
+
* description: 'Updated description'
|
|
2557
|
+
* });
|
|
2558
|
+
* ```
|
|
2559
|
+
*/
|
|
2560
|
+
async update(id, request) {
|
|
2561
|
+
const response = await this.http.request({
|
|
2562
|
+
method: "PATCH",
|
|
2563
|
+
path: `/contact-lists/${id}`,
|
|
2564
|
+
body: {
|
|
2565
|
+
name: request.name,
|
|
2566
|
+
description: request.description
|
|
2567
|
+
}
|
|
2568
|
+
});
|
|
2569
|
+
return this.transformList(response);
|
|
2570
|
+
}
|
|
2571
|
+
/**
|
|
2572
|
+
* Delete a contact list
|
|
2573
|
+
*
|
|
2574
|
+
* This does not delete the contacts in the list.
|
|
2575
|
+
*
|
|
2576
|
+
* @param id - Contact list ID
|
|
2577
|
+
*
|
|
2578
|
+
* @example
|
|
2579
|
+
* ```typescript
|
|
2580
|
+
* await sendly.contacts.lists.delete('lst_xxx');
|
|
2581
|
+
* ```
|
|
2582
|
+
*/
|
|
2583
|
+
async delete(id) {
|
|
2584
|
+
await this.http.request({
|
|
2585
|
+
method: "DELETE",
|
|
2586
|
+
path: `/contact-lists/${id}`
|
|
2587
|
+
});
|
|
2588
|
+
}
|
|
2589
|
+
/**
|
|
2590
|
+
* Add contacts to a list
|
|
2591
|
+
*
|
|
2592
|
+
* @param listId - Contact list ID
|
|
2593
|
+
* @param contactIds - Array of contact IDs to add
|
|
2594
|
+
* @returns Number of contacts added
|
|
2595
|
+
*
|
|
2596
|
+
* @example
|
|
2597
|
+
* ```typescript
|
|
2598
|
+
* const result = await sendly.contacts.lists.addContacts('lst_xxx', [
|
|
2599
|
+
* 'cnt_abc',
|
|
2600
|
+
* 'cnt_def',
|
|
2601
|
+
* 'cnt_ghi'
|
|
2602
|
+
* ]);
|
|
2603
|
+
* console.log(`Added ${result.addedCount} contacts`);
|
|
2604
|
+
* ```
|
|
2605
|
+
*/
|
|
2606
|
+
async addContacts(listId, contactIds) {
|
|
2607
|
+
const response = await this.http.request({
|
|
2608
|
+
method: "POST",
|
|
2609
|
+
path: `/contact-lists/${listId}/contacts`,
|
|
2610
|
+
body: { contact_ids: contactIds }
|
|
2611
|
+
});
|
|
2612
|
+
return { addedCount: response.added_count };
|
|
2613
|
+
}
|
|
2614
|
+
/**
|
|
2615
|
+
* Remove a contact from a list
|
|
2616
|
+
*
|
|
2617
|
+
* @param listId - Contact list ID
|
|
2618
|
+
* @param contactId - Contact ID to remove
|
|
2619
|
+
*
|
|
2620
|
+
* @example
|
|
2621
|
+
* ```typescript
|
|
2622
|
+
* await sendly.contacts.lists.removeContact('lst_xxx', 'cnt_abc');
|
|
2623
|
+
* ```
|
|
2624
|
+
*/
|
|
2625
|
+
async removeContact(listId, contactId) {
|
|
2626
|
+
await this.http.request({
|
|
2627
|
+
method: "DELETE",
|
|
2628
|
+
path: `/contact-lists/${listId}/contacts/${contactId}`
|
|
2629
|
+
});
|
|
2630
|
+
}
|
|
2631
|
+
transformList(raw) {
|
|
2632
|
+
return {
|
|
2633
|
+
id: raw.id,
|
|
2634
|
+
name: raw.name,
|
|
2635
|
+
description: raw.description,
|
|
2636
|
+
contactCount: raw.contact_count || 0,
|
|
2637
|
+
createdAt: raw.created_at,
|
|
2638
|
+
updatedAt: raw.updated_at,
|
|
2639
|
+
contacts: raw.contacts?.map((c) => ({
|
|
2640
|
+
id: c.id,
|
|
2641
|
+
phoneNumber: c.phone_number,
|
|
2642
|
+
name: c.name,
|
|
2643
|
+
email: c.email
|
|
2644
|
+
})),
|
|
2645
|
+
contactsTotal: raw.contacts_total
|
|
2646
|
+
};
|
|
2647
|
+
}
|
|
2648
|
+
};
|
|
2649
|
+
|
|
1934
2650
|
// src/client.ts
|
|
1935
2651
|
var DEFAULT_BASE_URL2 = "https://sendly.live/api/v1";
|
|
1936
2652
|
var DEFAULT_TIMEOUT2 = 3e4;
|
|
@@ -2028,6 +2744,47 @@ var Sendly = class {
|
|
|
2028
2744
|
* ```
|
|
2029
2745
|
*/
|
|
2030
2746
|
templates;
|
|
2747
|
+
/**
|
|
2748
|
+
* Campaigns API resource - Bulk SMS campaign management
|
|
2749
|
+
*
|
|
2750
|
+
* @example
|
|
2751
|
+
* ```typescript
|
|
2752
|
+
* // Create a campaign
|
|
2753
|
+
* const campaign = await sendly.campaigns.create({
|
|
2754
|
+
* name: 'Welcome Campaign',
|
|
2755
|
+
* text: 'Hello {{name}}!',
|
|
2756
|
+
* contactListIds: ['lst_xxx']
|
|
2757
|
+
* });
|
|
2758
|
+
*
|
|
2759
|
+
* // Preview cost
|
|
2760
|
+
* const preview = await sendly.campaigns.preview(campaign.id);
|
|
2761
|
+
* console.log(`Cost: ${preview.estimatedCredits} credits`);
|
|
2762
|
+
*
|
|
2763
|
+
* // Send or schedule
|
|
2764
|
+
* await sendly.campaigns.send(campaign.id);
|
|
2765
|
+
* ```
|
|
2766
|
+
*/
|
|
2767
|
+
campaigns;
|
|
2768
|
+
/**
|
|
2769
|
+
* Contacts API resource - Contact and list management
|
|
2770
|
+
*
|
|
2771
|
+
* @example
|
|
2772
|
+
* ```typescript
|
|
2773
|
+
* // Create a contact
|
|
2774
|
+
* const contact = await sendly.contacts.create({
|
|
2775
|
+
* phoneNumber: '+15551234567',
|
|
2776
|
+
* name: 'John Doe'
|
|
2777
|
+
* });
|
|
2778
|
+
*
|
|
2779
|
+
* // Create a list and add contacts
|
|
2780
|
+
* const list = await sendly.contacts.lists.create({ name: 'VIPs' });
|
|
2781
|
+
* await sendly.contacts.lists.addContacts(list.id, [contact.id]);
|
|
2782
|
+
*
|
|
2783
|
+
* // List all contacts
|
|
2784
|
+
* const { contacts } = await sendly.contacts.list();
|
|
2785
|
+
* ```
|
|
2786
|
+
*/
|
|
2787
|
+
contacts;
|
|
2031
2788
|
http;
|
|
2032
2789
|
config;
|
|
2033
2790
|
/**
|
|
@@ -2062,6 +2819,8 @@ var Sendly = class {
|
|
|
2062
2819
|
this.account = new AccountResource(this.http);
|
|
2063
2820
|
this.verify = new VerifyResource(this.http);
|
|
2064
2821
|
this.templates = new TemplatesResource(this.http);
|
|
2822
|
+
this.campaigns = new CampaignsResource(this.http);
|
|
2823
|
+
this.contacts = new ContactsResource(this.http);
|
|
2065
2824
|
}
|
|
2066
2825
|
/**
|
|
2067
2826
|
* Check if the client is using a test API key
|