retransmit.dev 0.1.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 +80 -6
- package/dist/index.cjs +66 -6
- package/dist/index.d.cts +153 -2
- package/dist/index.d.ts +153 -2
- package/dist/index.js +63 -5
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# retransmit.dev
|
|
2
2
|
|
|
3
|
-
Node.js SDK for the [Retransmit](https://retransmit.dev) messaging API. Send email and
|
|
3
|
+
Node.js SDK for the [Retransmit](https://retransmit.dev) messaging API. Send email, SMS, and WhatsApp through one typed client. Zero dependencies, works on Node 18+ and edge runtimes with `fetch`.
|
|
4
4
|
|
|
5
5
|
| Channel | SDK namespace | Availability |
|
|
6
6
|
| --- | --- | --- |
|
|
7
7
|
| Email | `retransmit.emails` | Available |
|
|
8
8
|
| SMS | `retransmit.sms` | Available |
|
|
9
|
-
| WhatsApp | `retransmit.whatsapp` |
|
|
9
|
+
| WhatsApp | `retransmit.whatsapp` | Available |
|
|
10
10
|
|
|
11
11
|
## Install
|
|
12
12
|
|
|
@@ -51,6 +51,57 @@ const { data } = await retransmit.emails.get("em_xxxxxxxxxxxx");
|
|
|
51
51
|
console.log(data?.status); // "delivered"
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
+
### Tags
|
|
55
|
+
|
|
56
|
+
Attach up to 10 `{ name, value }` tags to an email to label it. Filter by
|
|
57
|
+
them in the dashboard or with `emails.list`. Tags come back on `emails.get`
|
|
58
|
+
and are never sent to the recipient.
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
await retransmit.emails.send({
|
|
62
|
+
from: "Acme <hello@yourdomain.com>",
|
|
63
|
+
to: "user@example.com",
|
|
64
|
+
subject: "Your receipt",
|
|
65
|
+
html: "<p>Thanks for your order!</p>",
|
|
66
|
+
tags: [
|
|
67
|
+
{ name: "category", value: "receipt" },
|
|
68
|
+
{ name: "campaign", value: "spring-2026" },
|
|
69
|
+
],
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Names and values allow letters, digits, underscores and dashes, up to 256
|
|
74
|
+
characters each. Names must be unique within one email. Batch emails accept
|
|
75
|
+
the same `tags` field.
|
|
76
|
+
|
|
77
|
+
### List and filter emails
|
|
78
|
+
|
|
79
|
+
`emails.list` returns your emails newest first. Every tag you pass must match.
|
|
80
|
+
Combine with `status` or `batchId`, and page with `cursor`:
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
const { data } = await retransmit.emails.list({
|
|
84
|
+
tags: [{ name: "campaign", value: "spring-2026" }],
|
|
85
|
+
status: "bounced",
|
|
86
|
+
limit: 100,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
for (const email of data!.emails) {
|
|
90
|
+
console.log(email.id, email.to, email.status, email.tags);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (data!.has_more) {
|
|
94
|
+
await retransmit.emails.list({ cursor: data!.next_cursor!, /* same filters */ });
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
To see which tags exist on your account, and how many emails carry each:
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
const { data } = await retransmit.emails.tags();
|
|
102
|
+
// data.tags: [{ name: "campaign", value: "spring-2026", count: 1240 }, ...]
|
|
103
|
+
```
|
|
104
|
+
|
|
54
105
|
## SMS
|
|
55
106
|
|
|
56
107
|
Use international E.164 phone numbers. A single request can contain up to 50
|
|
@@ -93,10 +144,33 @@ console.log(progress?.processed, "/", progress?.total, progress?.counts);
|
|
|
93
144
|
|
|
94
145
|
## WhatsApp
|
|
95
146
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
147
|
+
Connect your WhatsApp Business number in the dashboard first. One recipient
|
|
148
|
+
per request, in E.164 format. Start a conversation with an approved template;
|
|
149
|
+
once the recipient replies you can send free-form text and media for 24 hours.
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
const { data, error } = await retransmit.whatsapp.send({
|
|
153
|
+
to: "+237670000000",
|
|
154
|
+
type: "template",
|
|
155
|
+
template: {
|
|
156
|
+
name: "verification_code",
|
|
157
|
+
language: "en_US",
|
|
158
|
+
components: [{ type: "body", parameters: [{ type: "text", text: "482913" }] }],
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// Inside the 24-hour window:
|
|
163
|
+
await retransmit.whatsapp.send({ to: "+237670000000", text: "Anything else we can help with?" });
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Check the outcome, including `read` receipts:
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
const { data } = await retransmit.whatsapp.get("wa_xxxxxxxxxxxx");
|
|
170
|
+
console.log(data?.status); // "sent" | "delivered" | "read" | "failed"
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Replies from recipients reach you as `whatsapp.received` webhooks.
|
|
100
174
|
|
|
101
175
|
## Error handling
|
|
102
176
|
|
package/dist/index.cjs
CHANGED
|
@@ -25,7 +25,9 @@ __export(index_exports, {
|
|
|
25
25
|
Emails: () => Emails,
|
|
26
26
|
Retransmit: () => Retransmit,
|
|
27
27
|
SMS_STATUSES: () => SMS_STATUSES,
|
|
28
|
-
Sms: () => Sms
|
|
28
|
+
Sms: () => Sms,
|
|
29
|
+
WHATSAPP_STATUSES: () => WHATSAPP_STATUSES,
|
|
30
|
+
Whatsapp: () => Whatsapp
|
|
29
31
|
});
|
|
30
32
|
module.exports = __toCommonJS(index_exports);
|
|
31
33
|
|
|
@@ -40,7 +42,8 @@ function toWirePayload(options) {
|
|
|
40
42
|
subject: options.subject,
|
|
41
43
|
html: options.html,
|
|
42
44
|
text: options.text,
|
|
43
|
-
marketing: options.marketing
|
|
45
|
+
marketing: options.marketing,
|
|
46
|
+
tags: options.tags
|
|
44
47
|
};
|
|
45
48
|
}
|
|
46
49
|
var Emails = class {
|
|
@@ -56,6 +59,23 @@ var Emails = class {
|
|
|
56
59
|
get(id) {
|
|
57
60
|
return this.client.request("GET", `/v1/emails/${encodeURIComponent(id)}`);
|
|
58
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Lists your emails, newest first, optionally filtered by tags, status or
|
|
64
|
+
* batch. Pass `next_cursor` back as `cursor` to page through the results.
|
|
65
|
+
*/
|
|
66
|
+
list(options = {}) {
|
|
67
|
+
return this.client.request("GET", "/v1/emails", void 0, {
|
|
68
|
+
tag: options.tags?.map((tag) => `${tag.name}:${tag.value}`),
|
|
69
|
+
status: options.status,
|
|
70
|
+
batch_id: options.batchId,
|
|
71
|
+
limit: options.limit,
|
|
72
|
+
cursor: options.cursor
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/** Every distinct tag on your emails, with a count of emails carrying it. */
|
|
76
|
+
tags() {
|
|
77
|
+
return this.client.request("GET", "/v1/emails/tags");
|
|
78
|
+
}
|
|
59
79
|
};
|
|
60
80
|
|
|
61
81
|
// src/batch.ts
|
|
@@ -96,15 +116,45 @@ var Sms = class {
|
|
|
96
116
|
}
|
|
97
117
|
};
|
|
98
118
|
|
|
119
|
+
// src/whatsapp.ts
|
|
120
|
+
var Whatsapp = class {
|
|
121
|
+
constructor(client) {
|
|
122
|
+
this.client = client;
|
|
123
|
+
}
|
|
124
|
+
client;
|
|
125
|
+
/**
|
|
126
|
+
* Queues a single WhatsApp message to one recipient. Poll `get(id)` or
|
|
127
|
+
* subscribe to webhooks for the outcome; replies arrive as
|
|
128
|
+
* `whatsapp.received` webhooks.
|
|
129
|
+
*/
|
|
130
|
+
send(options) {
|
|
131
|
+
return this.client.request("POST", "/v1/whatsapp", {
|
|
132
|
+
from: options.from,
|
|
133
|
+
to: options.to,
|
|
134
|
+
type: options.type,
|
|
135
|
+
text: options.text,
|
|
136
|
+
preview_url: options.previewUrl,
|
|
137
|
+
template: options.template,
|
|
138
|
+
image: options.image,
|
|
139
|
+
document: options.document
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
/** Retrieves a WhatsApp message with its current status and event history. */
|
|
143
|
+
get(id) {
|
|
144
|
+
return this.client.request("GET", `/v1/whatsapp/${encodeURIComponent(id)}`);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
99
148
|
// src/retransmit.ts
|
|
100
149
|
var DEFAULT_BASE_URL = "https://api.retransmit.dev";
|
|
101
|
-
var USER_AGENT = "retransmit.dev-node/0.
|
|
150
|
+
var USER_AGENT = "retransmit.dev-node/0.3.0";
|
|
102
151
|
function readEnv(name) {
|
|
103
152
|
return typeof process !== "undefined" ? process.env?.[name] : void 0;
|
|
104
153
|
}
|
|
105
154
|
var Retransmit = class {
|
|
106
155
|
emails = new Emails(this);
|
|
107
156
|
sms = new Sms(this);
|
|
157
|
+
whatsapp = new Whatsapp(this);
|
|
108
158
|
batch = new Batch(this);
|
|
109
159
|
apiKey;
|
|
110
160
|
baseUrl;
|
|
@@ -122,10 +172,17 @@ var Retransmit = class {
|
|
|
122
172
|
);
|
|
123
173
|
}
|
|
124
174
|
/** Internal transport shared by the resource classes. API failures are returned, never thrown. */
|
|
125
|
-
async request(method, path, body) {
|
|
175
|
+
async request(method, path, body, query) {
|
|
176
|
+
const params = new URLSearchParams();
|
|
177
|
+
for (const [key, value] of Object.entries(query ?? {})) {
|
|
178
|
+
if (value === void 0) continue;
|
|
179
|
+
for (const item of Array.isArray(value) ? value : [value]) params.append(key, String(item));
|
|
180
|
+
}
|
|
181
|
+
const encoded = params.toString();
|
|
182
|
+
const search = encoded ? `?${encoded}` : "";
|
|
126
183
|
let response;
|
|
127
184
|
try {
|
|
128
|
-
response = await fetch(`${this.baseUrl}${path}`, {
|
|
185
|
+
response = await fetch(`${this.baseUrl}${path}${search}`, {
|
|
129
186
|
method,
|
|
130
187
|
headers: {
|
|
131
188
|
Authorization: `Bearer ${this.apiKey}`,
|
|
@@ -187,6 +244,7 @@ var SMS_STATUSES = [
|
|
|
187
244
|
"rejected",
|
|
188
245
|
"failed"
|
|
189
246
|
];
|
|
247
|
+
var WHATSAPP_STATUSES = ["queued", "sent", "delivered", "read", "failed"];
|
|
190
248
|
// Annotate the CommonJS export names for ESM import in node:
|
|
191
249
|
0 && (module.exports = {
|
|
192
250
|
Batch,
|
|
@@ -194,5 +252,7 @@ var SMS_STATUSES = [
|
|
|
194
252
|
Emails,
|
|
195
253
|
Retransmit,
|
|
196
254
|
SMS_STATUSES,
|
|
197
|
-
Sms
|
|
255
|
+
Sms,
|
|
256
|
+
WHATSAPP_STATUSES,
|
|
257
|
+
Whatsapp
|
|
198
258
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -39,6 +39,18 @@ interface SendEmailOptions {
|
|
|
39
39
|
* headers, and skips recipients who already unsubscribed.
|
|
40
40
|
*/
|
|
41
41
|
marketing?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Up to 10 labels for filtering emails in the dashboard, for example
|
|
44
|
+
* `[{ name: "campaign", value: "outreach-1" }]`. Names and values allow
|
|
45
|
+
* letters, digits, underscores and dashes, up to 256 characters each.
|
|
46
|
+
* Names must be unique within one email. Tags are returned by `emails.get`
|
|
47
|
+
* and are never sent to the recipient.
|
|
48
|
+
*/
|
|
49
|
+
tags?: EmailTag[];
|
|
50
|
+
}
|
|
51
|
+
interface EmailTag {
|
|
52
|
+
name: string;
|
|
53
|
+
value: string;
|
|
42
54
|
}
|
|
43
55
|
interface SendEmailResponse {
|
|
44
56
|
id: string;
|
|
@@ -59,12 +71,55 @@ interface GetEmailResponse {
|
|
|
59
71
|
reply_to: string[] | null;
|
|
60
72
|
subject: string;
|
|
61
73
|
marketing: boolean;
|
|
74
|
+
tags: EmailTag[];
|
|
62
75
|
status: EmailStatus;
|
|
63
76
|
error: string | null;
|
|
64
77
|
created_at: string;
|
|
65
78
|
last_event_at: string | null;
|
|
66
79
|
events: EmailEvent[];
|
|
67
80
|
}
|
|
81
|
+
interface ListEmailsOptions {
|
|
82
|
+
/**
|
|
83
|
+
* Only emails carrying every one of these tags, for example
|
|
84
|
+
* `[{ name: "campaign", value: "outreach-1" }]`.
|
|
85
|
+
*/
|
|
86
|
+
tags?: EmailTag[];
|
|
87
|
+
status?: EmailStatus;
|
|
88
|
+
/** Only emails sent as part of this batch. */
|
|
89
|
+
batchId?: string;
|
|
90
|
+
/** Page size, 1 to 100. Defaults to 50. */
|
|
91
|
+
limit?: number;
|
|
92
|
+
/** `next_cursor` from the previous page. */
|
|
93
|
+
cursor?: string;
|
|
94
|
+
}
|
|
95
|
+
/** One row of `emails.list`. Call `emails.get(id)` for the event history. */
|
|
96
|
+
interface EmailSummary {
|
|
97
|
+
id: string;
|
|
98
|
+
batch_id: string | null;
|
|
99
|
+
from: string;
|
|
100
|
+
to: string[];
|
|
101
|
+
subject: string;
|
|
102
|
+
marketing: boolean;
|
|
103
|
+
tags: EmailTag[];
|
|
104
|
+
status: EmailStatus;
|
|
105
|
+
error: string | null;
|
|
106
|
+
created_at: string;
|
|
107
|
+
last_event_at: string | null;
|
|
108
|
+
}
|
|
109
|
+
interface ListEmailsResponse {
|
|
110
|
+
/** Newest first. */
|
|
111
|
+
emails: EmailSummary[];
|
|
112
|
+
has_more: boolean;
|
|
113
|
+
/** Pass back as `cursor` to fetch the next page. `null` on the last page. */
|
|
114
|
+
next_cursor: string | null;
|
|
115
|
+
}
|
|
116
|
+
interface EmailTagCount extends EmailTag {
|
|
117
|
+
/** How many of your emails carry this tag. */
|
|
118
|
+
count: number;
|
|
119
|
+
}
|
|
120
|
+
interface ListEmailTagsResponse {
|
|
121
|
+
tags: EmailTagCount[];
|
|
122
|
+
}
|
|
68
123
|
declare const SMS_STATUSES: readonly ["queued", "sent", "delivered", "undelivered", "expired", "rejected", "failed"];
|
|
69
124
|
type SmsStatus = (typeof SMS_STATUSES)[number];
|
|
70
125
|
interface SendSmsOptions {
|
|
@@ -106,6 +161,81 @@ interface GetSmsResponse {
|
|
|
106
161
|
last_event_at: string | null;
|
|
107
162
|
events: SmsEvent[];
|
|
108
163
|
}
|
|
164
|
+
declare const WHATSAPP_STATUSES: readonly ["queued", "sent", "delivered", "read", "failed"];
|
|
165
|
+
type WhatsappStatus = (typeof WHATSAPP_STATUSES)[number];
|
|
166
|
+
type WhatsappMessageType = "text" | "template" | "image" | "document";
|
|
167
|
+
interface WhatsappTemplate {
|
|
168
|
+
/** Template name as approved in WhatsApp Manager. */
|
|
169
|
+
name: string;
|
|
170
|
+
/** Language code the template was approved for, e.g. `en_US`. */
|
|
171
|
+
language: string;
|
|
172
|
+
/** Meta `components` (header/body/button parameters), passed through verbatim. */
|
|
173
|
+
components?: Record<string, unknown>[];
|
|
174
|
+
}
|
|
175
|
+
interface WhatsappMedia {
|
|
176
|
+
/** Public HTTPS link fetched at send time. */
|
|
177
|
+
link: string;
|
|
178
|
+
caption?: string;
|
|
179
|
+
}
|
|
180
|
+
interface WhatsappDocument extends WhatsappMedia {
|
|
181
|
+
/** File name shown to the recipient. */
|
|
182
|
+
filename?: string;
|
|
183
|
+
}
|
|
184
|
+
interface SendWhatsappOptions {
|
|
185
|
+
/**
|
|
186
|
+
* Connected number to send from, in international format. Optional when
|
|
187
|
+
* your organization has a single WhatsApp number.
|
|
188
|
+
*/
|
|
189
|
+
from?: string;
|
|
190
|
+
/** One recipient in international format (`+237670000000`). */
|
|
191
|
+
to: string;
|
|
192
|
+
/** Defaults to `text`. */
|
|
193
|
+
type?: WhatsappMessageType;
|
|
194
|
+
/** Body for `text` messages (up to 4,096 characters), or a media caption. */
|
|
195
|
+
text?: string;
|
|
196
|
+
/** Render a preview for the first link in a `text` message. */
|
|
197
|
+
previewUrl?: boolean;
|
|
198
|
+
/** Required for `type: "template"`. Needed to start a conversation outside the 24h window. */
|
|
199
|
+
template?: WhatsappTemplate;
|
|
200
|
+
/** Required for `type: "image"`. */
|
|
201
|
+
image?: WhatsappMedia;
|
|
202
|
+
/** Required for `type: "document"`. */
|
|
203
|
+
document?: WhatsappDocument;
|
|
204
|
+
}
|
|
205
|
+
interface SendWhatsappResponse {
|
|
206
|
+
id: string;
|
|
207
|
+
status: "queued";
|
|
208
|
+
type: WhatsappMessageType;
|
|
209
|
+
/** The connected number the message goes out from. */
|
|
210
|
+
from: string;
|
|
211
|
+
/** ISO 3166-1 alpha-2 destination country detected from the number prefix. */
|
|
212
|
+
country: string | null;
|
|
213
|
+
created_at: string;
|
|
214
|
+
}
|
|
215
|
+
interface WhatsappEvent {
|
|
216
|
+
type: string;
|
|
217
|
+
created_at: string;
|
|
218
|
+
}
|
|
219
|
+
interface GetWhatsappResponse {
|
|
220
|
+
id: string;
|
|
221
|
+
from: string;
|
|
222
|
+
to: string;
|
|
223
|
+
country: string | null;
|
|
224
|
+
type: WhatsappMessageType;
|
|
225
|
+
text: string | null;
|
|
226
|
+
preview_url: boolean;
|
|
227
|
+
template: WhatsappTemplate | null;
|
|
228
|
+
media: WhatsappDocument | null;
|
|
229
|
+
/** Upstream provider that carried the message, e.g. `meta`. */
|
|
230
|
+
provider: string | null;
|
|
231
|
+
/** Provider-side message id (`wamid.…` on Meta); inbound replies reference it. */
|
|
232
|
+
provider_message_id: string | null;
|
|
233
|
+
status: WhatsappStatus;
|
|
234
|
+
error: string | null;
|
|
235
|
+
created_at: string;
|
|
236
|
+
last_event_at: string | null;
|
|
237
|
+
events: WhatsappEvent[];
|
|
238
|
+
}
|
|
109
239
|
interface SendBatchResponse {
|
|
110
240
|
id: string;
|
|
111
241
|
total: number;
|
|
@@ -138,6 +268,13 @@ declare class Emails {
|
|
|
138
268
|
send(options: SendEmailOptions): Promise<Result<SendEmailResponse>>;
|
|
139
269
|
/** Retrieves an email with its current status and event history. */
|
|
140
270
|
get(id: string): Promise<Result<GetEmailResponse>>;
|
|
271
|
+
/**
|
|
272
|
+
* Lists your emails, newest first, optionally filtered by tags, status or
|
|
273
|
+
* batch. Pass `next_cursor` back as `cursor` to page through the results.
|
|
274
|
+
*/
|
|
275
|
+
list(options?: ListEmailsOptions): Promise<Result<ListEmailsResponse>>;
|
|
276
|
+
/** Every distinct tag on your emails, with a count of emails carrying it. */
|
|
277
|
+
tags(): Promise<Result<ListEmailTagsResponse>>;
|
|
141
278
|
}
|
|
142
279
|
|
|
143
280
|
declare class Sms {
|
|
@@ -149,15 +286,29 @@ declare class Sms {
|
|
|
149
286
|
get(id: string): Promise<Result<GetSmsResponse>>;
|
|
150
287
|
}
|
|
151
288
|
|
|
289
|
+
declare class Whatsapp {
|
|
290
|
+
private readonly client;
|
|
291
|
+
constructor(client: Retransmit);
|
|
292
|
+
/**
|
|
293
|
+
* Queues a single WhatsApp message to one recipient. Poll `get(id)` or
|
|
294
|
+
* subscribe to webhooks for the outcome; replies arrive as
|
|
295
|
+
* `whatsapp.received` webhooks.
|
|
296
|
+
*/
|
|
297
|
+
send(options: SendWhatsappOptions): Promise<Result<SendWhatsappResponse>>;
|
|
298
|
+
/** Retrieves a WhatsApp message with its current status and event history. */
|
|
299
|
+
get(id: string): Promise<Result<GetWhatsappResponse>>;
|
|
300
|
+
}
|
|
301
|
+
|
|
152
302
|
declare class Retransmit {
|
|
153
303
|
readonly emails: Emails;
|
|
154
304
|
readonly sms: Sms;
|
|
305
|
+
readonly whatsapp: Whatsapp;
|
|
155
306
|
readonly batch: Batch;
|
|
156
307
|
private readonly apiKey;
|
|
157
308
|
private readonly baseUrl;
|
|
158
309
|
constructor(apiKey?: string, options?: RetransmitOptions);
|
|
159
310
|
/** Internal transport shared by the resource classes. API failures are returned, never thrown. */
|
|
160
|
-
request<T>(method: "GET" | "POST", path: string, body?: unknown): Promise<Result<T>>;
|
|
311
|
+
request<T>(method: "GET" | "POST", path: string, body?: unknown, query?: Record<string, string | number | string[] | undefined>): Promise<Result<T>>;
|
|
161
312
|
}
|
|
162
313
|
|
|
163
|
-
export { Batch, EMAIL_STATUSES, type EmailEvent, type EmailStatus, Emails, type GetBatchResponse, type GetEmailResponse, type GetSmsResponse, type Result, Retransmit, type RetransmitError, type RetransmitOptions, SMS_STATUSES, type SendBatchResponse, type SendEmailOptions, type SendEmailResponse, type SendSmsOptions, type SendSmsResponse, Sms, type SmsEvent, type SmsStatus };
|
|
314
|
+
export { Batch, EMAIL_STATUSES, type EmailEvent, type EmailStatus, type EmailSummary, type EmailTag, type EmailTagCount, Emails, type GetBatchResponse, type GetEmailResponse, type GetSmsResponse, type GetWhatsappResponse, type ListEmailTagsResponse, type ListEmailsOptions, type ListEmailsResponse, type Result, Retransmit, type RetransmitError, type RetransmitOptions, SMS_STATUSES, type SendBatchResponse, type SendEmailOptions, type SendEmailResponse, type SendSmsOptions, type SendSmsResponse, type SendWhatsappOptions, type SendWhatsappResponse, Sms, type SmsEvent, type SmsStatus, WHATSAPP_STATUSES, Whatsapp, type WhatsappDocument, type WhatsappEvent, type WhatsappMedia, type WhatsappMessageType, type WhatsappStatus, type WhatsappTemplate };
|
package/dist/index.d.ts
CHANGED
|
@@ -39,6 +39,18 @@ interface SendEmailOptions {
|
|
|
39
39
|
* headers, and skips recipients who already unsubscribed.
|
|
40
40
|
*/
|
|
41
41
|
marketing?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Up to 10 labels for filtering emails in the dashboard, for example
|
|
44
|
+
* `[{ name: "campaign", value: "outreach-1" }]`. Names and values allow
|
|
45
|
+
* letters, digits, underscores and dashes, up to 256 characters each.
|
|
46
|
+
* Names must be unique within one email. Tags are returned by `emails.get`
|
|
47
|
+
* and are never sent to the recipient.
|
|
48
|
+
*/
|
|
49
|
+
tags?: EmailTag[];
|
|
50
|
+
}
|
|
51
|
+
interface EmailTag {
|
|
52
|
+
name: string;
|
|
53
|
+
value: string;
|
|
42
54
|
}
|
|
43
55
|
interface SendEmailResponse {
|
|
44
56
|
id: string;
|
|
@@ -59,12 +71,55 @@ interface GetEmailResponse {
|
|
|
59
71
|
reply_to: string[] | null;
|
|
60
72
|
subject: string;
|
|
61
73
|
marketing: boolean;
|
|
74
|
+
tags: EmailTag[];
|
|
62
75
|
status: EmailStatus;
|
|
63
76
|
error: string | null;
|
|
64
77
|
created_at: string;
|
|
65
78
|
last_event_at: string | null;
|
|
66
79
|
events: EmailEvent[];
|
|
67
80
|
}
|
|
81
|
+
interface ListEmailsOptions {
|
|
82
|
+
/**
|
|
83
|
+
* Only emails carrying every one of these tags, for example
|
|
84
|
+
* `[{ name: "campaign", value: "outreach-1" }]`.
|
|
85
|
+
*/
|
|
86
|
+
tags?: EmailTag[];
|
|
87
|
+
status?: EmailStatus;
|
|
88
|
+
/** Only emails sent as part of this batch. */
|
|
89
|
+
batchId?: string;
|
|
90
|
+
/** Page size, 1 to 100. Defaults to 50. */
|
|
91
|
+
limit?: number;
|
|
92
|
+
/** `next_cursor` from the previous page. */
|
|
93
|
+
cursor?: string;
|
|
94
|
+
}
|
|
95
|
+
/** One row of `emails.list`. Call `emails.get(id)` for the event history. */
|
|
96
|
+
interface EmailSummary {
|
|
97
|
+
id: string;
|
|
98
|
+
batch_id: string | null;
|
|
99
|
+
from: string;
|
|
100
|
+
to: string[];
|
|
101
|
+
subject: string;
|
|
102
|
+
marketing: boolean;
|
|
103
|
+
tags: EmailTag[];
|
|
104
|
+
status: EmailStatus;
|
|
105
|
+
error: string | null;
|
|
106
|
+
created_at: string;
|
|
107
|
+
last_event_at: string | null;
|
|
108
|
+
}
|
|
109
|
+
interface ListEmailsResponse {
|
|
110
|
+
/** Newest first. */
|
|
111
|
+
emails: EmailSummary[];
|
|
112
|
+
has_more: boolean;
|
|
113
|
+
/** Pass back as `cursor` to fetch the next page. `null` on the last page. */
|
|
114
|
+
next_cursor: string | null;
|
|
115
|
+
}
|
|
116
|
+
interface EmailTagCount extends EmailTag {
|
|
117
|
+
/** How many of your emails carry this tag. */
|
|
118
|
+
count: number;
|
|
119
|
+
}
|
|
120
|
+
interface ListEmailTagsResponse {
|
|
121
|
+
tags: EmailTagCount[];
|
|
122
|
+
}
|
|
68
123
|
declare const SMS_STATUSES: readonly ["queued", "sent", "delivered", "undelivered", "expired", "rejected", "failed"];
|
|
69
124
|
type SmsStatus = (typeof SMS_STATUSES)[number];
|
|
70
125
|
interface SendSmsOptions {
|
|
@@ -106,6 +161,81 @@ interface GetSmsResponse {
|
|
|
106
161
|
last_event_at: string | null;
|
|
107
162
|
events: SmsEvent[];
|
|
108
163
|
}
|
|
164
|
+
declare const WHATSAPP_STATUSES: readonly ["queued", "sent", "delivered", "read", "failed"];
|
|
165
|
+
type WhatsappStatus = (typeof WHATSAPP_STATUSES)[number];
|
|
166
|
+
type WhatsappMessageType = "text" | "template" | "image" | "document";
|
|
167
|
+
interface WhatsappTemplate {
|
|
168
|
+
/** Template name as approved in WhatsApp Manager. */
|
|
169
|
+
name: string;
|
|
170
|
+
/** Language code the template was approved for, e.g. `en_US`. */
|
|
171
|
+
language: string;
|
|
172
|
+
/** Meta `components` (header/body/button parameters), passed through verbatim. */
|
|
173
|
+
components?: Record<string, unknown>[];
|
|
174
|
+
}
|
|
175
|
+
interface WhatsappMedia {
|
|
176
|
+
/** Public HTTPS link fetched at send time. */
|
|
177
|
+
link: string;
|
|
178
|
+
caption?: string;
|
|
179
|
+
}
|
|
180
|
+
interface WhatsappDocument extends WhatsappMedia {
|
|
181
|
+
/** File name shown to the recipient. */
|
|
182
|
+
filename?: string;
|
|
183
|
+
}
|
|
184
|
+
interface SendWhatsappOptions {
|
|
185
|
+
/**
|
|
186
|
+
* Connected number to send from, in international format. Optional when
|
|
187
|
+
* your organization has a single WhatsApp number.
|
|
188
|
+
*/
|
|
189
|
+
from?: string;
|
|
190
|
+
/** One recipient in international format (`+237670000000`). */
|
|
191
|
+
to: string;
|
|
192
|
+
/** Defaults to `text`. */
|
|
193
|
+
type?: WhatsappMessageType;
|
|
194
|
+
/** Body for `text` messages (up to 4,096 characters), or a media caption. */
|
|
195
|
+
text?: string;
|
|
196
|
+
/** Render a preview for the first link in a `text` message. */
|
|
197
|
+
previewUrl?: boolean;
|
|
198
|
+
/** Required for `type: "template"`. Needed to start a conversation outside the 24h window. */
|
|
199
|
+
template?: WhatsappTemplate;
|
|
200
|
+
/** Required for `type: "image"`. */
|
|
201
|
+
image?: WhatsappMedia;
|
|
202
|
+
/** Required for `type: "document"`. */
|
|
203
|
+
document?: WhatsappDocument;
|
|
204
|
+
}
|
|
205
|
+
interface SendWhatsappResponse {
|
|
206
|
+
id: string;
|
|
207
|
+
status: "queued";
|
|
208
|
+
type: WhatsappMessageType;
|
|
209
|
+
/** The connected number the message goes out from. */
|
|
210
|
+
from: string;
|
|
211
|
+
/** ISO 3166-1 alpha-2 destination country detected from the number prefix. */
|
|
212
|
+
country: string | null;
|
|
213
|
+
created_at: string;
|
|
214
|
+
}
|
|
215
|
+
interface WhatsappEvent {
|
|
216
|
+
type: string;
|
|
217
|
+
created_at: string;
|
|
218
|
+
}
|
|
219
|
+
interface GetWhatsappResponse {
|
|
220
|
+
id: string;
|
|
221
|
+
from: string;
|
|
222
|
+
to: string;
|
|
223
|
+
country: string | null;
|
|
224
|
+
type: WhatsappMessageType;
|
|
225
|
+
text: string | null;
|
|
226
|
+
preview_url: boolean;
|
|
227
|
+
template: WhatsappTemplate | null;
|
|
228
|
+
media: WhatsappDocument | null;
|
|
229
|
+
/** Upstream provider that carried the message, e.g. `meta`. */
|
|
230
|
+
provider: string | null;
|
|
231
|
+
/** Provider-side message id (`wamid.…` on Meta); inbound replies reference it. */
|
|
232
|
+
provider_message_id: string | null;
|
|
233
|
+
status: WhatsappStatus;
|
|
234
|
+
error: string | null;
|
|
235
|
+
created_at: string;
|
|
236
|
+
last_event_at: string | null;
|
|
237
|
+
events: WhatsappEvent[];
|
|
238
|
+
}
|
|
109
239
|
interface SendBatchResponse {
|
|
110
240
|
id: string;
|
|
111
241
|
total: number;
|
|
@@ -138,6 +268,13 @@ declare class Emails {
|
|
|
138
268
|
send(options: SendEmailOptions): Promise<Result<SendEmailResponse>>;
|
|
139
269
|
/** Retrieves an email with its current status and event history. */
|
|
140
270
|
get(id: string): Promise<Result<GetEmailResponse>>;
|
|
271
|
+
/**
|
|
272
|
+
* Lists your emails, newest first, optionally filtered by tags, status or
|
|
273
|
+
* batch. Pass `next_cursor` back as `cursor` to page through the results.
|
|
274
|
+
*/
|
|
275
|
+
list(options?: ListEmailsOptions): Promise<Result<ListEmailsResponse>>;
|
|
276
|
+
/** Every distinct tag on your emails, with a count of emails carrying it. */
|
|
277
|
+
tags(): Promise<Result<ListEmailTagsResponse>>;
|
|
141
278
|
}
|
|
142
279
|
|
|
143
280
|
declare class Sms {
|
|
@@ -149,15 +286,29 @@ declare class Sms {
|
|
|
149
286
|
get(id: string): Promise<Result<GetSmsResponse>>;
|
|
150
287
|
}
|
|
151
288
|
|
|
289
|
+
declare class Whatsapp {
|
|
290
|
+
private readonly client;
|
|
291
|
+
constructor(client: Retransmit);
|
|
292
|
+
/**
|
|
293
|
+
* Queues a single WhatsApp message to one recipient. Poll `get(id)` or
|
|
294
|
+
* subscribe to webhooks for the outcome; replies arrive as
|
|
295
|
+
* `whatsapp.received` webhooks.
|
|
296
|
+
*/
|
|
297
|
+
send(options: SendWhatsappOptions): Promise<Result<SendWhatsappResponse>>;
|
|
298
|
+
/** Retrieves a WhatsApp message with its current status and event history. */
|
|
299
|
+
get(id: string): Promise<Result<GetWhatsappResponse>>;
|
|
300
|
+
}
|
|
301
|
+
|
|
152
302
|
declare class Retransmit {
|
|
153
303
|
readonly emails: Emails;
|
|
154
304
|
readonly sms: Sms;
|
|
305
|
+
readonly whatsapp: Whatsapp;
|
|
155
306
|
readonly batch: Batch;
|
|
156
307
|
private readonly apiKey;
|
|
157
308
|
private readonly baseUrl;
|
|
158
309
|
constructor(apiKey?: string, options?: RetransmitOptions);
|
|
159
310
|
/** Internal transport shared by the resource classes. API failures are returned, never thrown. */
|
|
160
|
-
request<T>(method: "GET" | "POST", path: string, body?: unknown): Promise<Result<T>>;
|
|
311
|
+
request<T>(method: "GET" | "POST", path: string, body?: unknown, query?: Record<string, string | number | string[] | undefined>): Promise<Result<T>>;
|
|
161
312
|
}
|
|
162
313
|
|
|
163
|
-
export { Batch, EMAIL_STATUSES, type EmailEvent, type EmailStatus, Emails, type GetBatchResponse, type GetEmailResponse, type GetSmsResponse, type Result, Retransmit, type RetransmitError, type RetransmitOptions, SMS_STATUSES, type SendBatchResponse, type SendEmailOptions, type SendEmailResponse, type SendSmsOptions, type SendSmsResponse, Sms, type SmsEvent, type SmsStatus };
|
|
314
|
+
export { Batch, EMAIL_STATUSES, type EmailEvent, type EmailStatus, type EmailSummary, type EmailTag, type EmailTagCount, Emails, type GetBatchResponse, type GetEmailResponse, type GetSmsResponse, type GetWhatsappResponse, type ListEmailTagsResponse, type ListEmailsOptions, type ListEmailsResponse, type Result, Retransmit, type RetransmitError, type RetransmitOptions, SMS_STATUSES, type SendBatchResponse, type SendEmailOptions, type SendEmailResponse, type SendSmsOptions, type SendSmsResponse, type SendWhatsappOptions, type SendWhatsappResponse, Sms, type SmsEvent, type SmsStatus, WHATSAPP_STATUSES, Whatsapp, type WhatsappDocument, type WhatsappEvent, type WhatsappMedia, type WhatsappMessageType, type WhatsappStatus, type WhatsappTemplate };
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,8 @@ function toWirePayload(options) {
|
|
|
9
9
|
subject: options.subject,
|
|
10
10
|
html: options.html,
|
|
11
11
|
text: options.text,
|
|
12
|
-
marketing: options.marketing
|
|
12
|
+
marketing: options.marketing,
|
|
13
|
+
tags: options.tags
|
|
13
14
|
};
|
|
14
15
|
}
|
|
15
16
|
var Emails = class {
|
|
@@ -25,6 +26,23 @@ var Emails = class {
|
|
|
25
26
|
get(id) {
|
|
26
27
|
return this.client.request("GET", `/v1/emails/${encodeURIComponent(id)}`);
|
|
27
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Lists your emails, newest first, optionally filtered by tags, status or
|
|
31
|
+
* batch. Pass `next_cursor` back as `cursor` to page through the results.
|
|
32
|
+
*/
|
|
33
|
+
list(options = {}) {
|
|
34
|
+
return this.client.request("GET", "/v1/emails", void 0, {
|
|
35
|
+
tag: options.tags?.map((tag) => `${tag.name}:${tag.value}`),
|
|
36
|
+
status: options.status,
|
|
37
|
+
batch_id: options.batchId,
|
|
38
|
+
limit: options.limit,
|
|
39
|
+
cursor: options.cursor
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/** Every distinct tag on your emails, with a count of emails carrying it. */
|
|
43
|
+
tags() {
|
|
44
|
+
return this.client.request("GET", "/v1/emails/tags");
|
|
45
|
+
}
|
|
28
46
|
};
|
|
29
47
|
|
|
30
48
|
// src/batch.ts
|
|
@@ -65,15 +83,45 @@ var Sms = class {
|
|
|
65
83
|
}
|
|
66
84
|
};
|
|
67
85
|
|
|
86
|
+
// src/whatsapp.ts
|
|
87
|
+
var Whatsapp = class {
|
|
88
|
+
constructor(client) {
|
|
89
|
+
this.client = client;
|
|
90
|
+
}
|
|
91
|
+
client;
|
|
92
|
+
/**
|
|
93
|
+
* Queues a single WhatsApp message to one recipient. Poll `get(id)` or
|
|
94
|
+
* subscribe to webhooks for the outcome; replies arrive as
|
|
95
|
+
* `whatsapp.received` webhooks.
|
|
96
|
+
*/
|
|
97
|
+
send(options) {
|
|
98
|
+
return this.client.request("POST", "/v1/whatsapp", {
|
|
99
|
+
from: options.from,
|
|
100
|
+
to: options.to,
|
|
101
|
+
type: options.type,
|
|
102
|
+
text: options.text,
|
|
103
|
+
preview_url: options.previewUrl,
|
|
104
|
+
template: options.template,
|
|
105
|
+
image: options.image,
|
|
106
|
+
document: options.document
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/** Retrieves a WhatsApp message with its current status and event history. */
|
|
110
|
+
get(id) {
|
|
111
|
+
return this.client.request("GET", `/v1/whatsapp/${encodeURIComponent(id)}`);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
|
|
68
115
|
// src/retransmit.ts
|
|
69
116
|
var DEFAULT_BASE_URL = "https://api.retransmit.dev";
|
|
70
|
-
var USER_AGENT = "retransmit.dev-node/0.
|
|
117
|
+
var USER_AGENT = "retransmit.dev-node/0.3.0";
|
|
71
118
|
function readEnv(name) {
|
|
72
119
|
return typeof process !== "undefined" ? process.env?.[name] : void 0;
|
|
73
120
|
}
|
|
74
121
|
var Retransmit = class {
|
|
75
122
|
emails = new Emails(this);
|
|
76
123
|
sms = new Sms(this);
|
|
124
|
+
whatsapp = new Whatsapp(this);
|
|
77
125
|
batch = new Batch(this);
|
|
78
126
|
apiKey;
|
|
79
127
|
baseUrl;
|
|
@@ -91,10 +139,17 @@ var Retransmit = class {
|
|
|
91
139
|
);
|
|
92
140
|
}
|
|
93
141
|
/** Internal transport shared by the resource classes. API failures are returned, never thrown. */
|
|
94
|
-
async request(method, path, body) {
|
|
142
|
+
async request(method, path, body, query) {
|
|
143
|
+
const params = new URLSearchParams();
|
|
144
|
+
for (const [key, value] of Object.entries(query ?? {})) {
|
|
145
|
+
if (value === void 0) continue;
|
|
146
|
+
for (const item of Array.isArray(value) ? value : [value]) params.append(key, String(item));
|
|
147
|
+
}
|
|
148
|
+
const encoded = params.toString();
|
|
149
|
+
const search = encoded ? `?${encoded}` : "";
|
|
95
150
|
let response;
|
|
96
151
|
try {
|
|
97
|
-
response = await fetch(`${this.baseUrl}${path}`, {
|
|
152
|
+
response = await fetch(`${this.baseUrl}${path}${search}`, {
|
|
98
153
|
method,
|
|
99
154
|
headers: {
|
|
100
155
|
Authorization: `Bearer ${this.apiKey}`,
|
|
@@ -156,11 +211,14 @@ var SMS_STATUSES = [
|
|
|
156
211
|
"rejected",
|
|
157
212
|
"failed"
|
|
158
213
|
];
|
|
214
|
+
var WHATSAPP_STATUSES = ["queued", "sent", "delivered", "read", "failed"];
|
|
159
215
|
export {
|
|
160
216
|
Batch,
|
|
161
217
|
EMAIL_STATUSES,
|
|
162
218
|
Emails,
|
|
163
219
|
Retransmit,
|
|
164
220
|
SMS_STATUSES,
|
|
165
|
-
Sms
|
|
221
|
+
Sms,
|
|
222
|
+
WHATSAPP_STATUSES,
|
|
223
|
+
Whatsapp
|
|
166
224
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "retransmit.dev",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Node.js SDK for the Retransmit email and
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Node.js SDK for the Retransmit email, SMS and WhatsApp APIs",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"email",
|
|
7
7
|
"sms",
|
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
"retransmit",
|
|
10
10
|
"ses",
|
|
11
11
|
"transactional-email",
|
|
12
|
-
"transactional-sms"
|
|
12
|
+
"transactional-sms",
|
|
13
|
+
"whatsapp",
|
|
14
|
+
"whatsapp-cloud-api"
|
|
13
15
|
],
|
|
14
16
|
"homepage": "https://docs.retransmit.dev",
|
|
15
17
|
"repository": {
|