@linqapp/sdk 0.25.0 → 0.26.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.
Files changed (179) hide show
  1. package/CHANGELOG.md +2 -2
  2. package/api-promise.d.mts +1 -0
  3. package/api-promise.d.mts.map +1 -1
  4. package/api-promise.d.ts +1 -0
  5. package/api-promise.d.ts.map +1 -1
  6. package/api-promise.mjs +1 -0
  7. package/api-promise.mjs.map +1 -1
  8. package/client.d.mts +162 -84
  9. package/client.d.mts.map +1 -1
  10. package/client.d.ts +162 -84
  11. package/client.d.ts.map +1 -1
  12. package/client.js +162 -84
  13. package/client.js.map +1 -1
  14. package/client.mjs +162 -84
  15. package/client.mjs.map +1 -1
  16. package/core/api-promise.d.mts.map +1 -1
  17. package/core/api-promise.d.ts.map +1 -1
  18. package/core/api-promise.mjs.map +1 -1
  19. package/core/error.mjs.map +1 -1
  20. package/core/pagination.d.mts.map +1 -1
  21. package/core/pagination.d.ts.map +1 -1
  22. package/core/pagination.mjs.map +1 -1
  23. package/core/resource.d.mts.map +1 -1
  24. package/core/resource.d.ts.map +1 -1
  25. package/core/uploads.d.mts.map +1 -1
  26. package/core/uploads.d.ts.map +1 -1
  27. package/core/uploads.mjs.map +1 -1
  28. package/error.d.mts +1 -0
  29. package/error.d.mts.map +1 -1
  30. package/error.d.ts +1 -0
  31. package/error.d.ts.map +1 -1
  32. package/error.mjs +1 -0
  33. package/error.mjs.map +1 -1
  34. package/index.d.mts.map +1 -1
  35. package/index.d.ts.map +1 -1
  36. package/index.mjs.map +1 -1
  37. package/internal/detect-platform.mjs.map +1 -1
  38. package/internal/headers.mjs.map +1 -1
  39. package/internal/parse.d.mts.map +1 -1
  40. package/internal/parse.d.ts.map +1 -1
  41. package/internal/parse.mjs.map +1 -1
  42. package/internal/request-options.d.mts.map +1 -1
  43. package/internal/request-options.d.ts.map +1 -1
  44. package/internal/shims.d.mts +6 -0
  45. package/internal/shims.d.mts.map +1 -1
  46. package/internal/shims.d.ts +6 -0
  47. package/internal/shims.d.ts.map +1 -1
  48. package/internal/to-file.d.mts.map +1 -1
  49. package/internal/to-file.d.ts.map +1 -1
  50. package/internal/to-file.mjs.map +1 -1
  51. package/internal/types.d.mts +4 -4
  52. package/internal/types.d.mts.map +1 -1
  53. package/internal/types.d.ts +4 -4
  54. package/internal/types.d.ts.map +1 -1
  55. package/internal/uploads.d.mts.map +1 -1
  56. package/internal/uploads.d.ts.map +1 -1
  57. package/internal/uploads.mjs.map +1 -1
  58. package/internal/utils/base64.mjs.map +1 -1
  59. package/internal/utils/log.d.mts.map +1 -1
  60. package/internal/utils/log.d.ts.map +1 -1
  61. package/internal/utils/log.mjs.map +1 -1
  62. package/internal/utils/path.mjs.map +1 -1
  63. package/internal/utils/query.mjs.map +1 -1
  64. package/internal/utils/values.mjs.map +1 -1
  65. package/internal/utils.d.mts.map +1 -1
  66. package/internal/utils.d.ts.map +1 -1
  67. package/internal/utils.mjs.map +1 -1
  68. package/package.json +1 -1
  69. package/pagination.d.mts +1 -0
  70. package/pagination.d.mts.map +1 -1
  71. package/pagination.d.ts +1 -0
  72. package/pagination.d.ts.map +1 -1
  73. package/pagination.mjs +1 -0
  74. package/pagination.mjs.map +1 -1
  75. package/resource.d.mts +1 -0
  76. package/resource.d.mts.map +1 -1
  77. package/resource.d.ts +1 -0
  78. package/resource.d.ts.map +1 -1
  79. package/resource.mjs +1 -0
  80. package/resource.mjs.map +1 -1
  81. package/resources/attachments.d.mts.map +1 -1
  82. package/resources/attachments.d.ts.map +1 -1
  83. package/resources/attachments.mjs.map +1 -1
  84. package/resources/capability.d.mts.map +1 -1
  85. package/resources/capability.d.ts.map +1 -1
  86. package/resources/capability.mjs.map +1 -1
  87. package/resources/chats/chats.d.mts +4 -0
  88. package/resources/chats/chats.d.mts.map +1 -1
  89. package/resources/chats/chats.d.ts +4 -0
  90. package/resources/chats/chats.d.ts.map +1 -1
  91. package/resources/chats/chats.js +4 -0
  92. package/resources/chats/chats.js.map +1 -1
  93. package/resources/chats/chats.mjs +4 -0
  94. package/resources/chats/chats.mjs.map +1 -1
  95. package/resources/chats/index.d.mts +1 -0
  96. package/resources/chats/index.d.mts.map +1 -1
  97. package/resources/chats/index.d.ts +1 -0
  98. package/resources/chats/index.d.ts.map +1 -1
  99. package/resources/chats/index.js +3 -1
  100. package/resources/chats/index.js.map +1 -1
  101. package/resources/chats/index.mjs +1 -0
  102. package/resources/chats/index.mjs.map +1 -1
  103. package/resources/chats/location.d.mts +107 -0
  104. package/resources/chats/location.d.mts.map +1 -0
  105. package/resources/chats/location.d.ts +107 -0
  106. package/resources/chats/location.d.ts.map +1 -0
  107. package/resources/chats/location.js +68 -0
  108. package/resources/chats/location.js.map +1 -0
  109. package/resources/chats/location.mjs +64 -0
  110. package/resources/chats/location.mjs.map +1 -0
  111. package/resources/chats/messages.d.mts.map +1 -1
  112. package/resources/chats/messages.d.ts.map +1 -1
  113. package/resources/chats/messages.mjs.map +1 -1
  114. package/resources/chats/participants.d.mts.map +1 -1
  115. package/resources/chats/participants.d.ts.map +1 -1
  116. package/resources/chats/participants.mjs.map +1 -1
  117. package/resources/chats/typing.d.mts.map +1 -1
  118. package/resources/chats/typing.d.ts.map +1 -1
  119. package/resources/chats/typing.mjs.map +1 -1
  120. package/resources/chats.d.mts.map +1 -1
  121. package/resources/chats.d.ts.map +1 -1
  122. package/resources/chats.mjs.map +1 -1
  123. package/resources/contact-card.d.mts.map +1 -1
  124. package/resources/contact-card.d.ts.map +1 -1
  125. package/resources/contact-card.mjs.map +1 -1
  126. package/resources/index.d.mts.map +1 -1
  127. package/resources/index.d.ts.map +1 -1
  128. package/resources/index.mjs.map +1 -1
  129. package/resources/messages.d.mts.map +1 -1
  130. package/resources/messages.d.ts.map +1 -1
  131. package/resources/messages.mjs.map +1 -1
  132. package/resources/phone-numbers.d.mts.map +1 -1
  133. package/resources/phone-numbers.d.ts.map +1 -1
  134. package/resources/phone-numbers.mjs.map +1 -1
  135. package/resources/phonenumbers.d.mts.map +1 -1
  136. package/resources/phonenumbers.d.ts.map +1 -1
  137. package/resources/phonenumbers.mjs.map +1 -1
  138. package/resources/webhook-events.d.mts +83 -44
  139. package/resources/webhook-events.d.mts.map +1 -1
  140. package/resources/webhook-events.d.ts +83 -44
  141. package/resources/webhook-events.d.ts.map +1 -1
  142. package/resources/webhook-events.js +81 -42
  143. package/resources/webhook-events.js.map +1 -1
  144. package/resources/webhook-events.mjs +81 -42
  145. package/resources/webhook-events.mjs.map +1 -1
  146. package/resources/webhook-subscriptions.d.mts +89 -44
  147. package/resources/webhook-subscriptions.d.mts.map +1 -1
  148. package/resources/webhook-subscriptions.d.ts +89 -44
  149. package/resources/webhook-subscriptions.d.ts.map +1 -1
  150. package/resources/webhook-subscriptions.js +90 -45
  151. package/resources/webhook-subscriptions.js.map +1 -1
  152. package/resources/webhook-subscriptions.mjs +90 -45
  153. package/resources/webhook-subscriptions.mjs.map +1 -1
  154. package/resources/webhooks.d.mts +4 -4
  155. package/resources/webhooks.d.mts.map +1 -1
  156. package/resources/webhooks.d.ts +4 -4
  157. package/resources/webhooks.d.ts.map +1 -1
  158. package/resources/webhooks.mjs.map +1 -1
  159. package/resources.d.mts.map +1 -1
  160. package/resources.d.ts.map +1 -1
  161. package/resources.mjs.map +1 -1
  162. package/src/client.ts +162 -84
  163. package/src/resources/chats/chats.ts +10 -0
  164. package/src/resources/chats/index.ts +1 -0
  165. package/src/resources/chats/location.ts +138 -0
  166. package/src/resources/webhook-events.ts +85 -44
  167. package/src/resources/webhook-subscriptions.ts +89 -44
  168. package/src/resources/webhooks.ts +6 -4
  169. package/src/version.ts +1 -1
  170. package/uploads.d.mts +1 -0
  171. package/uploads.d.mts.map +1 -1
  172. package/uploads.d.ts +1 -0
  173. package/uploads.d.ts.map +1 -1
  174. package/uploads.mjs +1 -0
  175. package/uploads.mjs.map +1 -1
  176. package/version.d.mts +1 -1
  177. package/version.d.ts +1 -1
  178. package/version.js +1 -1
  179. package/version.mjs +1 -1
