@tozielinski/next-brevo-api-helper 1.0.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/LICENSE +21 -0
- package/README.md +10 -0
- package/dist/brevo-client.d.ts +59 -0
- package/dist/brevo-client.d.ts.map +1 -0
- package/dist/brevo-client.js +265 -0
- package/dist/brevo.d.ts +358 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/package.json +41 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Torsten Zielinski
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# next-brevo-api-helper
|
|
2
|
+
[](https://opensource.org/licenses/MIT)
|
|
3
|
+
|
|
4
|
+
## Using the Brevo API for create, update and delete contacts, folders and lists and send mails via the API
|
|
5
|
+
|
|
6
|
+
# Quick Start
|
|
7
|
+
### Install the package:
|
|
8
|
+
```bash
|
|
9
|
+
npm install @tozielinski/next-brevo-api-helper
|
|
10
|
+
```
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { BrevoApiResponse, BrevoStatus, BrevoContact, BrevoCreateContactRequest, BrevoCreateContactResponse, BrevoGetContactResponse, BrevoSendEmailRequest, BrevoSendEmailResponse, BrevoSendSmsRequest, BrevoSendSmsResponse, BrevoList, BrevoCreateListRequest, BrevoCreateListResponse, BrevoGetListsResponse, BrevoUpdateListRequest, BrevoDeleteListRequest, BrevoAddContactsToListRequest, BrevoAddContactsToListResponse, BrevoFolder, BrevoCreateFolderRequest, BrevoCreateFolderResponse, BrevoGetFolderRequest, BrevoGetFoldersResponse, BrevoUpdateFolderRequest, BrevoDeleteFolderRequest } from "./brevo";
|
|
2
|
+
/**
|
|
3
|
+
* Create a fabric for brevoFetch with API key preconfigured
|
|
4
|
+
* @param baseUrl
|
|
5
|
+
* @param apiKey
|
|
6
|
+
*/
|
|
7
|
+
export declare function createBrevoFetcher(baseUrl: string, apiKey: string): <T>(endpoint: string, options?: RequestInit) => Promise<BrevoApiResponse<T>>;
|
|
8
|
+
/**
|
|
9
|
+
* Configuration for BrevoClient, when Toke is not available in environment
|
|
10
|
+
*/
|
|
11
|
+
export interface BrevoClientConfig {
|
|
12
|
+
apiKey?: string;
|
|
13
|
+
baseUrl?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* BrevoClient – typed wrapper for Brevo REST API v3
|
|
17
|
+
*/
|
|
18
|
+
export declare class BrevoClient {
|
|
19
|
+
private brevoFetcher;
|
|
20
|
+
constructor(config?: BrevoClientConfig);
|
|
21
|
+
/** Create or update a contact */
|
|
22
|
+
createContact(contact: BrevoCreateContactRequest): Promise<BrevoApiResponse<BrevoCreateContactResponse>>;
|
|
23
|
+
/** Get contact by email or ID */
|
|
24
|
+
getContact(identifier: string | number): Promise<BrevoApiResponse<BrevoGetContactResponse>>;
|
|
25
|
+
/** Delete a contact */
|
|
26
|
+
deleteContact(identifier: string | number): Promise<BrevoApiResponse<null>>;
|
|
27
|
+
/** Get all lists */
|
|
28
|
+
getLists(): Promise<BrevoApiResponse<BrevoGetListsResponse>>;
|
|
29
|
+
/** Get lists of a folder */
|
|
30
|
+
getListContacts(listId: number): Promise<BrevoApiResponse<BrevoContact[]>>;
|
|
31
|
+
/** Get list details */
|
|
32
|
+
getListDetails(listId: number): Promise<BrevoApiResponse<BrevoList>>;
|
|
33
|
+
/** Create a new list */
|
|
34
|
+
createList(list: BrevoCreateListRequest): Promise<BrevoApiResponse<BrevoCreateListResponse>>;
|
|
35
|
+
updateList(req: BrevoUpdateListRequest): Promise<BrevoApiResponse<BrevoStatus>>;
|
|
36
|
+
/** Delete a list */
|
|
37
|
+
deleteList(req: BrevoDeleteListRequest): Promise<BrevoApiResponse<BrevoStatus>>;
|
|
38
|
+
/** Add existing contacts to a list */
|
|
39
|
+
addContactsToList(req: BrevoAddContactsToListRequest): Promise<BrevoApiResponse<BrevoAddContactsToListResponse>>;
|
|
40
|
+
/** Get all folders */
|
|
41
|
+
getFolders(): Promise<BrevoApiResponse<BrevoGetFoldersResponse>>;
|
|
42
|
+
/** Get lists of a folder */
|
|
43
|
+
getFolderLists(req: BrevoGetFolderRequest): Promise<BrevoApiResponse<BrevoList[]>>;
|
|
44
|
+
/** Get folder details */
|
|
45
|
+
getFolderDetails(req: BrevoGetFolderRequest): Promise<BrevoApiResponse<BrevoFolder>>;
|
|
46
|
+
/** Create a new folder */
|
|
47
|
+
createFolder(req: BrevoCreateFolderRequest): Promise<BrevoApiResponse<BrevoCreateFolderResponse>>;
|
|
48
|
+
/** Update a folders name */
|
|
49
|
+
updateFolder(req: BrevoUpdateFolderRequest): Promise<BrevoApiResponse<BrevoStatus>>;
|
|
50
|
+
/** Delete a folder and all its lists */
|
|
51
|
+
deleteFolder(req: BrevoDeleteFolderRequest): Promise<BrevoApiResponse<BrevoStatus>>;
|
|
52
|
+
/** Send transactional email */
|
|
53
|
+
sendEmail(email: BrevoSendEmailRequest): Promise<BrevoApiResponse<BrevoSendEmailResponse>>;
|
|
54
|
+
/** Send SMS */
|
|
55
|
+
static sendSms(sms: BrevoSendSmsRequest): Promise<BrevoApiResponse<BrevoSendSmsResponse>>;
|
|
56
|
+
/** Ping Brevo API (GET /account) */
|
|
57
|
+
static ping(): Promise<BrevoApiResponse<unknown>>;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=brevo-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brevo-client.d.ts","sourceRoot":"","sources":["../src/brevo-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BrevoClient = void 0;
|
|
4
|
+
exports.createBrevoFetcher = createBrevoFetcher;
|
|
5
|
+
/**
|
|
6
|
+
* Environment-based configuration
|
|
7
|
+
*/
|
|
8
|
+
const BREVO_BASE_URL = "https://api.brevo.com/v3";
|
|
9
|
+
const BREVO_API_KEY = process.env.BREVO_API_KEY;
|
|
10
|
+
if (!BREVO_API_KEY) {
|
|
11
|
+
console.warn("⚠️ BREVO_API_KEY not set in environment. API calls will fail.");
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Create a fabric for brevoFetch with API key preconfigured
|
|
15
|
+
* @param baseUrl
|
|
16
|
+
* @param apiKey
|
|
17
|
+
*/
|
|
18
|
+
function createBrevoFetcher(baseUrl, apiKey) {
|
|
19
|
+
return async function brevoFetcher(endpoint, options = {}) {
|
|
20
|
+
const res = await fetch(`${baseUrl}${endpoint}`, {
|
|
21
|
+
...options,
|
|
22
|
+
headers: {
|
|
23
|
+
"Content-Type": "application/json",
|
|
24
|
+
"api-key": apiKey,
|
|
25
|
+
...options.headers,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
const status = res.status;
|
|
29
|
+
let data = null;
|
|
30
|
+
try {
|
|
31
|
+
data = await res.json();
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
data = null;
|
|
35
|
+
}
|
|
36
|
+
if (!res.ok) {
|
|
37
|
+
const error = {
|
|
38
|
+
status,
|
|
39
|
+
message: data?.message || res.statusText,
|
|
40
|
+
code: data?.code,
|
|
41
|
+
details: data,
|
|
42
|
+
};
|
|
43
|
+
return { status, error };
|
|
44
|
+
}
|
|
45
|
+
return { status, data };
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Minimal helper for making API requests
|
|
50
|
+
*/
|
|
51
|
+
async function brevoFetch(endpoint, options = {}) {
|
|
52
|
+
const res = await fetch(`${BREVO_BASE_URL}${endpoint}`, {
|
|
53
|
+
...options,
|
|
54
|
+
headers: {
|
|
55
|
+
"Content-Type": "application/json",
|
|
56
|
+
"api-key": BREVO_API_KEY,
|
|
57
|
+
...options.headers,
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
const status = res.status;
|
|
61
|
+
let data = null;
|
|
62
|
+
try {
|
|
63
|
+
data = await res.json();
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
data = null;
|
|
67
|
+
}
|
|
68
|
+
if (!res.ok) {
|
|
69
|
+
const error = {
|
|
70
|
+
status,
|
|
71
|
+
message: data?.message || res.statusText,
|
|
72
|
+
code: data?.code,
|
|
73
|
+
details: data,
|
|
74
|
+
};
|
|
75
|
+
return { status, error };
|
|
76
|
+
}
|
|
77
|
+
return { status, data };
|
|
78
|
+
}
|
|
79
|
+
async function fetchAllPaginated(endpoint, responseKey, limit = 50, extraQuery = "") {
|
|
80
|
+
let offset = 0;
|
|
81
|
+
const allItems = [];
|
|
82
|
+
let items;
|
|
83
|
+
do {
|
|
84
|
+
const url = `${endpoint}?limit=${limit}&offset=${offset}${extraQuery}`;
|
|
85
|
+
const response = await brevoFetch(url, { method: "GET" });
|
|
86
|
+
if (response.status !== 200) {
|
|
87
|
+
return response; // Fehler durchreichen
|
|
88
|
+
}
|
|
89
|
+
items = response.data?.[responseKey] ?? [];
|
|
90
|
+
allItems.push(...items);
|
|
91
|
+
offset += limit;
|
|
92
|
+
} while (items.length === limit);
|
|
93
|
+
return {
|
|
94
|
+
status: 200,
|
|
95
|
+
data: {
|
|
96
|
+
count: allItems.length,
|
|
97
|
+
[responseKey]: allItems,
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* BrevoClient – typed wrapper for Brevo REST API v3
|
|
103
|
+
*/
|
|
104
|
+
class BrevoClient {
|
|
105
|
+
brevoFetcher;
|
|
106
|
+
// private apiKey: string;
|
|
107
|
+
constructor(config) {
|
|
108
|
+
const apiKey = config?.apiKey ?? process.env.BREVO_API_KEY;
|
|
109
|
+
const baseUrl = config?.baseUrl ?? process.env.BREVO_BASE_URL ?? "https://api.brevo.com/v3";
|
|
110
|
+
this.brevoFetcher = createBrevoFetcher(baseUrl, apiKey);
|
|
111
|
+
}
|
|
112
|
+
//
|
|
113
|
+
// ────────────────────────────────
|
|
114
|
+
// CONTACTS
|
|
115
|
+
// ────────────────────────────────
|
|
116
|
+
//
|
|
117
|
+
/** Create or update a contact */
|
|
118
|
+
async createContact(contact) {
|
|
119
|
+
return brevoFetch("/contacts", {
|
|
120
|
+
method: "POST",
|
|
121
|
+
body: JSON.stringify(contact),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
/** Get contact by email or ID */
|
|
125
|
+
async getContact(identifier) {
|
|
126
|
+
return brevoFetch(`/contacts/${identifier}`, {
|
|
127
|
+
method: "GET",
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
/** Delete a contact */
|
|
131
|
+
async deleteContact(identifier) {
|
|
132
|
+
return brevoFetch(`/contacts/${identifier}`, { method: "DELETE" });
|
|
133
|
+
}
|
|
134
|
+
//
|
|
135
|
+
// ────────────────────────────────
|
|
136
|
+
// LISTS
|
|
137
|
+
// ────────────────────────────────
|
|
138
|
+
//
|
|
139
|
+
/** Get all lists */
|
|
140
|
+
async getLists() {
|
|
141
|
+
return fetchAllPaginated("/contacts/lists", "lists", 50, "&sort=asc");
|
|
142
|
+
}
|
|
143
|
+
/** Get lists of a folder */
|
|
144
|
+
async getListContacts(listId) {
|
|
145
|
+
return fetchAllPaginated(`/contacts/folders/${listId}/contacts`, "contacts", 50, "&sort=asc");
|
|
146
|
+
}
|
|
147
|
+
/** Get list details */
|
|
148
|
+
async getListDetails(listId) {
|
|
149
|
+
return brevoFetch(`/contacts/lists/${listId}`, {
|
|
150
|
+
method: "GET"
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
/** Create a new list */
|
|
154
|
+
async createList(list) {
|
|
155
|
+
return brevoFetch("/contacts/lists", {
|
|
156
|
+
method: "POST",
|
|
157
|
+
body: JSON.stringify(list),
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
async updateList(req) {
|
|
161
|
+
return brevoFetch(`/contacts/lists/${req.id}`, {
|
|
162
|
+
method: "PUT",
|
|
163
|
+
body: JSON.stringify(req.name),
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
/** Delete a list */
|
|
167
|
+
async deleteList(req) {
|
|
168
|
+
return brevoFetch(`/contacts/lists/${req.id}`, {
|
|
169
|
+
method: "DELETE"
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
/** Add existing contacts to a list */
|
|
173
|
+
async addContactsToList(req) {
|
|
174
|
+
let body = {};
|
|
175
|
+
if ("emails" in req) {
|
|
176
|
+
body.emails = req.emails;
|
|
177
|
+
}
|
|
178
|
+
else if ("ids" in req) {
|
|
179
|
+
body.ids = req.ids;
|
|
180
|
+
}
|
|
181
|
+
else if ("extIds" in req) {
|
|
182
|
+
body.extIds = req.extIds;
|
|
183
|
+
}
|
|
184
|
+
return brevoFetch(`/contacts/lists/${req.id}/contacts/add`, {
|
|
185
|
+
method: "POST",
|
|
186
|
+
body: JSON.stringify(body),
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
// async deleteContactFromList(req: BrevoDeleteContactFromListRequest): Promise<BrevoApiResponse<BrevoStatus>> {
|
|
190
|
+
//
|
|
191
|
+
// }
|
|
192
|
+
//
|
|
193
|
+
// ────────────────────────────────
|
|
194
|
+
// FOLDERS
|
|
195
|
+
// ────────────────────────────────
|
|
196
|
+
//
|
|
197
|
+
/** Get all folders */
|
|
198
|
+
async getFolders() {
|
|
199
|
+
return fetchAllPaginated("/contacts/folders", "folders", 50, "&sort=asc");
|
|
200
|
+
}
|
|
201
|
+
/** Get lists of a folder */
|
|
202
|
+
async getFolderLists(req) {
|
|
203
|
+
return fetchAllPaginated(`/contacts/folders/${req.id}/lists`, "lists", 50, "&sort=asc");
|
|
204
|
+
}
|
|
205
|
+
/** Get folder details */
|
|
206
|
+
async getFolderDetails(req) {
|
|
207
|
+
return brevoFetch(`/contacts/folders/${req.id}`, {
|
|
208
|
+
method: "GET"
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
/** Create a new folder */
|
|
212
|
+
async createFolder(req) {
|
|
213
|
+
return brevoFetch("/contacts/folders", {
|
|
214
|
+
method: "POST",
|
|
215
|
+
body: JSON.stringify({ name: req.name }),
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
/** Update a folders name */
|
|
219
|
+
async updateFolder(req) {
|
|
220
|
+
return brevoFetch(`/contacts/folders/${req.id}`, {
|
|
221
|
+
method: "PUT",
|
|
222
|
+
body: JSON.stringify({ name: req.name }),
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
/** Delete a folder and all its lists */
|
|
226
|
+
async deleteFolder(req) {
|
|
227
|
+
return brevoFetch(`/contacts/folders/${req.id}`, {
|
|
228
|
+
method: "DELETE"
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
//
|
|
232
|
+
// ────────────────────────────────
|
|
233
|
+
// TRANSACTIONAL EMAILS
|
|
234
|
+
// ────────────────────────────────
|
|
235
|
+
//
|
|
236
|
+
/** Send transactional email */
|
|
237
|
+
async sendEmail(email) {
|
|
238
|
+
return brevoFetch("/smtp/email", {
|
|
239
|
+
method: "POST",
|
|
240
|
+
body: JSON.stringify(email),
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
//
|
|
244
|
+
// ────────────────────────────────
|
|
245
|
+
// TRANSACTIONAL SMS
|
|
246
|
+
// ────────────────────────────────
|
|
247
|
+
//
|
|
248
|
+
/** Send SMS */
|
|
249
|
+
static async sendSms(sms) {
|
|
250
|
+
return brevoFetch("/transactionalSMS/sms", {
|
|
251
|
+
method: "POST",
|
|
252
|
+
body: JSON.stringify(sms),
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
//
|
|
256
|
+
// ────────────────────────────────
|
|
257
|
+
// UTILS
|
|
258
|
+
// ────────────────────────────────
|
|
259
|
+
//
|
|
260
|
+
/** Ping Brevo API (GET /account) */
|
|
261
|
+
static async ping() {
|
|
262
|
+
return brevoFetch("/account", { method: "GET" });
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
exports.BrevoClient = BrevoClient;
|
package/dist/brevo.d.ts
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript declarations for Brevo (Sendinblue) API v3
|
|
3
|
+
* Compatible with Next.js 15 / TypeScript 5.x
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export const BrevoHttpStatus = {
|
|
7
|
+
200: "OK",
|
|
8
|
+
201: "Created",
|
|
9
|
+
202: "Accepted",
|
|
10
|
+
204: "No Content",
|
|
11
|
+
400: "Bad Request",
|
|
12
|
+
401: "Unauthorized",
|
|
13
|
+
403: "Forbidden",
|
|
14
|
+
404: "Not Found",
|
|
15
|
+
429: "Too Many Requests",
|
|
16
|
+
500: "Internal Server Error",
|
|
17
|
+
} as const;
|
|
18
|
+
|
|
19
|
+
export type BrevoStatusCode = keyof typeof BrevoHttpStatus;
|
|
20
|
+
|
|
21
|
+
export type BrevoStatusMessage = (typeof BrevoHttpStatus)[BrevoStatusCode];
|
|
22
|
+
|
|
23
|
+
export type BrevoStatus = {
|
|
24
|
+
code: BrevoStatusCode;
|
|
25
|
+
message: BrevoStatusMessage;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/////////////////////////////
|
|
29
|
+
// CONTACTS
|
|
30
|
+
/////////////////////////////
|
|
31
|
+
|
|
32
|
+
export interface BrevoContact {
|
|
33
|
+
id?: number;
|
|
34
|
+
email?: string;
|
|
35
|
+
sms?: string;
|
|
36
|
+
attributes?: Record<string, string | number | boolean | (string | number | boolean)[]>;
|
|
37
|
+
listIds?: number[];
|
|
38
|
+
emailBlacklisted?: boolean;
|
|
39
|
+
smsBlacklisted?: boolean;
|
|
40
|
+
updateEnabled?: boolean;
|
|
41
|
+
extId?: string;
|
|
42
|
+
createdAt?: string;
|
|
43
|
+
modifiedAt?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Request payload when creating a new contact.
|
|
48
|
+
* API: POST /v3/contact
|
|
49
|
+
*/
|
|
50
|
+
export interface BrevoCreateContactRequest {
|
|
51
|
+
email?: string;
|
|
52
|
+
sms?: string;
|
|
53
|
+
attributes?: Record<string, string | number | boolean | (string | number | boolean)[]>;
|
|
54
|
+
listIds?: number[];
|
|
55
|
+
updateEnabled?: boolean;
|
|
56
|
+
emailBlacklisted?: boolean;
|
|
57
|
+
smsBlacklisted?: boolean;
|
|
58
|
+
extId?: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Response from POST /v3/contact
|
|
63
|
+
*/
|
|
64
|
+
export interface BrevoCreateContactResponse {
|
|
65
|
+
id: number;
|
|
66
|
+
email?: string;
|
|
67
|
+
sms?: string;
|
|
68
|
+
attributes?: Record<string, string | number | boolean | (string | number | boolean)[]>;
|
|
69
|
+
createdAt: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Response for GET /v3/contact/{identifier}
|
|
74
|
+
*/
|
|
75
|
+
export interface BrevoGetContactResponse extends BrevoContact {
|
|
76
|
+
listIds: number[];
|
|
77
|
+
statistics?: BrevoContactStats;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Contact statistics (opens, clicks, etc.)
|
|
82
|
+
*/
|
|
83
|
+
export interface BrevoContactStats {
|
|
84
|
+
messagesSent?: number;
|
|
85
|
+
delivered?: number;
|
|
86
|
+
opened?: number;
|
|
87
|
+
click?: number;
|
|
88
|
+
hardBounces?: number;
|
|
89
|
+
softBounces?: number;
|
|
90
|
+
complaints?: number;
|
|
91
|
+
unsubscriptions?: number;
|
|
92
|
+
transactionalStats?: {
|
|
93
|
+
delivered?: number;
|
|
94
|
+
opened?: number;
|
|
95
|
+
click?: number;
|
|
96
|
+
softBounces?: number;
|
|
97
|
+
hardBounces?: number;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/////////////////////////////
|
|
102
|
+
// ATTRIBUTES
|
|
103
|
+
/////////////////////////////
|
|
104
|
+
|
|
105
|
+
export interface BrevoAttributeCategory {
|
|
106
|
+
name: string;
|
|
107
|
+
attributes: BrevoContactAttributeDefinition[];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface BrevoContactAttributeDefinition {
|
|
111
|
+
name: string;
|
|
112
|
+
type: "text" | "date" | "float" | "boolean" | "id" | "category" | "multiple_choice";
|
|
113
|
+
value?: string | number | boolean;
|
|
114
|
+
enumeration?: { value: number; label: string }[];
|
|
115
|
+
calculatedValue?: boolean;
|
|
116
|
+
createdAt?: string;
|
|
117
|
+
updatedAt?: string;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface BrevoListAttributesResponse {
|
|
121
|
+
attributes: BrevoContactAttributeDefinition[];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/////////////////////////////
|
|
125
|
+
// LISTS
|
|
126
|
+
/////////////////////////////
|
|
127
|
+
|
|
128
|
+
export interface BrevoList {
|
|
129
|
+
id: number;
|
|
130
|
+
name: string;
|
|
131
|
+
totalSubscribers: number;
|
|
132
|
+
uniqueSubscribers: number;
|
|
133
|
+
shared: boolean;
|
|
134
|
+
folderId: number;
|
|
135
|
+
createdAt: string;
|
|
136
|
+
dynamic?: boolean;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export interface BrevoGetListsResponse {
|
|
140
|
+
lists: BrevoList[];
|
|
141
|
+
count: number;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export interface BrevoGetListContactsResponse {
|
|
145
|
+
contacts: BrevoContact[];
|
|
146
|
+
count: number;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export interface BrevoCreateListRequest {
|
|
150
|
+
name: string;
|
|
151
|
+
folderId?: number;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface BrevoCreateListResponse {
|
|
155
|
+
id: number;
|
|
156
|
+
name: string;
|
|
157
|
+
totalSubscribers: number;
|
|
158
|
+
folderId: number;
|
|
159
|
+
createdAt: string;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export interface BrevoUpdateListRequest {
|
|
163
|
+
id: number;
|
|
164
|
+
name: string;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export interface BrevoDeleteListRequest {
|
|
168
|
+
id: number;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export interface BrevoAddContactsToListBase {
|
|
172
|
+
id: number;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export interface BrevoAddContactsToListByEmail extends BrevoAddContactsToListBase {
|
|
176
|
+
emails: string[];
|
|
177
|
+
ids?: never;
|
|
178
|
+
extIds?: never;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export interface BrevoAddContactsToListById extends BrevoAddContactsToListBase {
|
|
182
|
+
ids: number[];
|
|
183
|
+
emails?: never;
|
|
184
|
+
extIds?: never;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export interface BrevoAddContactsToListByExtId extends BrevoAddContactsToListBase {
|
|
188
|
+
extIds: string[];
|
|
189
|
+
emails?: never;
|
|
190
|
+
ids?: never;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export type BrevoAddContactsToListRequest =
|
|
194
|
+
| BrevoAddContactsToListByEmail
|
|
195
|
+
| BrevoAddContactsToListById
|
|
196
|
+
| BrevoAddContactsToListByExtId;
|
|
197
|
+
|
|
198
|
+
export interface BrevoAddContactsToListResponse {
|
|
199
|
+
contacts: {
|
|
200
|
+
success: number[] | string[],
|
|
201
|
+
failure: number[] | string[],
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/////////////////////////////
|
|
206
|
+
// FOLDERS
|
|
207
|
+
/////////////////////////////
|
|
208
|
+
|
|
209
|
+
export interface BrevoFolder {
|
|
210
|
+
id: number;
|
|
211
|
+
name: string;
|
|
212
|
+
uniqueSubscribers: number;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export interface BrevoGetFoldersResponse {
|
|
216
|
+
folders: BrevoFolder[];
|
|
217
|
+
count: number;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export interface BrevoGetFolderRequest {
|
|
221
|
+
id: number;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export interface BrevoGetFolderListsResponse {
|
|
225
|
+
lists: BrevoList[];
|
|
226
|
+
count: number;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export interface BrevoCreateFolderRequest {
|
|
230
|
+
name: string;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export interface BrevoCreateFolderResponse {
|
|
234
|
+
id: number;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export interface BrevoUpdateFolderRequest {
|
|
238
|
+
id: number;
|
|
239
|
+
name: string;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export interface BrevoDeleteFolderRequest {
|
|
243
|
+
id: number;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/////////////////////////////
|
|
247
|
+
// TRANSACTIONAL EMAILS
|
|
248
|
+
/////////////////////////////
|
|
249
|
+
|
|
250
|
+
export interface BrevoEmailRecipient {
|
|
251
|
+
email: string;
|
|
252
|
+
name?: string;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export interface BrevoSendEmailRequest {
|
|
256
|
+
sender: BrevoEmailRecipient & { id?: number };
|
|
257
|
+
to: BrevoEmailRecipient[];
|
|
258
|
+
cc?: BrevoEmailRecipient[];
|
|
259
|
+
bcc?: BrevoEmailRecipient[];
|
|
260
|
+
replyTo?: BrevoEmailRecipient;
|
|
261
|
+
subject?: string;
|
|
262
|
+
htmlContent?: string;
|
|
263
|
+
textContent?: string;
|
|
264
|
+
templateId?: number;
|
|
265
|
+
params?: Record<string, string | number | boolean>;
|
|
266
|
+
headers?: Record<string, string>;
|
|
267
|
+
attachment?: {
|
|
268
|
+
url?: string;
|
|
269
|
+
content?: string; // Base64 encoded
|
|
270
|
+
name?: string;
|
|
271
|
+
}[];
|
|
272
|
+
tags?: string[];
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export interface BrevoSendEmailResponse {
|
|
276
|
+
messageId: string;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/////////////////////////////
|
|
280
|
+
// TRANSACTIONAL SMS
|
|
281
|
+
/////////////////////////////
|
|
282
|
+
|
|
283
|
+
export interface BrevoSendSmsRequest {
|
|
284
|
+
sender: string; // must be alphanumeric and <= 11 chars
|
|
285
|
+
recipient: string;
|
|
286
|
+
content: string;
|
|
287
|
+
type?: "transactional" | "marketing";
|
|
288
|
+
tag?: string;
|
|
289
|
+
webUrl?: string;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export interface BrevoSendSmsResponse {
|
|
293
|
+
messageId: string;
|
|
294
|
+
reference?: string;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/////////////////////////////
|
|
298
|
+
// SMTP / EMAIL EVENT WEBHOOKS
|
|
299
|
+
/////////////////////////////
|
|
300
|
+
|
|
301
|
+
export interface BrevoEmailWebhookEvent {
|
|
302
|
+
event: "delivered" | "opened" | "clicked" | "hardBounce" | "softBounce" | "spam" | "invalidEmail" | "deferred" | "blocked" | "unsubscribed" | "error";
|
|
303
|
+
email: string;
|
|
304
|
+
id: string;
|
|
305
|
+
date: string;
|
|
306
|
+
subject?: string;
|
|
307
|
+
tag?: string;
|
|
308
|
+
messageId?: string;
|
|
309
|
+
reason?: string;
|
|
310
|
+
sendingIp?: string;
|
|
311
|
+
ts?: number;
|
|
312
|
+
ts_event?: number;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/////////////////////////////
|
|
316
|
+
// MARKETING CAMPAIGNS (optional)
|
|
317
|
+
/////////////////////////////
|
|
318
|
+
|
|
319
|
+
export interface BrevoCampaign {
|
|
320
|
+
id: number;
|
|
321
|
+
name: string;
|
|
322
|
+
subject: string;
|
|
323
|
+
sender: {
|
|
324
|
+
name: string;
|
|
325
|
+
email: string;
|
|
326
|
+
};
|
|
327
|
+
type: "classic" | "trigger";
|
|
328
|
+
status: "draft" | "sent" | "archive" | "queued" | "suspended" | "inProcess";
|
|
329
|
+
statistics?: {
|
|
330
|
+
delivered?: number;
|
|
331
|
+
opened?: number;
|
|
332
|
+
click?: number;
|
|
333
|
+
};
|
|
334
|
+
createdAt?: string;
|
|
335
|
+
modifiedAt?: string;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/////////////////////////////
|
|
339
|
+
// ERROR HANDLING
|
|
340
|
+
/////////////////////////////
|
|
341
|
+
|
|
342
|
+
export interface BrevoApiError {
|
|
343
|
+
code?: string | number;
|
|
344
|
+
message: string;
|
|
345
|
+
status?: number;
|
|
346
|
+
details?: any;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/////////////////////////////
|
|
350
|
+
// GENERIC UTILS
|
|
351
|
+
/////////////////////////////
|
|
352
|
+
|
|
353
|
+
export type BrevoApiResponse<T> = {
|
|
354
|
+
data?: T;
|
|
355
|
+
error?: BrevoApiError;
|
|
356
|
+
status: number;
|
|
357
|
+
};
|
|
358
|
+
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,mBAAmB,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./brevo-client"), exports);
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tozielinski/next-brevo-api-helper",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Lightweight helper to use Brevo to send mails via the Brevo API and maintain all",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc && cp src/brevo.d.ts dist/",
|
|
12
|
+
"test": "vitest run",
|
|
13
|
+
"typecheck": "tsc --noEmit",
|
|
14
|
+
"prepublishOnly": "npm run build"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/tozielinski/next-brevo-api-helper.git"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"next",
|
|
25
|
+
"nextjs",
|
|
26
|
+
"brevo",
|
|
27
|
+
"api",
|
|
28
|
+
"mail"
|
|
29
|
+
],
|
|
30
|
+
"author": "Torsten Zielinski",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"bugs": {
|
|
33
|
+
"url": "https://github.com/tozielinski/next-brevo-api-helper/issues"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://github.com/tozielinski/next-brevo-api-helper#readme",
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/node": "^20.19.25",
|
|
38
|
+
"typescript": "^5.0.0",
|
|
39
|
+
"vitest": "^4.0.12"
|
|
40
|
+
}
|
|
41
|
+
}
|