@linqapp/sdk 0.1.5 → 0.4.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/CHANGELOG.md +36 -0
- package/README.md +31 -0
- package/client.d.mts +299 -7
- package/client.d.mts.map +1 -1
- package/client.d.ts +299 -7
- package/client.d.ts.map +1 -1
- package/client.js +294 -12
- package/client.js.map +1 -1
- package/client.mjs +294 -12
- package/client.mjs.map +1 -1
- package/core/pagination.d.mts +69 -0
- package/core/pagination.d.mts.map +1 -0
- package/core/pagination.d.ts +69 -0
- package/core/pagination.d.ts.map +1 -0
- package/core/pagination.js +125 -0
- package/core/pagination.js.map +1 -0
- package/core/pagination.mjs +118 -0
- package/core/pagination.mjs.map +1 -0
- package/index.d.mts +1 -0
- package/index.d.mts.map +1 -1
- package/index.d.ts +1 -0
- package/index.d.ts.map +1 -1
- package/index.js +3 -1
- package/index.js.map +1 -1
- package/index.mjs +1 -0
- package/index.mjs.map +1 -1
- package/internal/tslib.js +18 -18
- package/internal/utils/query.d.mts +5 -0
- package/internal/utils/query.d.mts.map +1 -0
- package/internal/utils/query.d.ts +5 -0
- package/internal/utils/query.d.ts.map +1 -0
- package/internal/utils/query.js +23 -0
- package/internal/utils/query.js.map +1 -0
- package/internal/utils/query.mjs +20 -0
- package/internal/utils/query.mjs.map +1 -0
- package/internal/utils.d.mts +1 -0
- package/internal/utils.d.ts +1 -0
- package/internal/utils.js +1 -0
- package/internal/utils.js.map +1 -1
- package/internal/utils.mjs +1 -0
- package/package.json +11 -1
- package/pagination.d.mts +2 -0
- package/pagination.d.mts.map +1 -0
- package/pagination.d.ts +2 -0
- package/pagination.d.ts.map +1 -0
- package/pagination.js +6 -0
- package/pagination.js.map +1 -0
- package/pagination.mjs +2 -0
- package/pagination.mjs.map +1 -0
- package/resources/attachments.d.mts +64 -0
- package/resources/attachments.d.mts.map +1 -1
- package/resources/attachments.d.ts +64 -0
- package/resources/attachments.d.ts.map +1 -1
- package/resources/attachments.js +64 -0
- package/resources/attachments.js.map +1 -1
- package/resources/attachments.mjs +64 -0
- package/resources/attachments.mjs.map +1 -1
- package/resources/capability.d.mts +12 -9
- package/resources/capability.d.mts.map +1 -1
- package/resources/capability.d.ts +12 -9
- package/resources/capability.d.ts.map +1 -1
- package/resources/capability.js +7 -4
- package/resources/capability.js.map +1 -1
- package/resources/capability.mjs +7 -4
- package/resources/capability.mjs.map +1 -1
- package/resources/chats/chats.d.mts +76 -97
- package/resources/chats/chats.d.mts.map +1 -1
- package/resources/chats/chats.d.ts +76 -97
- package/resources/chats/chats.d.ts.map +1 -1
- package/resources/chats/chats.js +8 -4
- package/resources/chats/chats.js.map +1 -1
- package/resources/chats/chats.mjs +9 -5
- package/resources/chats/chats.mjs.map +1 -1
- package/resources/chats/index.d.mts +2 -2
- package/resources/chats/index.d.mts.map +1 -1
- package/resources/chats/index.d.ts +2 -2
- package/resources/chats/index.d.ts.map +1 -1
- package/resources/chats/index.js.map +1 -1
- package/resources/chats/index.mjs.map +1 -1
- package/resources/chats/messages.d.mts +21 -25
- package/resources/chats/messages.d.mts.map +1 -1
- package/resources/chats/messages.d.ts +21 -25
- package/resources/chats/messages.d.ts.map +1 -1
- package/resources/chats/messages.js +16 -3
- package/resources/chats/messages.js.map +1 -1
- package/resources/chats/messages.mjs +16 -3
- package/resources/chats/messages.mjs.map +1 -1
- package/resources/chats/participants.d.mts +18 -0
- package/resources/chats/participants.d.mts.map +1 -1
- package/resources/chats/participants.d.ts +18 -0
- package/resources/chats/participants.d.ts.map +1 -1
- package/resources/chats/participants.js +18 -0
- package/resources/chats/participants.js.map +1 -1
- package/resources/chats/participants.mjs +18 -0
- package/resources/chats/participants.mjs.map +1 -1
- package/resources/chats/typing.d.mts +18 -0
- package/resources/chats/typing.d.mts.map +1 -1
- package/resources/chats/typing.d.ts +18 -0
- package/resources/chats/typing.d.ts.map +1 -1
- package/resources/chats/typing.js +18 -0
- package/resources/chats/typing.js.map +1 -1
- package/resources/chats/typing.mjs +18 -0
- package/resources/chats/typing.mjs.map +1 -1
- package/resources/index.d.mts +4 -3
- package/resources/index.d.mts.map +1 -1
- package/resources/index.d.ts +4 -3
- package/resources/index.d.ts.map +1 -1
- package/resources/index.js +3 -1
- package/resources/index.js.map +1 -1
- package/resources/index.mjs +1 -0
- package/resources/index.mjs.map +1 -1
- package/resources/messages.d.mts +37 -72
- package/resources/messages.d.mts.map +1 -1
- package/resources/messages.d.ts +37 -72
- package/resources/messages.d.ts.map +1 -1
- package/resources/messages.js +34 -4
- package/resources/messages.js.map +1 -1
- package/resources/messages.mjs +34 -4
- package/resources/messages.mjs.map +1 -1
- package/resources/phone-numbers.d.mts +9 -0
- package/resources/phone-numbers.d.mts.map +1 -1
- package/resources/phone-numbers.d.ts +9 -0
- package/resources/phone-numbers.d.ts.map +1 -1
- package/resources/phone-numbers.js +9 -0
- package/resources/phone-numbers.js.map +1 -1
- package/resources/phone-numbers.mjs +9 -0
- package/resources/phone-numbers.mjs.map +1 -1
- package/resources/phonenumbers.d.mts +9 -0
- package/resources/phonenumbers.d.mts.map +1 -1
- package/resources/phonenumbers.d.ts +9 -0
- package/resources/phonenumbers.d.ts.map +1 -1
- package/resources/phonenumbers.js +9 -0
- package/resources/phonenumbers.js.map +1 -1
- package/resources/phonenumbers.mjs +9 -0
- package/resources/phonenumbers.mjs.map +1 -1
- package/resources/shared.d.mts +51 -0
- package/resources/shared.d.mts.map +1 -1
- package/resources/shared.d.ts +51 -0
- package/resources/shared.d.ts.map +1 -1
- package/resources/webhook-events.d.mts +90 -1
- package/resources/webhook-events.d.mts.map +1 -1
- package/resources/webhook-events.d.ts +90 -1
- package/resources/webhook-events.d.ts.map +1 -1
- package/resources/webhook-events.js +89 -0
- package/resources/webhook-events.js.map +1 -1
- package/resources/webhook-events.mjs +89 -0
- package/resources/webhook-events.mjs.map +1 -1
- package/resources/webhook-subscriptions.d.mts +89 -0
- package/resources/webhook-subscriptions.d.mts.map +1 -1
- package/resources/webhook-subscriptions.d.ts +89 -0
- package/resources/webhook-subscriptions.d.ts.map +1 -1
- package/resources/webhook-subscriptions.js +89 -0
- package/resources/webhook-subscriptions.js.map +1 -1
- package/resources/webhook-subscriptions.mjs +89 -0
- package/resources/webhook-subscriptions.mjs.map +1 -1
- package/resources/webhooks.d.mts +2506 -0
- package/resources/webhooks.d.mts.map +1 -0
- package/resources/webhooks.d.ts +2506 -0
- package/resources/webhooks.d.ts.map +1 -0
- package/resources/webhooks.js +12 -0
- package/resources/webhooks.js.map +1 -0
- package/resources/webhooks.mjs +8 -0
- package/resources/webhooks.mjs.map +1 -0
- package/src/client.ts +443 -37
- package/src/core/pagination.ts +212 -0
- package/src/index.ts +1 -0
- package/src/internal/utils/query.ts +23 -0
- package/src/internal/utils.ts +1 -0
- package/src/pagination.ts +2 -0
- package/src/resources/attachments.ts +64 -0
- package/src/resources/capability.ts +17 -14
- package/src/resources/chats/chats.ts +86 -115
- package/src/resources/chats/index.ts +4 -3
- package/src/resources/chats/messages.ts +30 -30
- package/src/resources/chats/participants.ts +18 -0
- package/src/resources/chats/typing.ts +18 -0
- package/src/resources/index.ts +55 -10
- package/src/resources/messages.ts +49 -90
- package/src/resources/phone-numbers.ts +9 -0
- package/src/resources/phonenumbers.ts +9 -0
- package/src/resources/shared.ts +62 -0
- package/src/resources/webhook-events.ts +90 -0
- package/src/resources/webhook-subscriptions.ts +89 -0
- package/src/resources/webhooks.ts +3089 -0
- package/src/version.ts +1 -1
- package/version.d.mts +1 -1
- package/version.d.ts +1 -1
- package/version.js +1 -1
- package/version.mjs +1 -1
|
@@ -3,10 +3,20 @@
|
|
|
3
3
|
import { APIResource } from '../core/resource';
|
|
4
4
|
import * as Shared from './shared';
|
|
5
5
|
import { APIPromise } from '../core/api-promise';
|
|
6
|
+
import { ListMessagesPagination, type ListMessagesPaginationParams, PagePromise } from '../core/pagination';
|
|
6
7
|
import { buildHeaders } from '../internal/headers';
|
|
7
8
|
import { RequestOptions } from '../internal/request-options';
|
|
8
9
|
import { path } from '../internal/utils/path';
|
|
9
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Messages are individual text or multimedia communications within a chat thread.
|
|
13
|
+
*
|
|
14
|
+
* Messages can include text, attachments, special effects (like confetti or fireworks),
|
|
15
|
+
* and reactions. All messages are associated with a specific chat and sent from a
|
|
16
|
+
* phone number you own.
|
|
17
|
+
*
|
|
18
|
+
* Messages support delivery status tracking, read receipts, and editing capabilities.
|
|
19
|
+
*/
|
|
10
20
|
export class Messages extends APIResource {
|
|
11
21
|
/**
|
|
12
22
|
* Retrieve a specific message by its ID. This endpoint returns the full message
|
|
@@ -23,6 +33,21 @@ export class Messages extends APIResource {
|
|
|
23
33
|
return this._client.get(path`/v3/messages/${messageID}`, options);
|
|
24
34
|
}
|
|
25
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Edit the text content of a specific part of a previously sent message.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* const message = await client.messages.update(
|
|
42
|
+
* '69a37c7d-af4f-4b5e-af42-e28e98ce873a',
|
|
43
|
+
* { text: 'This is the edited message content' },
|
|
44
|
+
* );
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
update(messageID: string, body: MessageUpdateParams, options?: RequestOptions): APIPromise<Message> {
|
|
48
|
+
return this._client.patch(path`/v3/messages/${messageID}`, { body, ...options });
|
|
49
|
+
}
|
|
50
|
+
|
|
26
51
|
/**
|
|
27
52
|
* Deletes a message from the Linq API only. This does NOT unsend or remove the
|
|
28
53
|
* message from the actual chat - recipients will still see the message.
|
|
@@ -86,20 +111,28 @@ export class Messages extends APIResource {
|
|
|
86
111
|
*
|
|
87
112
|
* @example
|
|
88
113
|
* ```ts
|
|
89
|
-
*
|
|
114
|
+
* // Automatically fetches more pages as needed.
|
|
115
|
+
* for await (const message of client.messages.listMessagesThread(
|
|
90
116
|
* '69a37c7d-af4f-4b5e-af42-e28e98ce873a',
|
|
91
|
-
* )
|
|
117
|
+
* )) {
|
|
118
|
+
* // ...
|
|
119
|
+
* }
|
|
92
120
|
* ```
|
|
93
121
|
*/
|
|
94
|
-
|
|
122
|
+
listMessagesThread(
|
|
95
123
|
messageID: string,
|
|
96
|
-
query:
|
|
124
|
+
query: MessageListMessagesThreadParams | null | undefined = {},
|
|
97
125
|
options?: RequestOptions,
|
|
98
|
-
):
|
|
99
|
-
return this._client.
|
|
126
|
+
): PagePromise<MessagesListMessagesPagination, Message> {
|
|
127
|
+
return this._client.getAPIList(path`/v3/messages/${messageID}/thread`, ListMessagesPagination<Message>, {
|
|
128
|
+
query,
|
|
129
|
+
...options,
|
|
130
|
+
});
|
|
100
131
|
}
|
|
101
132
|
}
|
|
102
133
|
|
|
134
|
+
export type MessagesListMessagesPagination = ListMessagesPagination<Message>;
|
|
135
|
+
|
|
103
136
|
export interface ChatHandle {
|
|
104
137
|
/**
|
|
105
138
|
* Unique identifier for this handle
|
|
@@ -137,46 +170,6 @@ export interface ChatHandle {
|
|
|
137
170
|
status?: 'active' | 'left' | 'removed' | null;
|
|
138
171
|
}
|
|
139
172
|
|
|
140
|
-
/**
|
|
141
|
-
* A media attachment part
|
|
142
|
-
*/
|
|
143
|
-
export interface MediaPart {
|
|
144
|
-
/**
|
|
145
|
-
* Unique attachment identifier
|
|
146
|
-
*/
|
|
147
|
-
id: string;
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Original filename
|
|
151
|
-
*/
|
|
152
|
-
filename: string;
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* MIME type of the file
|
|
156
|
-
*/
|
|
157
|
-
mime_type: string;
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Reactions on this message part
|
|
161
|
-
*/
|
|
162
|
-
reactions: Array<Reaction> | null;
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* File size in bytes
|
|
166
|
-
*/
|
|
167
|
-
size_bytes: number;
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Indicates this is a media attachment part
|
|
171
|
-
*/
|
|
172
|
-
type: 'media';
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Presigned URL for downloading the attachment (expires in 1 hour).
|
|
176
|
-
*/
|
|
177
|
-
url: string;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
173
|
export interface Message {
|
|
181
174
|
/**
|
|
182
175
|
* Unique identifier for the message
|
|
@@ -237,7 +230,7 @@ export interface Message {
|
|
|
237
230
|
/**
|
|
238
231
|
* Message parts in order (text and media)
|
|
239
232
|
*/
|
|
240
|
-
parts?: Array<
|
|
233
|
+
parts?: Array<Shared.TextPartResponse | Shared.MediaPartResponse> | null;
|
|
241
234
|
|
|
242
235
|
/**
|
|
243
236
|
* Messaging service type
|
|
@@ -378,26 +371,6 @@ export interface ReplyTo {
|
|
|
378
371
|
part_index?: number;
|
|
379
372
|
}
|
|
380
373
|
|
|
381
|
-
/**
|
|
382
|
-
* A text message part
|
|
383
|
-
*/
|
|
384
|
-
export interface TextPart {
|
|
385
|
-
/**
|
|
386
|
-
* Reactions on this message part
|
|
387
|
-
*/
|
|
388
|
-
reactions: Array<Reaction> | null;
|
|
389
|
-
|
|
390
|
-
/**
|
|
391
|
-
* Indicates this is a text message part
|
|
392
|
-
*/
|
|
393
|
-
type: 'text';
|
|
394
|
-
|
|
395
|
-
/**
|
|
396
|
-
* The text content
|
|
397
|
-
*/
|
|
398
|
-
value: string;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
374
|
export interface MessageAddReactionResponse {
|
|
402
375
|
message?: string;
|
|
403
376
|
|
|
@@ -406,19 +379,16 @@ export interface MessageAddReactionResponse {
|
|
|
406
379
|
trace_id?: string;
|
|
407
380
|
}
|
|
408
381
|
|
|
409
|
-
|
|
410
|
-
* Response containing messages in a thread with pagination
|
|
411
|
-
*/
|
|
412
|
-
export interface MessageRetrieveThreadResponse {
|
|
382
|
+
export interface MessageUpdateParams {
|
|
413
383
|
/**
|
|
414
|
-
*
|
|
384
|
+
* New text content for the message part
|
|
415
385
|
*/
|
|
416
|
-
|
|
386
|
+
text: string;
|
|
417
387
|
|
|
418
388
|
/**
|
|
419
|
-
*
|
|
389
|
+
* Index of the message part to edit. Defaults to 0.
|
|
420
390
|
*/
|
|
421
|
-
|
|
391
|
+
part_index?: number;
|
|
422
392
|
}
|
|
423
393
|
|
|
424
394
|
export interface MessageDeleteParams {
|
|
@@ -454,17 +424,7 @@ export interface MessageAddReactionParams {
|
|
|
454
424
|
part_index?: number;
|
|
455
425
|
}
|
|
456
426
|
|
|
457
|
-
export interface
|
|
458
|
-
/**
|
|
459
|
-
* Pagination cursor from previous next_cursor response
|
|
460
|
-
*/
|
|
461
|
-
cursor?: string;
|
|
462
|
-
|
|
463
|
-
/**
|
|
464
|
-
* Maximum number of messages to return
|
|
465
|
-
*/
|
|
466
|
-
limit?: number;
|
|
467
|
-
|
|
427
|
+
export interface MessageListMessagesThreadParams extends ListMessagesPaginationParams {
|
|
468
428
|
/**
|
|
469
429
|
* Sort order for messages (asc = oldest first, desc = newest first)
|
|
470
430
|
*/
|
|
@@ -474,17 +434,16 @@ export interface MessageRetrieveThreadParams {
|
|
|
474
434
|
export declare namespace Messages {
|
|
475
435
|
export {
|
|
476
436
|
type ChatHandle as ChatHandle,
|
|
477
|
-
type MediaPart as MediaPart,
|
|
478
437
|
type Message as Message,
|
|
479
438
|
type MessageEffect as MessageEffect,
|
|
480
439
|
type Reaction as Reaction,
|
|
481
440
|
type ReactionType as ReactionType,
|
|
482
441
|
type ReplyTo as ReplyTo,
|
|
483
|
-
type TextPart as TextPart,
|
|
484
442
|
type MessageAddReactionResponse as MessageAddReactionResponse,
|
|
485
|
-
type
|
|
443
|
+
type MessagesListMessagesPagination as MessagesListMessagesPagination,
|
|
444
|
+
type MessageUpdateParams as MessageUpdateParams,
|
|
486
445
|
type MessageDeleteParams as MessageDeleteParams,
|
|
487
446
|
type MessageAddReactionParams as MessageAddReactionParams,
|
|
488
|
-
type
|
|
447
|
+
type MessageListMessagesThreadParams as MessageListMessagesThreadParams,
|
|
489
448
|
};
|
|
490
449
|
}
|
|
@@ -4,6 +4,15 @@ import { APIResource } from '../core/resource';
|
|
|
4
4
|
import { APIPromise } from '../core/api-promise';
|
|
5
5
|
import { RequestOptions } from '../internal/request-options';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Phone Numbers represent the phone numbers assigned to your partner account.
|
|
9
|
+
*
|
|
10
|
+
* Use the list phone numbers endpoint to discover which phone numbers are available
|
|
11
|
+
* for sending messages.
|
|
12
|
+
*
|
|
13
|
+
* When creating chats, listing chats, or sending a voice memo, use one of your assigned phone numbers
|
|
14
|
+
* in the `from` field.
|
|
15
|
+
*/
|
|
7
16
|
export class PhoneNumbers extends APIResource {
|
|
8
17
|
/**
|
|
9
18
|
* Returns all phone numbers assigned to the authenticated partner. Use this
|
|
@@ -4,6 +4,15 @@ import { APIResource } from '../core/resource';
|
|
|
4
4
|
import { APIPromise } from '../core/api-promise';
|
|
5
5
|
import { RequestOptions } from '../internal/request-options';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Phone Numbers represent the phone numbers assigned to your partner account.
|
|
9
|
+
*
|
|
10
|
+
* Use the list phone numbers endpoint to discover which phone numbers are available
|
|
11
|
+
* for sending messages.
|
|
12
|
+
*
|
|
13
|
+
* When creating chats, listing chats, or sending a voice memo, use one of your assigned phone numbers
|
|
14
|
+
* in the `from` field.
|
|
15
|
+
*/
|
|
7
16
|
export class Phonenumbers extends APIResource {
|
|
8
17
|
/**
|
|
9
18
|
* **Deprecated.** Use `GET /v3/phone_numbers` instead.
|
package/src/resources/shared.ts
CHANGED
|
@@ -1,6 +1,68 @@
|
|
|
1
1
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
2
2
|
|
|
3
|
+
import * as MessagesAPI from './messages';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A media attachment part
|
|
7
|
+
*/
|
|
8
|
+
export interface MediaPartResponse {
|
|
9
|
+
/**
|
|
10
|
+
* Unique attachment identifier
|
|
11
|
+
*/
|
|
12
|
+
id: string;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Original filename
|
|
16
|
+
*/
|
|
17
|
+
filename: string;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* MIME type of the file
|
|
21
|
+
*/
|
|
22
|
+
mime_type: string;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Reactions on this message part
|
|
26
|
+
*/
|
|
27
|
+
reactions: Array<MessagesAPI.Reaction> | null;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* File size in bytes
|
|
31
|
+
*/
|
|
32
|
+
size_bytes: number;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Indicates this is a media attachment part
|
|
36
|
+
*/
|
|
37
|
+
type: 'media';
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Presigned URL for downloading the attachment (expires in 1 hour).
|
|
41
|
+
*/
|
|
42
|
+
url: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
3
45
|
/**
|
|
4
46
|
* Messaging service type
|
|
5
47
|
*/
|
|
6
48
|
export type ServiceType = 'iMessage' | 'SMS' | 'RCS';
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* A text message part
|
|
52
|
+
*/
|
|
53
|
+
export interface TextPartResponse {
|
|
54
|
+
/**
|
|
55
|
+
* Reactions on this message part
|
|
56
|
+
*/
|
|
57
|
+
reactions: Array<MessagesAPI.Reaction> | null;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Indicates this is a text message part
|
|
61
|
+
*/
|
|
62
|
+
type: 'text';
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The text content
|
|
66
|
+
*/
|
|
67
|
+
value: string;
|
|
68
|
+
}
|
|
@@ -4,6 +4,95 @@ import { APIResource } from '../core/resource';
|
|
|
4
4
|
import { APIPromise } from '../core/api-promise';
|
|
5
5
|
import { RequestOptions } from '../internal/request-options';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Webhook Subscriptions allow you to receive real-time notifications when events
|
|
9
|
+
* occur on your account.
|
|
10
|
+
*
|
|
11
|
+
* Configure webhook endpoints to receive events such as messages sent/received,
|
|
12
|
+
* delivery status changes, reactions, typing indicators, and more.
|
|
13
|
+
*
|
|
14
|
+
* Failed deliveries (5xx, 429, network errors) are retried up to 10 times over
|
|
15
|
+
* ~2 hours with exponential backoff. Each event includes a unique ID for
|
|
16
|
+
* deduplication.
|
|
17
|
+
*
|
|
18
|
+
* ## Webhook Headers
|
|
19
|
+
*
|
|
20
|
+
* Each webhook request includes the following headers:
|
|
21
|
+
*
|
|
22
|
+
* | Header | Description |
|
|
23
|
+
* |--------|-------------|
|
|
24
|
+
* | `X-Webhook-Event` | The event type (e.g., `message.sent`, `message.received`) |
|
|
25
|
+
* | `X-Webhook-Subscription-ID` | Your webhook subscription ID |
|
|
26
|
+
* | `X-Webhook-Timestamp` | Unix timestamp (seconds) when the webhook was sent |
|
|
27
|
+
* | `X-Webhook-Signature` | HMAC-SHA256 signature for verification |
|
|
28
|
+
*
|
|
29
|
+
* ## Verifying Webhook Signatures
|
|
30
|
+
*
|
|
31
|
+
* All webhooks are signed using HMAC-SHA256. You should always verify the signature
|
|
32
|
+
* to ensure the webhook originated from Linq and hasn't been tampered with.
|
|
33
|
+
*
|
|
34
|
+
* **Signature Construction:**
|
|
35
|
+
*
|
|
36
|
+
* The signature is computed over a concatenation of the timestamp and payload:
|
|
37
|
+
*
|
|
38
|
+
* ```
|
|
39
|
+
* {timestamp}.{payload}
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* Where:
|
|
43
|
+
* - `timestamp` is the value from the `X-Webhook-Timestamp` header
|
|
44
|
+
* - `payload` is the raw JSON request body (exact bytes, not re-serialized)
|
|
45
|
+
*
|
|
46
|
+
* **Verification Steps:**
|
|
47
|
+
*
|
|
48
|
+
* 1. Extract the `X-Webhook-Timestamp` and `X-Webhook-Signature` headers
|
|
49
|
+
* 2. Get the raw request body bytes (do not parse and re-serialize)
|
|
50
|
+
* 3. Concatenate: `"{timestamp}.{payload}"`
|
|
51
|
+
* 4. Compute HMAC-SHA256 using your signing secret as the key
|
|
52
|
+
* 5. Hex-encode the result and compare with `X-Webhook-Signature`
|
|
53
|
+
* 6. Use constant-time comparison to prevent timing attacks
|
|
54
|
+
*
|
|
55
|
+
* **Example (Python):**
|
|
56
|
+
*
|
|
57
|
+
* ```python
|
|
58
|
+
* import hmac
|
|
59
|
+
* import hashlib
|
|
60
|
+
*
|
|
61
|
+
* def verify_webhook(signing_secret, payload, timestamp, signature):
|
|
62
|
+
* message = f"{timestamp}.{payload.decode('utf-8')}"
|
|
63
|
+
* expected = hmac.new(
|
|
64
|
+
* signing_secret.encode('utf-8'),
|
|
65
|
+
* message.encode('utf-8'),
|
|
66
|
+
* hashlib.sha256
|
|
67
|
+
* ).hexdigest()
|
|
68
|
+
* return hmac.compare_digest(expected, signature)
|
|
69
|
+
* ```
|
|
70
|
+
*
|
|
71
|
+
* **Example (Node.js):**
|
|
72
|
+
*
|
|
73
|
+
* ```javascript
|
|
74
|
+
* const crypto = require('crypto');
|
|
75
|
+
*
|
|
76
|
+
* function verifyWebhook(signingSecret, payload, timestamp, signature) {
|
|
77
|
+
* const message = `${timestamp}.${payload}`;
|
|
78
|
+
* const expected = crypto
|
|
79
|
+
* .createHmac('sha256', signingSecret)
|
|
80
|
+
* .update(message)
|
|
81
|
+
* .digest('hex');
|
|
82
|
+
* return crypto.timingSafeEqual(
|
|
83
|
+
* Buffer.from(expected),
|
|
84
|
+
* Buffer.from(signature)
|
|
85
|
+
* );
|
|
86
|
+
* }
|
|
87
|
+
* ```
|
|
88
|
+
*
|
|
89
|
+
* **Security Best Practices:**
|
|
90
|
+
*
|
|
91
|
+
* - Reject webhooks with timestamps older than 5 minutes to prevent replay attacks
|
|
92
|
+
* - Always use constant-time comparison for signature verification
|
|
93
|
+
* - Store your signing secret securely (e.g., environment variable, secrets manager)
|
|
94
|
+
* - Return a 2xx status code quickly, then process the webhook asynchronously
|
|
95
|
+
*/
|
|
7
96
|
export class WebhookEvents extends APIResource {
|
|
8
97
|
/**
|
|
9
98
|
* Returns all available webhook event types that can be subscribed to. Use this
|
|
@@ -24,6 +113,7 @@ export type WebhookEventType =
|
|
|
24
113
|
| 'message.read'
|
|
25
114
|
| 'message.delivered'
|
|
26
115
|
| 'message.failed'
|
|
116
|
+
| 'message.edited'
|
|
27
117
|
| 'reaction.added'
|
|
28
118
|
| 'reaction.removed'
|
|
29
119
|
| 'participant.added'
|
|
@@ -7,6 +7,95 @@ import { buildHeaders } from '../internal/headers';
|
|
|
7
7
|
import { RequestOptions } from '../internal/request-options';
|
|
8
8
|
import { path } from '../internal/utils/path';
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Webhook Subscriptions allow you to receive real-time notifications when events
|
|
12
|
+
* occur on your account.
|
|
13
|
+
*
|
|
14
|
+
* Configure webhook endpoints to receive events such as messages sent/received,
|
|
15
|
+
* delivery status changes, reactions, typing indicators, and more.
|
|
16
|
+
*
|
|
17
|
+
* Failed deliveries (5xx, 429, network errors) are retried up to 10 times over
|
|
18
|
+
* ~2 hours with exponential backoff. Each event includes a unique ID for
|
|
19
|
+
* deduplication.
|
|
20
|
+
*
|
|
21
|
+
* ## Webhook Headers
|
|
22
|
+
*
|
|
23
|
+
* Each webhook request includes the following headers:
|
|
24
|
+
*
|
|
25
|
+
* | Header | Description |
|
|
26
|
+
* |--------|-------------|
|
|
27
|
+
* | `X-Webhook-Event` | The event type (e.g., `message.sent`, `message.received`) |
|
|
28
|
+
* | `X-Webhook-Subscription-ID` | Your webhook subscription ID |
|
|
29
|
+
* | `X-Webhook-Timestamp` | Unix timestamp (seconds) when the webhook was sent |
|
|
30
|
+
* | `X-Webhook-Signature` | HMAC-SHA256 signature for verification |
|
|
31
|
+
*
|
|
32
|
+
* ## Verifying Webhook Signatures
|
|
33
|
+
*
|
|
34
|
+
* All webhooks are signed using HMAC-SHA256. You should always verify the signature
|
|
35
|
+
* to ensure the webhook originated from Linq and hasn't been tampered with.
|
|
36
|
+
*
|
|
37
|
+
* **Signature Construction:**
|
|
38
|
+
*
|
|
39
|
+
* The signature is computed over a concatenation of the timestamp and payload:
|
|
40
|
+
*
|
|
41
|
+
* ```
|
|
42
|
+
* {timestamp}.{payload}
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* Where:
|
|
46
|
+
* - `timestamp` is the value from the `X-Webhook-Timestamp` header
|
|
47
|
+
* - `payload` is the raw JSON request body (exact bytes, not re-serialized)
|
|
48
|
+
*
|
|
49
|
+
* **Verification Steps:**
|
|
50
|
+
*
|
|
51
|
+
* 1. Extract the `X-Webhook-Timestamp` and `X-Webhook-Signature` headers
|
|
52
|
+
* 2. Get the raw request body bytes (do not parse and re-serialize)
|
|
53
|
+
* 3. Concatenate: `"{timestamp}.{payload}"`
|
|
54
|
+
* 4. Compute HMAC-SHA256 using your signing secret as the key
|
|
55
|
+
* 5. Hex-encode the result and compare with `X-Webhook-Signature`
|
|
56
|
+
* 6. Use constant-time comparison to prevent timing attacks
|
|
57
|
+
*
|
|
58
|
+
* **Example (Python):**
|
|
59
|
+
*
|
|
60
|
+
* ```python
|
|
61
|
+
* import hmac
|
|
62
|
+
* import hashlib
|
|
63
|
+
*
|
|
64
|
+
* def verify_webhook(signing_secret, payload, timestamp, signature):
|
|
65
|
+
* message = f"{timestamp}.{payload.decode('utf-8')}"
|
|
66
|
+
* expected = hmac.new(
|
|
67
|
+
* signing_secret.encode('utf-8'),
|
|
68
|
+
* message.encode('utf-8'),
|
|
69
|
+
* hashlib.sha256
|
|
70
|
+
* ).hexdigest()
|
|
71
|
+
* return hmac.compare_digest(expected, signature)
|
|
72
|
+
* ```
|
|
73
|
+
*
|
|
74
|
+
* **Example (Node.js):**
|
|
75
|
+
*
|
|
76
|
+
* ```javascript
|
|
77
|
+
* const crypto = require('crypto');
|
|
78
|
+
*
|
|
79
|
+
* function verifyWebhook(signingSecret, payload, timestamp, signature) {
|
|
80
|
+
* const message = `${timestamp}.${payload}`;
|
|
81
|
+
* const expected = crypto
|
|
82
|
+
* .createHmac('sha256', signingSecret)
|
|
83
|
+
* .update(message)
|
|
84
|
+
* .digest('hex');
|
|
85
|
+
* return crypto.timingSafeEqual(
|
|
86
|
+
* Buffer.from(expected),
|
|
87
|
+
* Buffer.from(signature)
|
|
88
|
+
* );
|
|
89
|
+
* }
|
|
90
|
+
* ```
|
|
91
|
+
*
|
|
92
|
+
* **Security Best Practices:**
|
|
93
|
+
*
|
|
94
|
+
* - Reject webhooks with timestamps older than 5 minutes to prevent replay attacks
|
|
95
|
+
* - Always use constant-time comparison for signature verification
|
|
96
|
+
* - Store your signing secret securely (e.g., environment variable, secrets manager)
|
|
97
|
+
* - Return a 2xx status code quickly, then process the webhook asynchronously
|
|
98
|
+
*/
|
|
10
99
|
export class WebhookSubscriptions extends APIResource {
|
|
11
100
|
/**
|
|
12
101
|
* Create a new webhook subscription to receive events at a target URL. Upon
|