@@ -17,55 +17,82 @@ import { RequestOptions } from '../internal/request-options';
17
17
  *
18
18
  * ## Webhook Headers
19
19
  *
20
- * Each webhook request includes the following headers:
20
+ * All webhook requests include two sets of headers. **If you have an existing integration
21
+ * using the `X-Webhook-*` headers, nothing changes** — those headers are still sent on
22
+ * every delivery and work exactly as before. The new `webhook-*` headers follow the
23
+ * [Standard Webhooks](https://github.com/standard-webhooks/standard-webhooks) specification.
24
+ * You can safely ignore them if your current verification code works and you don't want to use this convention.
25
+ *
26
+ * ### Standard Webhooks Headers (Recommended)
27
+ *
28
+ * Used by [our SDK](https://github.com/linq-team/linq-node) and any [Standard Webhooks library](https://github.com/standard-webhooks/standard-webhooks).
21
29
  *
22
30
  * | Header | Description |
23
31
  * |--------|-------------|
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 |
32
+ * | `webhook-id` | Unique event identifier (use as idempotency key) |
33
+ * | `webhook-timestamp` | Unix timestamp (seconds) when the webhook was sent |
34
+ * | `webhook-signature` | Standard Webhooks signature (`v1,{base64}` format) |
28
35
  *
29
- * ## Verifying Webhook Signatures
36
+ * ### Legacy Headers (Deprecated)
37
+ *
38
+ * Still sent on every delivery for backwards compatibility. Existing verification code
39
+ * using these headers continues to work — no changes required.
30
40
  *
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.
41
+ * | Header | Description |
42
+ * |--------|-------------|
43
+ * | `X-Webhook-Event` | *(deprecated)* Event type (e.g., `message.sent`) |
44
+ * | `X-Webhook-Subscription-ID` | *(deprecated)* Webhook subscription ID |
45
+ * | `X-Webhook-Timestamp` | *(deprecated)* Unix timestamp (seconds) |
46
+ * | `X-Webhook-Signature` | *(deprecated)* HMAC-SHA256 signature (hex-encoded) |
33
47
  *
34
- * **Signature Construction:**
48
+ * ## Signing Secrets
35
49
  *
36
- * The signature is computed over a concatenation of the timestamp and payload:
50
+ * Signing secrets use the Standard Webhooks format: a `whsec_` prefix followed
51
+ * by base64-encoded random bytes (e.g., `whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw7Jxx2Oll+OE=`).
37
52
  *
38
- * ```
39
- * {timestamp}.{payload}
40
- * ```
53
+ * Strip the `whsec_` prefix and base64-decode the remainder to get the raw key bytes.
41
54
  *
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)
55
+ * ## Verifying Webhook Signatures
56
+ *
57
+ * Webhooks are signed following the [Standard Webhooks specification](https://github.com/standard-webhooks/standard-webhooks).
58
+ * You can use any [Standard Webhooks library](https://github.com/standard-webhooks/standard-webhooks) to verify
59
+ * signatures, or implement verification manually:
60
+ *
61
+ * **Signed content:** `{webhook-id}.{webhook-timestamp}.{body}`
45
62
  *
46
63
  * **Verification Steps:**
47
64
  *
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
65
+ * 1. Extract the `webhook-id`, `webhook-timestamp`, and `webhook-signature` headers
66
+ * 2. Reject if the timestamp is more than 5 minutes old (replay protection)
67
+ * 3. Get the raw request body bytes (do not parse and re-serialize)
68
+ * 4. Construct signed content: `"{webhook-id}.{webhook-timestamp}.{body}"`
69
+ * 5. Strip the `whsec_` prefix from your secret and base64-decode to get key bytes
70
+ * 6. Compute HMAC-SHA256 using the key bytes over the signed content
71
+ * 7. Base64-encode the result and compare with the value after `v1,` in `webhook-signature`
72
+ * 8. Use constant-time comparison to prevent timing attacks
54
73
  *
55
74
  * **Example (Python):**
56
75
  *
57
76
  * ```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)
77
+ * import base64, hmac, hashlib
78
+ *
79
+ * def verify_webhook(secret, body, headers):
80
+ * msg_id = headers['webhook-id']
81
+ * timestamp = headers['webhook-timestamp']
82
+ * signature = headers['webhook-signature']
83
+ *
84
+ * secret_str = secret.removeprefix('whsec_')
85
+ * key = base64.b64decode(secret_str)
86
+ *
87
+ * signed_content = f"{msg_id}.{timestamp}.{body}"
88
+ * expected = base64.b64encode(
89
+ * hmac.new(key, signed_content.encode(), hashlib.sha256).digest()
90
+ * ).decode()
91
+ *
92
+ * for sig in signature.split(' '):
93
+ * if sig.startswith('v1,') and hmac.compare_digest(expected, sig[3:]):
94
+ * return True
95
+ * return False
69
96
  * ```
70
97
  *
71
98
  * **Example (Node.js):**
@@ -73,16 +100,28 @@ import { RequestOptions } from '../internal/request-options';
73
100
  * ```javascript
74
101
  * const crypto = require('crypto');
75
102
  *
76
- * function verifyWebhook(signingSecret, payload, timestamp, signature) {
77
- * const message = `${timestamp}.${payload}`;
103
+ * function verifyWebhook(secret, rawBody, headers) {
104
+ * const msgId = headers['webhook-id'];
105
+ * const timestamp = headers['webhook-timestamp'];
106
+ * const signature = headers['webhook-signature'];
107
+ *
108
+ * const secretStr = secret.startsWith('whsec_') ? secret.slice(6) : secret;
109
+ * const keyBytes = Buffer.from(secretStr, 'base64');
110
+ * const signedContent = `${msgId}.${timestamp}.${rawBody}`;
78
111
  * 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
- * );
112
+ * .createHmac('sha256', keyBytes)
113
+ * .update(signedContent)
114
+ * .digest('base64');
115
+ *
116
+ * return signature.split(' ').some(sig => {
117
+ * if (!sig.startsWith('v1,')) return false;
118
+ * try {
119
+ * return crypto.timingSafeEqual(
120
+ * Buffer.from(expected, 'base64'),
121
+ * Buffer.from(sig.slice(3), 'base64')
122
+ * );
123
+ * } catch { return false; }
124
+ * });
86
125
  * }
87
126
  * ```
88
127
  *
@@ -136,13 +175,15 @@ export type WebhookEventType =
136
175
  | 'call.ended'
137
176
  | 'call.failed'
138
177
  | 'call.declined'
139
- | 'call.no_answer';
178
+ | 'call.no_answer'
179
+ | 'location.sharing.started'
180
+ | 'location.sharing.stopped';
140
181
 
141
182
  export interface WebhookEventListResponse {
142
183
  /**
143
184
  * URL to the webhook events documentation
144
185
  */
145
- doc_url: 'https://apidocs.linqapp.com/documentation/webhook-events';
186
+ doc_url: 'https://docs.linqapp.com/guides/webhooks/events';
146
187
 
147
188
  /**
148
189
  * List of all available webhook event types
@@ -20,55 +20,82 @@ import { path } from '../internal/utils/path';
20
20
  *
21
21
  * ## Webhook Headers
22
22
  *
23
- * Each webhook request includes the following headers:
23
+ * All webhook requests include two sets of headers. **If you have an existing integration
24
+ * using the `X-Webhook-*` headers, nothing changes** — those headers are still sent on
25
+ * every delivery and work exactly as before. The new `webhook-*` headers follow the
26
+ * [Standard Webhooks](https://github.com/standard-webhooks/standard-webhooks) specification.
27
+ * You can safely ignore them if your current verification code works and you don't want to use this convention.
28
+ *
29
+ * ### Standard Webhooks Headers (Recommended)
30
+ *
31
+ * Used by [our SDK](https://github.com/linq-team/linq-node) and any [Standard Webhooks library](https://github.com/standard-webhooks/standard-webhooks).
24
32
  *
25
33
  * | Header | Description |
26
34
  * |--------|-------------|
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 |
35
+ * | `webhook-id` | Unique event identifier (use as idempotency key) |
36
+ * | `webhook-timestamp` | Unix timestamp (seconds) when the webhook was sent |
37
+ * | `webhook-signature` | Standard Webhooks signature (`v1,{base64}` format) |
31
38
  *
32
- * ## Verifying Webhook Signatures
39
+ * ### Legacy Headers (Deprecated)
40
+ *
41
+ * Still sent on every delivery for backwards compatibility. Existing verification code
42
+ * using these headers continues to work — no changes required.
33
43
  *
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.
44
+ * | Header | Description |
45
+ * |--------|-------------|
46
+ * | `X-Webhook-Event` | *(deprecated)* Event type (e.g., `message.sent`) |
47
+ * | `X-Webhook-Subscription-ID` | *(deprecated)* Webhook subscription ID |
48
+ * | `X-Webhook-Timestamp` | *(deprecated)* Unix timestamp (seconds) |
49
+ * | `X-Webhook-Signature` | *(deprecated)* HMAC-SHA256 signature (hex-encoded) |
36
50
  *
37
- * **Signature Construction:**
51
+ * ## Signing Secrets
38
52
  *
39
- * The signature is computed over a concatenation of the timestamp and payload:
53
+ * Signing secrets use the Standard Webhooks format: a `whsec_` prefix followed
54
+ * by base64-encoded random bytes (e.g., `whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw7Jxx2Oll+OE=`).
40
55
  *
41
- * ```
42
- * {timestamp}.{payload}
43
- * ```
56
+ * Strip the `whsec_` prefix and base64-decode the remainder to get the raw key bytes.
44
57
  *
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)
58
+ * ## Verifying Webhook Signatures
59
+ *
60
+ * Webhooks are signed following the [Standard Webhooks specification](https://github.com/standard-webhooks/standard-webhooks).
61
+ * You can use any [Standard Webhooks library](https://github.com/standard-webhooks/standard-webhooks) to verify
62
+ * signatures, or implement verification manually:
63
+ *
64
+ * **Signed content:** `{webhook-id}.{webhook-timestamp}.{body}`
48
65
  *
49
66
  * **Verification Steps:**
50
67
  *
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
68
+ * 1. Extract the `webhook-id`, `webhook-timestamp`, and `webhook-signature` headers
69
+ * 2. Reject if the timestamp is more than 5 minutes old (replay protection)
70
+ * 3. Get the raw request body bytes (do not parse and re-serialize)
71
+ * 4. Construct signed content: `"{webhook-id}.{webhook-timestamp}.{body}"`
72
+ * 5. Strip the `whsec_` prefix from your secret and base64-decode to get key bytes
73
+ * 6. Compute HMAC-SHA256 using the key bytes over the signed content
74
+ * 7. Base64-encode the result and compare with the value after `v1,` in `webhook-signature`
75
+ * 8. Use constant-time comparison to prevent timing attacks
57
76
  *
58
77
  * **Example (Python):**
59
78
  *
60
79
  * ```python
61
- * import hmac
62
- * import hashlib
80
+ * import base64, hmac, hashlib
81
+ *
82
+ * def verify_webhook(secret, body, headers):
83
+ * msg_id = headers['webhook-id']
84
+ * timestamp = headers['webhook-timestamp']
85
+ * signature = headers['webhook-signature']
63
86
  *
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)
87
+ * secret_str = secret.removeprefix('whsec_')
88
+ * key = base64.b64decode(secret_str)
89
+ *
90
+ * signed_content = f"{msg_id}.{timestamp}.{body}"
91
+ * expected = base64.b64encode(
92
+ * hmac.new(key, signed_content.encode(), hashlib.sha256).digest()
93
+ * ).decode()
94
+ *
95
+ * for sig in signature.split(' '):
96
+ * if sig.startswith('v1,') and hmac.compare_digest(expected, sig[3:]):
97
+ * return True
98
+ * return False
72
99
  * ```
73
100
  *
74
101
  * **Example (Node.js):**
@@ -76,16 +103,28 @@ import { path } from '../internal/utils/path';
76
103
  * ```javascript
77
104
  * const crypto = require('crypto');
78
105
  *
79
- * function verifyWebhook(signingSecret, payload, timestamp, signature) {
80
- * const message = `${timestamp}.${payload}`;
106
+ * function verifyWebhook(secret, rawBody, headers) {
107
+ * const msgId = headers['webhook-id'];
108
+ * const timestamp = headers['webhook-timestamp'];
109
+ * const signature = headers['webhook-signature'];
110
+ *
111
+ * const secretStr = secret.startsWith('whsec_') ? secret.slice(6) : secret;
112
+ * const keyBytes = Buffer.from(secretStr, 'base64');
113
+ * const signedContent = `${msgId}.${timestamp}.${rawBody}`;
81
114
  * 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
- * );
115
+ * .createHmac('sha256', keyBytes)
116
+ * .update(signedContent)
117
+ * .digest('base64');
118
+ *
119
+ * return signature.split(' ').some(sig => {
120
+ * if (!sig.startsWith('v1,')) return false;
121
+ * try {
122
+ * return crypto.timingSafeEqual(
123
+ * Buffer.from(expected, 'base64'),
124
+ * Buffer.from(sig.slice(3), 'base64')
125
+ * );
126
+ * } catch { return false; }
127
+ * });
89
128
  * }
90
129
  * ```
91
130
  *
@@ -115,9 +154,15 @@ export class WebhookSubscriptions extends APIResource {
115
154
  * **Webhook Delivery:**
116
155
  *
117
156
  * - Events are sent via HTTP POST to the target URL
118
- * - Each request includes `X-Webhook-Signature` and `X-Webhook-Timestamp` headers
119
- * - Signature is HMAC-SHA256 over `{timestamp}.{payload}` — see
120
- * [Webhook Events](/docs/webhook-events) for verification details
157
+ * - Each request includes
158
+ * [Standard Webhooks](https://github.com/standard-webhooks/standard-webhooks)
159
+ * headers (`webhook-id`, `webhook-timestamp`, `webhook-signature`) for signature
160
+ * verification
161
+ * - Legacy `X-Webhook-*` headers are also sent for backwards compatibility
162
+ * (deprecated)
163
+ * - See
164
+ * [Verifying Webhook Signatures](https://docs.linqapp.com/guides/webhooks#verifying-webhook-signatures)
165
+ * for verification details
121
166
  * - Failed deliveries (5xx, 429, network errors) are retried up to 10 times over
122
167
  * ~25 minutes with exponential backoff
123
168
  * - Client errors (4xx except 429) are not retried
@@ -794,7 +794,7 @@ export namespace MessageFailedWebhookEvent {
794
794
  */
795
795
  export interface Data {
796
796
  /**
797
- * Error codes in webhook failure events (3007, 4001).
797
+ * Error codes in webhook failure events (3007, 4001, 4005).
798
798
  */
799
799
  code: number;
800
800
 
@@ -1638,7 +1638,7 @@ export namespace ChatGroupNameUpdateFailedWebhookEvent {
1638
1638
  chat_id: string;
1639
1639
 
1640
1640
  /**
1641
- * Error codes in webhook failure events (3007, 4001).
1641
+ * Error codes in webhook failure events (3007, 4001, 4005).
1642
1642
  */
1643
1643
  error_code: number;
1644
1644
 
@@ -1715,7 +1715,7 @@ export namespace ChatGroupIconUpdateFailedWebhookEvent {
1715
1715
  chat_id: string;
1716
1716
 
1717
1717
  /**
1718
- * Error codes in webhook failure events (3007, 4001).
1718
+ * Error codes in webhook failure events (3007, 4001, 4005).
1719
1719
  */
1720
1720
  error_code: number;
1721
1721
 
@@ -1904,7 +1904,9 @@ export interface PhoneNumberStatusUpdatedWebhookEvent {
1904
1904
  | 'call.ended'
1905
1905
  | 'call.failed'
1906
1906
  | 'call.declined'
1907
- | 'call.no_answer';
1907
+ | 'call.no_answer'
1908
+ | 'location.sharing.started'
1909
+ | 'location.sharing.stopped';
1908
1910
 
1909
1911
  /**
1910
1912
  * Partner identifier. Present on all webhooks for cross-referencing.
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const VERSION = '0.25.0'; // x-release-please-version
1
+ export const VERSION = '0.26.0'; // x-release-please-version
package/uploads.d.mts CHANGED
@@ -1,2 +1,3 @@
1
+ /** @deprecated Import from ./core/uploads instead */
1
2
  export * from "./core/uploads.mjs";
2
3
  //# sourceMappingURL=uploads.d.mts.map
package/uploads.d.mts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"uploads.d.mts","sourceRoot":"","sources":["src/uploads.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"uploads.d.mts","sourceRoot":"","sources":["src/uploads.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,mCAA+B"}
package/uploads.d.ts CHANGED
@@ -1,2 +1,3 @@
1
+ /** @deprecated Import from ./core/uploads instead */
1
2
  export * from "./core/uploads.js";
2
3
  //# sourceMappingURL=uploads.d.ts.map
package/uploads.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"uploads.d.ts","sourceRoot":"","sources":["src/uploads.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"uploads.d.ts","sourceRoot":"","sources":["src/uploads.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,kCAA+B"}
package/uploads.mjs CHANGED
@@ -1,2 +1,3 @@
1
+ /** @deprecated Import from ./core/uploads instead */
1
2
  export * from "./core/uploads.mjs";
2
3
  //# sourceMappingURL=uploads.mjs.map
package/uploads.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"uploads.mjs","sourceRoot":"","sources":["src/uploads.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"uploads.mjs","sourceRoot":"","sources":["src/uploads.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,mCAA+B"}
package/version.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.25.0";
1
+ export declare const VERSION = "0.26.0";
2
2
  //# sourceMappingURL=version.d.mts.map
package/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.25.0";
1
+ export declare const VERSION = "0.26.0";
2
2
  //# sourceMappingURL=version.d.ts.map
package/version.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VERSION = void 0;
4
- exports.VERSION = '0.25.0'; // x-release-please-version
4
+ exports.VERSION = '0.26.0'; // x-release-please-version
5
5
  //# sourceMappingURL=version.js.map
package/version.mjs CHANGED
@@ -1,2 +1,2 @@
1
- export const VERSION = '0.25.0'; // x-release-please-version
1
+ export const VERSION = '0.26.0'; // x-release-please-version
2
2
  //# sourceMappingURL=version.mjs.map