mailerbot 0.1.0 → 0.1.1

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 CHANGED
@@ -1,290 +1,290 @@
1
- # MailerBot Node.js SDK
2
-
3
- Official TypeScript/JavaScript SDK for the [MailerBot](https://mailerbot.com) direct mail API. Send letters and postcards programmatically.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- npm install mailerbot
9
- ```
10
-
11
- Requires Node.js 18+ (uses native `fetch`).
12
-
13
- ## Authentication
14
-
15
- Generate an API key in your [MailerBot dashboard](https://app.mailerbot.com/settings/api-keys), then pass it to the client:
16
-
17
- ```ts
18
- import { MailerBot } from "mailerbot";
19
-
20
- const client = new MailerBot("mb_live_...");
21
- ```
22
-
23
- ## Quick Start
24
-
25
- ```ts
26
- import { MailerBot } from "mailerbot";
27
-
28
- const client = new MailerBot("mb_live_...");
29
-
30
- // List contacts
31
- const page = await client.contacts.list({ page: 1, pageSize: 25 });
32
- console.log(`${page.total} total contacts`);
33
- for (const contact of page.items) {
34
- console.log(` ${contact.firstName} ${contact.lastName}, ${contact.city}, ${contact.state}`);
35
- }
36
-
37
- // Dashboard stats
38
- const stats = await client.dashboard.stats();
39
- console.log(`Letters sent: ${stats.lettersSent}`);
40
- console.log(`Total spent: $${stats.totalSpent.toFixed(2)}`);
41
- ```
42
-
43
- ## Common Workflows
44
-
45
- ### Create and send a letter mailing
46
-
47
- ```ts
48
- import { MailerBot } from "mailerbot";
49
-
50
- const client = new MailerBot("mb_live_...");
51
-
52
- // 1. Create a contact list
53
- const contactList = await client.contactLists.create("My Campaign List");
54
-
55
- // 2. Add contacts (countryCode defaults to "US" if omitted)
56
- const contact = await client.contacts.create({
57
- firstName: "Jane",
58
- lastName: "Smith",
59
- addressLine1: "123 Main St",
60
- city: "Austin",
61
- state: "TX",
62
- zip: "78701",
63
- });
64
- await client.contactLists.addContacts(contactList.id, [contact.id]);
65
-
66
- // 3. Write a letter document
67
- const doc = await client.documents.create({
68
- title: "Spring Promo Letter",
69
- content: "<p>Dear {{first_name}},</p><p>Check out our spring deals!</p>",
70
- });
71
-
72
- // 4. Create the mailing (postage defaults to cheapest rate per zone)
73
- const mailing = await client.mailings.create({
74
- name: "Spring 2026 Promo",
75
- type: "letter",
76
- contactListId: contactList.id,
77
- documentId: doc.id,
78
- });
79
-
80
- // 5. Review the cost
81
- const cost = await client.mailings.calculateCost(mailing.id);
82
- console.log(`Product cost: $${cost.totalProductCost.toFixed(2)} (${cost.recipientCount} recipients)`);
83
- for (const zone of cost.zoneCounts) {
84
- console.log(` ${zone.postageZoneName}: ${zone.recipientCount} recipients`);
85
- }
86
-
87
- // 6. Create a Stripe payment intent, complete payment on your end, then send
88
- const intent = await client.payments.createPaymentIntent(mailing.id);
89
- // ... complete Stripe payment using intent.clientSecret ...
90
-
91
- // 7. Send
92
- const sent = await client.mailings.send(mailing.id);
93
- console.log(`Mailing status: ${sent.status}`);
94
- ```
95
-
96
- ### Bulk import contacts from CSV data
97
-
98
- ```ts
99
- const result = await client.contacts.importCsv(
100
- [
101
- { firstName: "Alice", lastName: "Wu", addressLine1: "456 Oak Ave",
102
- city: "Dallas", state: "TX", zip: "75201" },
103
- { firstName: "Bob", lastName: "Smith", addressLine1: "789 Pine Rd",
104
- city: "Houston", state: "TX", zip: "77001" },
105
- ],
106
- { listName: "Imported List" },
107
- );
108
- console.log(`Imported ${result.importedCount} contacts into list ${result.listId}`);
109
- ```
110
-
111
- ### International contacts
112
-
113
- ```ts
114
- // List available countries
115
- const countries = await client.pricing.countries();
116
- for (const c of countries) {
117
- console.log(` ${c.code} — ${c.name} (active: ${c.isActive})`);
118
- }
119
-
120
- // Create a Canadian contact
121
- const contact = await client.contacts.create({
122
- firstName: "Marie",
123
- lastName: "Tremblay",
124
- addressLine1: "350 Rue Saint-Paul",
125
- city: "Montréal",
126
- state: "QC",
127
- zip: "H2Y 1H2",
128
- countryCode: "CA",
129
- });
130
- ```
131
-
132
- ### Estimate cost before creating a mailing
133
-
134
- ```ts
135
- const cost = await client.mailings.estimateCost({
136
- type: "postcard",
137
- contactListId: "<list_id>",
138
- });
139
- console.log(`Product cost: $${cost.totalProductCost.toFixed(2)}`);
140
- for (const zone of cost.zoneCounts) {
141
- console.log(` ${zone.postageZoneName}: ${zone.recipientCount} recipients`);
142
- }
143
- for (const u of cost.unavailable) {
144
- console.log(` ⚠ ${u.countryName}: ${u.recipientCount} recipients (${u.reason})`);
145
- }
146
-
147
- // See available postage rates
148
- const rates = await client.pricing.postageRates({ productType: "postcard" });
149
- for (const r of rates) {
150
- console.log(` ${r.postageZoneName} — ${r.label}: $${r.costPerPiece}`);
151
- }
152
- ```
153
-
154
- ### Iterate over all contacts (auto-pagination)
155
-
156
- ```ts
157
- for await (const contact of client.contacts.iterAll({ pageSize: 100 })) {
158
- console.log(contact.firstName, contact.lastName);
159
- }
160
- ```
161
-
162
- ### Send a postcard mailing
163
-
164
- ```ts
165
- // Browse available templates
166
- const templates = await client.postcards.listTemplates();
167
- console.log(`${templates.length} templates available`);
168
-
169
- // Create a postcard from scratch (or use the canvas builder in the dashboard)
170
- const postcard = await client.postcards.create({ title: "Summer Sale Card" });
171
-
172
- const mailing = await client.mailings.create({
173
- name: "Summer Postcard Drop",
174
- type: "postcard",
175
- contactListId: "<list_id>",
176
- postcardId: postcard.id,
177
- });
178
- const cost = await client.mailings.calculateCost(mailing.id);
179
- console.log(`$${cost.totalProductCost.toFixed(2)} for ${cost.recipientCount} postcards`);
180
- ```
181
-
182
- ### Track QR code scans
183
-
184
- ```ts
185
- // Create a trackable short link
186
- const link = await client.qr.create({ destinationUrl: "https://yoursite.com/promo" });
187
- console.log(`Short URL: ${link.shortUrl}`);
188
-
189
- // Get analytics
190
- const analytics = await client.qr.analytics({ days: 30 });
191
- console.log(`${analytics.totalScans} scans across ${analytics.uniqueLinks} links`);
192
- for (const day of analytics.scansByDay) {
193
- console.log(` ${day.date}: ${day.count} scans`);
194
- }
195
- ```
196
-
197
- ### Track USPS delivery per piece
198
-
199
- ```ts
200
- const mailing = await client.mailings.get("<mailing_id>");
201
- console.log(`${mailing.itemsDelivered}/${mailing.itemCount} delivered, ${mailing.itemsReturned} returned`);
202
-
203
- // Pieces USPS flagged as return-to-sender (filter: none, in_transit,
204
- // out_for_delivery, forwarded, delivered, returned)
205
- for await (const item of client.mailings.iterItems(mailing.id, { trackingStatus: "returned" })) {
206
- console.log(`${item.recipientName}: ${item.lastScanLabel} at ${item.lastScanLocation}`);
207
- }
208
-
209
- // Full scan history for one piece
210
- const page = await client.mailings.listItems(mailing.id, { pageSize: 1 });
211
- for (const scan of await client.mailings.listItemScans(mailing.id, page.items[0].id)) {
212
- console.log(` ${scan.scanDatetime} ${scan.label} (${scan.facilityCity}, ${scan.facilityState})`);
213
- }
214
- ```
215
-
216
- Or subscribe to the `mail_delivered` and `mail_returned` webhook events to be pushed these updates instead of polling.
217
-
218
- ### Use coupon codes in mailings
219
-
220
- ```ts
221
- // Create a coupon list and import codes
222
- const couponList = await client.coupons.create("Spring Sale Coupons");
223
- const result = await client.coupons.importCodes(couponList.id, ["SAVE10", "SAVE20", "SAVE30"]);
224
- console.log(`Imported ${result.importedCount} codes`);
225
-
226
- // Check there are enough codes before sending
227
- const avail = await client.coupons.checkAvailability(couponList.id, 500);
228
- if (!avail.sufficient) {
229
- console.log(`Only ${avail.availableCodes} codes available, need 500`);
230
- }
231
-
232
- // Attach to a mailing — each recipient gets a unique code
233
- const mailing = await client.mailings.create({
234
- name: "Spring Promo",
235
- type: "letter",
236
- contactListId: "<list_id>",
237
- documentId: "<doc_id>",
238
- couponListId: couponList.id,
239
- });
240
- ```
241
-
242
- ## Error Handling
243
-
244
- ```ts
245
- import { MailerBot, AuthenticationError, NotFoundError, ValidationError, MailerBotError } from "mailerbot";
246
-
247
- try {
248
- const client = new MailerBot("bad_key");
249
- await client.contacts.list();
250
- } catch (error) {
251
- if (error instanceof AuthenticationError) {
252
- console.log(`Auth failed: ${error.message}`);
253
- } else if (error instanceof NotFoundError) {
254
- console.log(`Resource not found: ${error.message}`);
255
- } else if (error instanceof ValidationError) {
256
- console.log(`Bad request: ${error.message}`, error.response);
257
- } else if (error instanceof MailerBotError) {
258
- console.log(`API error ${error.statusCode}: ${error.message}`);
259
- }
260
- }
261
- ```
262
-
263
- ### Exception hierarchy
264
-
265
- | Error class | HTTP status |
266
- |---|---|
267
- | `AuthenticationError` | 401 |
268
- | `PermissionError` | 403 |
269
- | `NotFoundError` | 404 |
270
- | `ValidationError` | 422 |
271
- | `RateLimitError` | 429 |
272
- | `ServerError` | 5xx |
273
- | `MailerBotError` | base class / other |
274
-
275
- ## Configuration
276
-
277
- ```ts
278
- const client = new MailerBot("mb_live_...", {
279
- baseUrl: "https://api.mailerbot.com/api/v1", // default
280
- timeout: 30_000, // milliseconds, default 30000
281
- });
282
- ```
283
-
284
- ## Full API Reference
285
-
286
- See [https://mailerbot.com/docs](https://mailerbot.com/docs) for complete endpoint documentation.
287
-
288
- ## License
289
-
290
- MIT
1
+ # MailerBot Node.js SDK
2
+
3
+ Official TypeScript/JavaScript SDK for the [MailerBot](https://mailerbot.com) direct mail API. Send letters and postcards programmatically.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install mailerbot
9
+ ```
10
+
11
+ Requires Node.js 18+ (uses native `fetch`).
12
+
13
+ ## Authentication
14
+
15
+ Generate an API key in your [MailerBot dashboard](https://app.mailerbot.com/settings/api-keys), then pass it to the client:
16
+
17
+ ```ts
18
+ import { MailerBot } from "mailerbot";
19
+
20
+ const client = new MailerBot("mb_live_...");
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ ```ts
26
+ import { MailerBot } from "mailerbot";
27
+
28
+ const client = new MailerBot("mb_live_...");
29
+
30
+ // List contacts
31
+ const page = await client.contacts.list({ page: 1, pageSize: 25 });
32
+ console.log(`${page.total} total contacts`);
33
+ for (const contact of page.items) {
34
+ console.log(` ${contact.firstName} ${contact.lastName}, ${contact.city}, ${contact.state}`);
35
+ }
36
+
37
+ // Dashboard stats
38
+ const stats = await client.dashboard.stats();
39
+ console.log(`Letters sent: ${stats.lettersSent}`);
40
+ console.log(`Total spent: $${stats.totalSpent.toFixed(2)}`);
41
+ ```
42
+
43
+ ## Common Workflows
44
+
45
+ ### Create and send a letter mailing
46
+
47
+ ```ts
48
+ import { MailerBot } from "mailerbot";
49
+
50
+ const client = new MailerBot("mb_live_...");
51
+
52
+ // 1. Create a contact list
53
+ const contactList = await client.contactLists.create("My Campaign List");
54
+
55
+ // 2. Add contacts (countryCode defaults to "US" if omitted)
56
+ const contact = await client.contacts.create({
57
+ firstName: "Jane",
58
+ lastName: "Smith",
59
+ addressLine1: "123 Main St",
60
+ city: "Austin",
61
+ state: "TX",
62
+ zip: "78701",
63
+ });
64
+ await client.contactLists.addContacts(contactList.id, [contact.id]);
65
+
66
+ // 3. Write a letter document
67
+ const doc = await client.documents.create({
68
+ title: "Spring Promo Letter",
69
+ content: "<p>Dear {{first_name}},</p><p>Check out our spring deals!</p>",
70
+ });
71
+
72
+ // 4. Create the mailing (postage defaults to cheapest rate per zone)
73
+ const mailing = await client.mailings.create({
74
+ name: "Spring 2026 Promo",
75
+ type: "letter",
76
+ contactListId: contactList.id,
77
+ documentId: doc.id,
78
+ });
79
+
80
+ // 5. Review the cost
81
+ const cost = await client.mailings.calculateCost(mailing.id);
82
+ console.log(`Product cost: $${cost.totalProductCost.toFixed(2)} (${cost.recipientCount} recipients)`);
83
+ for (const zone of cost.zoneCounts) {
84
+ console.log(` ${zone.postageZoneName}: ${zone.recipientCount} recipients`);
85
+ }
86
+
87
+ // 6. Create a Stripe payment intent, complete payment on your end, then send
88
+ const intent = await client.payments.createPaymentIntent(mailing.id);
89
+ // ... complete Stripe payment using intent.clientSecret ...
90
+
91
+ // 7. Send
92
+ const sent = await client.mailings.send(mailing.id);
93
+ console.log(`Mailing status: ${sent.status}`);
94
+ ```
95
+
96
+ ### Bulk import contacts from CSV data
97
+
98
+ ```ts
99
+ const result = await client.contacts.importCsv(
100
+ [
101
+ { firstName: "Alice", lastName: "Wu", addressLine1: "456 Oak Ave",
102
+ city: "Dallas", state: "TX", zip: "75201" },
103
+ { firstName: "Bob", lastName: "Smith", addressLine1: "789 Pine Rd",
104
+ city: "Houston", state: "TX", zip: "77001" },
105
+ ],
106
+ { listName: "Imported List" },
107
+ );
108
+ console.log(`Imported ${result.importedCount} contacts into list ${result.listId}`);
109
+ ```
110
+
111
+ ### International contacts
112
+
113
+ ```ts
114
+ // List available countries
115
+ const countries = await client.pricing.countries();
116
+ for (const c of countries) {
117
+ console.log(` ${c.code} — ${c.name} (active: ${c.isActive})`);
118
+ }
119
+
120
+ // Create a Canadian contact
121
+ const contact = await client.contacts.create({
122
+ firstName: "Marie",
123
+ lastName: "Tremblay",
124
+ addressLine1: "350 Rue Saint-Paul",
125
+ city: "Montréal",
126
+ state: "QC",
127
+ zip: "H2Y 1H2",
128
+ countryCode: "CA",
129
+ });
130
+ ```
131
+
132
+ ### Estimate cost before creating a mailing
133
+
134
+ ```ts
135
+ const cost = await client.mailings.estimateCost({
136
+ type: "postcard",
137
+ contactListId: "<list_id>",
138
+ });
139
+ console.log(`Product cost: $${cost.totalProductCost.toFixed(2)}`);
140
+ for (const zone of cost.zoneCounts) {
141
+ console.log(` ${zone.postageZoneName}: ${zone.recipientCount} recipients`);
142
+ }
143
+ for (const u of cost.unavailable) {
144
+ console.log(` ⚠ ${u.countryName}: ${u.recipientCount} recipients (${u.reason})`);
145
+ }
146
+
147
+ // See available postage rates
148
+ const rates = await client.pricing.postageRates({ productType: "postcard" });
149
+ for (const r of rates) {
150
+ console.log(` ${r.postageZoneName} — ${r.label}: $${r.costPerPiece}`);
151
+ }
152
+ ```
153
+
154
+ ### Iterate over all contacts (auto-pagination)
155
+
156
+ ```ts
157
+ for await (const contact of client.contacts.iterAll({ pageSize: 100 })) {
158
+ console.log(contact.firstName, contact.lastName);
159
+ }
160
+ ```
161
+
162
+ ### Send a postcard mailing
163
+
164
+ ```ts
165
+ // Browse available templates
166
+ const templates = await client.postcards.listTemplates();
167
+ console.log(`${templates.length} templates available`);
168
+
169
+ // Create a postcard from scratch (or use the canvas builder in the dashboard)
170
+ const postcard = await client.postcards.create({ title: "Summer Sale Card" });
171
+
172
+ const mailing = await client.mailings.create({
173
+ name: "Summer Postcard Drop",
174
+ type: "postcard",
175
+ contactListId: "<list_id>",
176
+ postcardId: postcard.id,
177
+ });
178
+ const cost = await client.mailings.calculateCost(mailing.id);
179
+ console.log(`$${cost.totalProductCost.toFixed(2)} for ${cost.recipientCount} postcards`);
180
+ ```
181
+
182
+ ### Track QR code scans
183
+
184
+ ```ts
185
+ // Create a trackable short link
186
+ const link = await client.qr.create({ destinationUrl: "https://yoursite.com/promo" });
187
+ console.log(`Short URL: ${link.shortUrl}`);
188
+
189
+ // Get analytics
190
+ const analytics = await client.qr.analytics({ days: 30 });
191
+ console.log(`${analytics.totalScans} scans across ${analytics.uniqueLinks} links`);
192
+ for (const day of analytics.scansByDay) {
193
+ console.log(` ${day.date}: ${day.count} scans`);
194
+ }
195
+ ```
196
+
197
+ ### Track USPS delivery per piece
198
+
199
+ ```ts
200
+ const mailing = await client.mailings.get("<mailing_id>");
201
+ console.log(`${mailing.itemsDelivered}/${mailing.itemCount} delivered, ${mailing.itemsReturned} returned`);
202
+
203
+ // Pieces USPS flagged as return-to-sender (filter: none, in_transit,
204
+ // out_for_delivery, forwarded, delivered, returned)
205
+ for await (const item of client.mailings.iterItems(mailing.id, { trackingStatus: "returned" })) {
206
+ console.log(`${item.recipientName}: ${item.lastScanLabel} at ${item.lastScanLocation}`);
207
+ }
208
+
209
+ // Full scan history for one piece
210
+ const page = await client.mailings.listItems(mailing.id, { pageSize: 1 });
211
+ for (const scan of await client.mailings.listItemScans(mailing.id, page.items[0].id)) {
212
+ console.log(` ${scan.scanDatetime} ${scan.label} (${scan.facilityCity}, ${scan.facilityState})`);
213
+ }
214
+ ```
215
+
216
+ Or subscribe to the `mail_delivered` and `mail_returned` webhook events to be pushed these updates instead of polling.
217
+
218
+ ### Use coupon codes in mailings
219
+
220
+ ```ts
221
+ // Create a coupon list and import codes
222
+ const couponList = await client.coupons.create("Spring Sale Coupons");
223
+ const result = await client.coupons.importCodes(couponList.id, ["SAVE10", "SAVE20", "SAVE30"]);
224
+ console.log(`Imported ${result.importedCount} codes`);
225
+
226
+ // Check there are enough codes before sending
227
+ const avail = await client.coupons.checkAvailability(couponList.id, 500);
228
+ if (!avail.sufficient) {
229
+ console.log(`Only ${avail.availableCodes} codes available, need 500`);
230
+ }
231
+
232
+ // Attach to a mailing — each recipient gets a unique code
233
+ const mailing = await client.mailings.create({
234
+ name: "Spring Promo",
235
+ type: "letter",
236
+ contactListId: "<list_id>",
237
+ documentId: "<doc_id>",
238
+ couponListId: couponList.id,
239
+ });
240
+ ```
241
+
242
+ ## Error Handling
243
+
244
+ ```ts
245
+ import { MailerBot, AuthenticationError, NotFoundError, ValidationError, MailerBotError } from "mailerbot";
246
+
247
+ try {
248
+ const client = new MailerBot("bad_key");
249
+ await client.contacts.list();
250
+ } catch (error) {
251
+ if (error instanceof AuthenticationError) {
252
+ console.log(`Auth failed: ${error.message}`);
253
+ } else if (error instanceof NotFoundError) {
254
+ console.log(`Resource not found: ${error.message}`);
255
+ } else if (error instanceof ValidationError) {
256
+ console.log(`Bad request: ${error.message}`, error.response);
257
+ } else if (error instanceof MailerBotError) {
258
+ console.log(`API error ${error.statusCode}: ${error.message}`);
259
+ }
260
+ }
261
+ ```
262
+
263
+ ### Exception hierarchy
264
+
265
+ | Error class | HTTP status |
266
+ |---|---|
267
+ | `AuthenticationError` | 401 |
268
+ | `PermissionError` | 403 |
269
+ | `NotFoundError` | 404 |
270
+ | `ValidationError` | 422 |
271
+ | `RateLimitError` | 429 |
272
+ | `ServerError` | 5xx |
273
+ | `MailerBotError` | base class / other |
274
+
275
+ ## Configuration
276
+
277
+ ```ts
278
+ const client = new MailerBot("mb_live_...", {
279
+ baseUrl: "https://api.mailerbot.com/api/v1", // default
280
+ timeout: 30_000, // milliseconds, default 30000
281
+ });
282
+ ```
283
+
284
+ ## Full API Reference
285
+
286
+ See [https://mailerbot.com/docs](https://mailerbot.com/docs) for complete endpoint documentation.
287
+
288
+ ## License
289
+
290
+ MIT