shipmail 0.2.2 → 0.3.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 CHANGED
@@ -20,6 +20,7 @@ Official TypeScript SDK for the [Shipmail](https://shipmail.to) API. Zero runtim
20
20
  - [Messages](#messages)
21
21
  - [Sandbox](#sandbox)
22
22
  - [Threads](#threads)
23
+ - [Reply scans](#reply-scans)
23
24
  - [Webhooks](#webhooks)
24
25
  - [Suppressions](#suppressions)
25
26
  - [Audiences](#audiences)
@@ -158,8 +159,6 @@ const folder = await shipmail.mailboxes.createFolder("mbx_...", {
158
159
  await shipmail.mailboxes.updateFolder("mbx_...", folder.id, { name: "VIP Clients" });
159
160
  await shipmail.mailboxes.deleteFolder("mbx_...", folder.id);
160
161
  const identities = await shipmail.mailboxes.listIdentities("mbx_...");
161
- const rules = await shipmail.mailboxes.getRules("mbx_...");
162
- await shipmail.mailboxes.updateRules("mbx_...", { rules: rules.rules });
163
162
  await shipmail.mailboxes.updateSpamFilter("mbx_...", { threshold: 8 });
164
163
  await shipmail.mailboxes.delete("mbx_...");
165
164
 
@@ -170,6 +169,26 @@ await shipmail.mailboxes.updateAutoReply("mbx_...", {
170
169
  from_date: "2026-06-01",
171
170
  to_date: "2026-06-07",
172
171
  });
172
+
173
+ const mailboxId = "550e8400-e29b-41d4-a716-446655440000";
174
+ const inbox = await shipmail.mailboxes.listInboxMessages(mailboxId, {
175
+ after: "2025-07-20T00:00:00.000Z",
176
+ before: "2026-07-20T00:00:00.000Z",
177
+ limit: 50,
178
+ });
179
+ const exact = await shipmail.mailboxes.getInboxMessage(mailboxId, inbox.data[0].id);
180
+
181
+ const queue = await shipmail.mailboxes.listInboxThreads(mailboxId, {
182
+ reply_state: "needs_reply",
183
+ after: "2025-07-20T00:00:00.000Z",
184
+ });
185
+ const candidate = queue.data[0];
186
+ const draft = await shipmail.mailboxes.createInboxReplyDraft(mailboxId, candidate.thread_id, {
187
+ text: "Thanks for the note.",
188
+ expected_reply_version: candidate.reply_version,
189
+ });
190
+ // Apply your approval policy before sending. Stale versions fail with 409 without delivery.
191
+ await shipmail.mailboxes.sendInboxReplyDraft(mailboxId, candidate.thread_id, draft.id);
173
192
  ```
174
193
 
175
194
  ## Messages
@@ -195,7 +214,7 @@ await shipmail.messages.reply("msg_...", {
195
214
 
196
215
  ## Sandbox
197
216
 
198
- Create a test API key (`sm_test_...`) to simulate email without contacting real recipients. Test messages, threads, rules, webhooks, quota, suppressions, and reputation are isolated from live mode.
217
+ Create a test API key (`sm_test_...`) to simulate email without contacting real recipients. Test messages, threads, Assistant automations, webhooks, quota, suppressions, and reputation are isolated from live mode.
199
218
 
200
219
  ```ts
201
220
  const testClient = new ShipMailClient("sm_test_...");
@@ -229,6 +248,21 @@ await shipmail.threads.reply(threadId, {
229
248
  });
230
249
  ```
231
250
 
251
+ ## Reply scans
252
+
253
+ Use a durable, atomically captured scan for a historical window. Creation returns a completed
254
+ snapshot; retry a `409` with bounded backoff while historical classification finishes, then follow
255
+ every opaque `next_cursor`; never parse or fabricate cursors. Scans are retained for 30 days.
256
+
257
+ ```ts
258
+ const scan = await shipmail.replyScans.create({
259
+ mailbox_ids: ["550e8400-e29b-41d4-a716-446655440000"],
260
+ after: new Date(Date.now() - 365 * 86_400_000).toISOString(),
261
+ });
262
+ const results = await shipmail.replyScans.listResults(scan.id, { limit: 100 });
263
+ console.log(results.data);
264
+ ```
265
+
232
266
  ## Webhooks
233
267
 
234
268
  ```ts
@@ -261,6 +295,7 @@ message.sent
261
295
  message.delivered
262
296
  message.bounced
263
297
  message.complained
298
+ thread.needs_reply
264
299
  domain.verified
265
300
  domain.verification_failed
266
301
  domain.degraded
@@ -428,6 +463,10 @@ if (page.pagination.has_more) {
428
463
  }
429
464
  ```
430
465
 
466
+ Cursors are opaque and operation-specific. Return them unchanged to the same operation. Inbox and
467
+ reply-queue cursors are bound to their mailbox, time window, sort, and filters; omit those filters on
468
+ later pages or repeat them exactly.
469
+
431
470
  Auto-paginate over all pages:
432
471
 
433
472
  ```ts
package/dist/index.cjs CHANGED
@@ -624,7 +624,9 @@ var Mailboxes = class extends ApiResource {
624
624
  folder_id: params?.folder_id,
625
625
  folder_role: params?.folder_role,
626
626
  search_text: params?.search_text,
627
- position: params?.position,
627
+ cursor: params?.cursor,
628
+ after: params?.after,
629
+ before: params?.before,
628
630
  limit: params?.limit,
629
631
  has_keyword: params?.has_keyword,
630
632
  not_keyword: params?.not_keyword
@@ -632,6 +634,29 @@ var Mailboxes = class extends ApiResource {
632
634
  methodOptions: options
633
635
  });
634
636
  }
637
+ getInboxMessage(id, messageId, options) {
638
+ return this.client.request({
639
+ method: "GET",
640
+ path: `/mailboxes/${encodeURIComponent(id)}/inbox/messages/${encodeURIComponent(messageId)}`,
641
+ methodOptions: options
642
+ });
643
+ }
644
+ listInboxThreads(id, params, options) {
645
+ return this.client.request({
646
+ method: "GET",
647
+ path: `/mailboxes/${encodeURIComponent(id)}/inbox/threads`,
648
+ query: {
649
+ reply_state: params?.reply_state,
650
+ sort_by: params?.sort_by,
651
+ order: params?.order,
652
+ after: params?.after,
653
+ before: params?.before,
654
+ cursor: params?.cursor,
655
+ limit: params?.limit
656
+ },
657
+ methodOptions: options
658
+ });
659
+ }
635
660
  getInboxThread(id, threadId, options) {
636
661
  return this.client.request({
637
662
  method: "GET",
@@ -639,6 +664,29 @@ var Mailboxes = class extends ApiResource {
639
664
  methodOptions: options
640
665
  });
641
666
  }
667
+ updateInboxThreadReplyState(id, threadId, params, options) {
668
+ return this.client.request({
669
+ method: "PATCH",
670
+ path: `/mailboxes/${encodeURIComponent(id)}/inbox/threads/${encodeURIComponent(threadId)}`,
671
+ body: params,
672
+ methodOptions: options
673
+ });
674
+ }
675
+ createInboxReplyDraft(id, threadId, params, options) {
676
+ return this.client.request({
677
+ method: "POST",
678
+ path: `/mailboxes/${encodeURIComponent(id)}/inbox/threads/${encodeURIComponent(threadId)}/drafts`,
679
+ body: params,
680
+ methodOptions: options
681
+ });
682
+ }
683
+ sendInboxReplyDraft(id, threadId, draftId, options) {
684
+ return this.client.request({
685
+ method: "POST",
686
+ path: `/mailboxes/${encodeURIComponent(id)}/inbox/threads/${encodeURIComponent(threadId)}/drafts/${encodeURIComponent(draftId)}/send`,
687
+ methodOptions: options
688
+ });
689
+ }
642
690
  replyToInboxMessage(id, messageId, params, options) {
643
691
  return this.client.request({
644
692
  method: "POST",
@@ -719,21 +767,6 @@ var Mailboxes = class extends ApiResource {
719
767
  methodOptions: options
720
768
  });
721
769
  }
722
- getRules(id, options) {
723
- return this.client.request({
724
- method: "GET",
725
- path: `/mailboxes/${encodeURIComponent(id)}/rules`,
726
- methodOptions: options
727
- });
728
- }
729
- updateRules(id, params, options) {
730
- return this.client.request({
731
- method: "PUT",
732
- path: `/mailboxes/${encodeURIComponent(id)}/rules`,
733
- body: params,
734
- methodOptions: options
735
- });
736
- }
737
770
  listForwarding(id, options) {
738
771
  return this.client.request({
739
772
  method: "GET",
@@ -1097,6 +1130,33 @@ var Partner = class extends ApiResource {
1097
1130
  }
1098
1131
  };
1099
1132
 
1133
+ // src/resources/reply-scans.ts
1134
+ var ReplyScans = class extends ApiResource {
1135
+ create(params, options) {
1136
+ return this.client.request({
1137
+ method: "POST",
1138
+ path: "/reply-scans",
1139
+ body: params,
1140
+ methodOptions: options
1141
+ });
1142
+ }
1143
+ get(id, options) {
1144
+ return this.client.request({
1145
+ method: "GET",
1146
+ path: `/reply-scans/${encodeURIComponent(id)}`,
1147
+ methodOptions: options
1148
+ });
1149
+ }
1150
+ listResults(id, params, options) {
1151
+ return this.client.request({
1152
+ method: "GET",
1153
+ path: `/reply-scans/${encodeURIComponent(id)}/results`,
1154
+ query: { cursor: params?.cursor, limit: params?.limit },
1155
+ methodOptions: options
1156
+ });
1157
+ }
1158
+ };
1159
+
1100
1160
  // src/resources/status.ts
1101
1161
  var Status = class extends ApiResource {
1102
1162
  get(options) {
@@ -1280,7 +1340,7 @@ var Webhooks = class extends ApiResource {
1280
1340
  };
1281
1341
 
1282
1342
  // src/version.ts
1283
- var VERSION = "0.2.2";
1343
+ var VERSION = "0.3.0";
1284
1344
 
1285
1345
  // src/client.ts
1286
1346
  var DEFAULT_BASE_URL = "https://shipmail.to/api/v1";
@@ -1341,6 +1401,7 @@ var ShipMailClient = class {
1341
1401
  this.messages = new Messages(this);
1342
1402
  this.newsletters = new Newsletters(this);
1343
1403
  this.partner = new Partner(this);
1404
+ this.replyScans = new ReplyScans(this);
1344
1405
  this.suppressions = new Suppressions(this);
1345
1406
  this.threads = new Threads(this);
1346
1407
  this.webhooks = new Webhooks(this);
@@ -1451,7 +1512,7 @@ var WEBHOOK_EVENT_TYPES = [
1451
1512
  "message.delivered",
1452
1513
  "message.bounced",
1453
1514
  "message.complained",
1454
- "mailbox.rule_matched",
1515
+ "thread.needs_reply",
1455
1516
  "domain.verified",
1456
1517
  "domain.verification_failed",
1457
1518
  "domain.degraded",
@@ -1473,7 +1534,14 @@ var MESSAGE_STATUSES = [
1473
1534
  "suppressed",
1474
1535
  "cancelled"
1475
1536
  ];
1476
- var MESSAGE_SOURCES = ["api", "newsletter", "dashboard", "inbound", "smtp"];
1537
+ var MESSAGE_SOURCES = [
1538
+ "api",
1539
+ "newsletter",
1540
+ "dashboard",
1541
+ "inbound",
1542
+ "smtp",
1543
+ "assistant"
1544
+ ];
1477
1545
  var WEBHOOK_DELIVERY_STATUSES = ["pending", "delivered", "failed"];
1478
1546
 
1479
1547
  // src/webhook-verification.ts