@linqapp/sdk 0.22.0 → 0.23.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/src/client.ts CHANGED
@@ -940,6 +940,122 @@ export class LinqAPIV3 {
940
940
  * - **URL-based (`url` field):** 10MB maximum
941
941
  * - **Pre-upload (`attachment_id`):** 100MB maximum
942
942
  *
943
+ * ## Security & Ownership
944
+ *
945
+ * Every attachment is bound to the partner account that created or received it. The API enforces ownership on every operation that touches an attachment — sending, retrieving, deleting.
946
+ *
947
+ * **What this means for you:**
948
+ *
949
+ * - An attachment created under your API key can only be referenced by your API key.
950
+ * - Submitting another partner's `attachment_id` returns `404 Not Found`. We do not disclose whether the id exists or belongs to someone else.
951
+ * - Submitting a CDN URL that resolves to another partner's attachment is rejected before the send is attempted.
952
+ * - Ownership enforcement applies uniformly across send, create-chat, voice memo, retrieve, and delete operations.
953
+ *
954
+ * Every attachment-affecting endpoint requires a valid partner API key. Unauthenticated calls return `401 Unauthorized`.
955
+ *
956
+ * ## Attachment URL Patterns
957
+ *
958
+ * Attachment URLs in API responses and webhook payloads use one of two layouts, depending on the attachment's tier:
959
+ *
960
+ * | Tier | URL pattern | TTL |
961
+ * |---|---|---|
962
+ * | Persistent (default) | `https://cdn.linqapp.com/attachments/partners/{partner_id}/{attachment_id}/{filename}` | Long-lived |
963
+ * | Ephemeral | Pre-signed URL pointing at the ephemeral prefix on `cdn.linqapp.com` | 15 minutes per signed URL — re-fetch via the API for a fresh URL |
964
+ *
965
+ * Inbound media you receive over webhooks uses the same layout your outbound sends produce, so the URL you store and the URL you build look identical — no special casing in your client.
966
+ *
967
+ * ## Ephemeral Attachments (Privacy Tier)
968
+ *
969
+ * For regulated or sensitive content, opt in to the **ephemeral attachments** tier by contacting your Linq support contact. You can request it at two scopes:
970
+ *
971
+ * | Scope | Effect |
972
+ * |---|---|
973
+ * | **Partner-wide** | Every outbound and inbound attachment on every phone number under your account is routed through the ephemeral tier. |
974
+ * | **Per phone number** | Only the specified phone numbers route their attachments through the ephemeral tier. The rest stay on the persistent tier. |
975
+ *
976
+ * **Behavioral differences vs the persistent default:**
977
+ *
978
+ * | Aspect | Persistent | Ephemeral |
979
+ * |---|---|---|
980
+ * | Download URL form | Long-lived CDN URL | Pre-signed URL with short TTL |
981
+ * | Retention floor | Indefinite (until you call `DELETE`) | **Hard backstop: 1 day** — even without an explicit `DELETE`, the platform removes the underlying bytes after 24 hours |
982
+ * | URL re-fetch | Not required | Fetch via `GET /v3/attachments/{attachmentId}` for a fresh signed URL after TTL expiry |
983
+ * | Cross-partner isolation | Enforced | Enforced |
984
+ *
985
+ * **When to choose ephemeral:**
986
+ *
987
+ * - Your downstream system processes the file immediately on receipt and does not need to re-read it later.
988
+ * - You have a compliance requirement that the platform must not retain attachments beyond a short window.
989
+ * - The content is high-sensitivity (PHI, financial documents, identity verification) and you do not want it sitting behind a long-lived URL.
990
+ *
991
+ * **Important:** ephemeral applies in *both directions* — outbound files you upload **and** inbound media received by the phone numbers in that scope. Download bytes you need to keep promptly, or fetch a fresh signed URL via the API when needed.
992
+ *
993
+ * ## Deleting an Attachment
994
+ *
995
+ * To permanently remove an attachment you own, use:
996
+ *
997
+ * ```http
998
+ * DELETE /v3/attachments/{attachmentId}
999
+ * Authorization: Bearer <your_api_key>
1000
+ * ```
1001
+ *
1002
+ * **What this does:**
1003
+ *
1004
+ * 1. Verifies the attachment is owned by your account. Returns `404` otherwise.
1005
+ * 2. Removes the underlying file from Linq storage.
1006
+ * 3. Records an audit entry (timestamp, partner, attachment id).
1007
+ *
1008
+ * **Response codes:**
1009
+ *
1010
+ * | Status | Meaning |
1011
+ * |---|---|
1012
+ * | `204 No Content` | Deletion succeeded. The attachment is removed from Linq storage. |
1013
+ * | `400 Bad Request` | `attachmentId` is not a valid UUID. |
1014
+ * | `401 Unauthorized` | Missing or invalid API key. |
1015
+ * | `404 Not Found` | Attachment does not exist or is not owned by your account. |
1016
+ * | `500 Internal Server Error` | Transient infrastructure issue — safe to retry. |
1017
+ *
1018
+ * **Effect on message history:**
1019
+ *
1020
+ * - Messages that referenced the deleted attachment remain visible.
1021
+ * - The message part that pointed at the attachment is preserved with no attachment reference.
1022
+ * - Webhook payloads previously delivered to you retain the original URL string, but downloads from that URL return `404` going forward.
1023
+ *
1024
+ * Deletion is **irreversible**. Once `204` is returned, the bytes are gone — there is no undelete.
1025
+ *
1026
+ * ## Inbound Media Flow
1027
+ *
1028
+ * When one of your phone numbers receives a message with media (image, video, audio, document), the platform:
1029
+ *
1030
+ * 1. Stores the file under your partner account.
1031
+ * 2. Records metadata linked to the inbound message.
1032
+ * 3. Delivers a webhook whose `parts[]` array includes a `media` part with a `url` pointing at `cdn.linqapp.com`.
1033
+ * 4. If the receiving phone is opted in to ephemeral, the `url` is a short-TTL signed URL.
1034
+ *
1035
+ * You can acknowledge the webhook without fetching the file inline, and lazy-load via `GET /v3/attachments/{attachmentId}` later. For ephemeral attachments, retrieving via the API always returns a freshly-signed URL.
1036
+ *
1037
+ * ## Data Lifecycle Summary
1038
+ *
1039
+ * | Data | Persistent tier | Ephemeral tier |
1040
+ * |---|---|---|
1041
+ * | Attachment bytes | Retained until you `DELETE` | **Auto-removed after 1 day**, also removable via `DELETE` |
1042
+ * | Attachment metadata (id, filename, mime type, size) | Retained until you `DELETE` | Removed alongside the bytes |
1043
+ * | Message body & parts | Retained per message-retention policy | Retained per message-retention policy |
1044
+ * | Audit log of deletions | Retained per platform retention policy | Retained per platform retention policy |
1045
+ *
1046
+ * **In transit:** TLS 1.2+ everywhere. **At rest:** AES-256 (server-side encryption).
1047
+ *
1048
+ * ## Compliance Checklist
1049
+ *
1050
+ * If you're integrating Linq under a security or privacy review, here is the short list:
1051
+ *
1052
+ * - Allowlist exactly one outbound domain: `cdn.linqapp.com`.
1053
+ * - Decide whether you need ephemeral attachments (high-sensitivity content) — request enablement through your Linq support contact.
1054
+ * - Implement `DELETE /v3/attachments/{attachmentId}` calls in your deletion workflow.
1055
+ * - Persist any attachments your application needs long-term — Linq is the authoritative source until you delete, but the ephemeral tier auto-purges after 1 day.
1056
+ * - For audit: every deletion is logged on Linq's side. Surface a confirmation in your application UI based on the `204` response.
1057
+ * - For end-user "right to delete" requests: enumerate attachment ids and `DELETE` each. The platform does not provide a partner-wide wipe endpoint — deletion is per-attachment by design.
1058
+ *
943
1059
  */
944
1060
  attachments: API.Attachments = new API.Attachments(this);
945
1061
  /**
@@ -107,6 +107,8 @@ export const formatRequestDetails = (details: {
107
107
  name,
108
108
  (
109
109
  name.toLowerCase() === 'authorization' ||
110
+ name.toLowerCase() === 'api-key' ||
111
+ name.toLowerCase() === 'x-api-key' ||
110
112
  name.toLowerCase() === 'cookie' ||
111
113
  name.toLowerCase() === 'set-cookie'
112
114
  ) ?
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { APIResource } from '../core/resource';
4
4
  import { APIPromise } from '../core/api-promise';
5
+ import { buildHeaders } from '../internal/headers';
5
6
  import { RequestOptions } from '../internal/request-options';
6
7
  import { path } from '../internal/utils/path';
7
8
 
@@ -68,6 +69,122 @@ import { path } from '../internal/utils/path';
68
69
  *
69
70
  * - **URL-based (`url` field):** 10MB maximum
70
71
  * - **Pre-upload (`attachment_id`):** 100MB maximum
72
+ *
73
+ * ## Security & Ownership
74
+ *
75
+ * Every attachment is bound to the partner account that created or received it. The API enforces ownership on every operation that touches an attachment — sending, retrieving, deleting.
76
+ *
77
+ * **What this means for you:**
78
+ *
79
+ * - An attachment created under your API key can only be referenced by your API key.
80
+ * - Submitting another partner's `attachment_id` returns `404 Not Found`. We do not disclose whether the id exists or belongs to someone else.
81
+ * - Submitting a CDN URL that resolves to another partner's attachment is rejected before the send is attempted.
82
+ * - Ownership enforcement applies uniformly across send, create-chat, voice memo, retrieve, and delete operations.
83
+ *
84
+ * Every attachment-affecting endpoint requires a valid partner API key. Unauthenticated calls return `401 Unauthorized`.
85
+ *
86
+ * ## Attachment URL Patterns
87
+ *
88
+ * Attachment URLs in API responses and webhook payloads use one of two layouts, depending on the attachment's tier:
89
+ *
90
+ * | Tier | URL pattern | TTL |
91
+ * |---|---|---|
92
+ * | Persistent (default) | `https://cdn.linqapp.com/attachments/partners/{partner_id}/{attachment_id}/{filename}` | Long-lived |
93
+ * | Ephemeral | Pre-signed URL pointing at the ephemeral prefix on `cdn.linqapp.com` | 15 minutes per signed URL — re-fetch via the API for a fresh URL |
94
+ *
95
+ * Inbound media you receive over webhooks uses the same layout your outbound sends produce, so the URL you store and the URL you build look identical — no special casing in your client.
96
+ *
97
+ * ## Ephemeral Attachments (Privacy Tier)
98
+ *
99
+ * For regulated or sensitive content, opt in to the **ephemeral attachments** tier by contacting your Linq support contact. You can request it at two scopes:
100
+ *
101
+ * | Scope | Effect |
102
+ * |---|---|
103
+ * | **Partner-wide** | Every outbound and inbound attachment on every phone number under your account is routed through the ephemeral tier. |
104
+ * | **Per phone number** | Only the specified phone numbers route their attachments through the ephemeral tier. The rest stay on the persistent tier. |
105
+ *
106
+ * **Behavioral differences vs the persistent default:**
107
+ *
108
+ * | Aspect | Persistent | Ephemeral |
109
+ * |---|---|---|
110
+ * | Download URL form | Long-lived CDN URL | Pre-signed URL with short TTL |
111
+ * | Retention floor | Indefinite (until you call `DELETE`) | **Hard backstop: 1 day** — even without an explicit `DELETE`, the platform removes the underlying bytes after 24 hours |
112
+ * | URL re-fetch | Not required | Fetch via `GET /v3/attachments/{attachmentId}` for a fresh signed URL after TTL expiry |
113
+ * | Cross-partner isolation | Enforced | Enforced |
114
+ *
115
+ * **When to choose ephemeral:**
116
+ *
117
+ * - Your downstream system processes the file immediately on receipt and does not need to re-read it later.
118
+ * - You have a compliance requirement that the platform must not retain attachments beyond a short window.
119
+ * - The content is high-sensitivity (PHI, financial documents, identity verification) and you do not want it sitting behind a long-lived URL.
120
+ *
121
+ * **Important:** ephemeral applies in *both directions* — outbound files you upload **and** inbound media received by the phone numbers in that scope. Download bytes you need to keep promptly, or fetch a fresh signed URL via the API when needed.
122
+ *
123
+ * ## Deleting an Attachment
124
+ *
125
+ * To permanently remove an attachment you own, use:
126
+ *
127
+ * ```http
128
+ * DELETE /v3/attachments/{attachmentId}
129
+ * Authorization: Bearer <your_api_key>
130
+ * ```
131
+ *
132
+ * **What this does:**
133
+ *
134
+ * 1. Verifies the attachment is owned by your account. Returns `404` otherwise.
135
+ * 2. Removes the underlying file from Linq storage.
136
+ * 3. Records an audit entry (timestamp, partner, attachment id).
137
+ *
138
+ * **Response codes:**
139
+ *
140
+ * | Status | Meaning |
141
+ * |---|---|
142
+ * | `204 No Content` | Deletion succeeded. The attachment is removed from Linq storage. |
143
+ * | `400 Bad Request` | `attachmentId` is not a valid UUID. |
144
+ * | `401 Unauthorized` | Missing or invalid API key. |
145
+ * | `404 Not Found` | Attachment does not exist or is not owned by your account. |
146
+ * | `500 Internal Server Error` | Transient infrastructure issue — safe to retry. |
147
+ *
148
+ * **Effect on message history:**
149
+ *
150
+ * - Messages that referenced the deleted attachment remain visible.
151
+ * - The message part that pointed at the attachment is preserved with no attachment reference.
152
+ * - Webhook payloads previously delivered to you retain the original URL string, but downloads from that URL return `404` going forward.
153
+ *
154
+ * Deletion is **irreversible**. Once `204` is returned, the bytes are gone — there is no undelete.
155
+ *
156
+ * ## Inbound Media Flow
157
+ *
158
+ * When one of your phone numbers receives a message with media (image, video, audio, document), the platform:
159
+ *
160
+ * 1. Stores the file under your partner account.
161
+ * 2. Records metadata linked to the inbound message.
162
+ * 3. Delivers a webhook whose `parts[]` array includes a `media` part with a `url` pointing at `cdn.linqapp.com`.
163
+ * 4. If the receiving phone is opted in to ephemeral, the `url` is a short-TTL signed URL.
164
+ *
165
+ * You can acknowledge the webhook without fetching the file inline, and lazy-load via `GET /v3/attachments/{attachmentId}` later. For ephemeral attachments, retrieving via the API always returns a freshly-signed URL.
166
+ *
167
+ * ## Data Lifecycle Summary
168
+ *
169
+ * | Data | Persistent tier | Ephemeral tier |
170
+ * |---|---|---|
171
+ * | Attachment bytes | Retained until you `DELETE` | **Auto-removed after 1 day**, also removable via `DELETE` |
172
+ * | Attachment metadata (id, filename, mime type, size) | Retained until you `DELETE` | Removed alongside the bytes |
173
+ * | Message body & parts | Retained per message-retention policy | Retained per message-retention policy |
174
+ * | Audit log of deletions | Retained per platform retention policy | Retained per platform retention policy |
175
+ *
176
+ * **In transit:** TLS 1.2+ everywhere. **At rest:** AES-256 (server-side encryption).
177
+ *
178
+ * ## Compliance Checklist
179
+ *
180
+ * If you're integrating Linq under a security or privacy review, here is the short list:
181
+ *
182
+ * - Allowlist exactly one outbound domain: `cdn.linqapp.com`.
183
+ * - Decide whether you need ephemeral attachments (high-sensitivity content) — request enablement through your Linq support contact.
184
+ * - Implement `DELETE /v3/attachments/{attachmentId}` calls in your deletion workflow.
185
+ * - Persist any attachments your application needs long-term — Linq is the authoritative source until you delete, but the ephemeral tier auto-purges after 1 day.
186
+ * - For audit: every deletion is logged on Linq's side. Surface a confirmation in your application UI based on the `204` response.
187
+ * - For end-user "right to delete" requests: enumerate attachment ids and `DELETE` each. The platform does not provide a partner-wide wipe endpoint — deletion is per-attachment by design.
71
188
  */
72
189
  export class Attachments extends APIResource {
73
190
  /**
@@ -158,8 +275,10 @@ export class Attachments extends APIResource {
158
275
  }
159
276
 
160
277
  /**
161
- * Retrieve metadata for a specific attachment including its status, file
162
- * information, and URLs for downloading.
278
+ * Retrieve metadata for a specific attachment including file information, and URLs
279
+ * for downloading.
280
+ *
281
+ * `status`: (**deprecated** — will be removed in a future API version)
163
282
  *
164
283
  * @example
165
284
  * ```ts
@@ -171,6 +290,23 @@ export class Attachments extends APIResource {
171
290
  retrieve(attachmentID: string, options?: RequestOptions): APIPromise<AttachmentRetrieveResponse> {
172
291
  return this._client.get(path`/v3/attachments/${attachmentID}`, options);
173
292
  }
293
+
294
+ /**
295
+ * Permanently delete an attachment owned by the authenticated partner.
296
+ *
297
+ * @example
298
+ * ```ts
299
+ * await client.attachments.delete(
300
+ * 'abc12345-1234-5678-9abc-def012345678',
301
+ * );
302
+ * ```
303
+ */
304
+ delete(attachmentID: string, options?: RequestOptions): APIPromise<void> {
305
+ return this._client.delete(path`/v3/attachments/${attachmentID}`, {
306
+ ...options,
307
+ headers: buildHeaders([{ Accept: '*/*' }, options?.headers]),
308
+ });
309
+ }
174
310
  }
175
311
 
176
312
  /**
@@ -267,8 +403,7 @@ export type SupportedContentType =
267
403
 
268
404
  export interface AttachmentCreateResponse {
269
405
  /**
270
- * Unique identifier for the attachment (for status checks via GET
271
- * /v3/attachments/{id})
406
+ * Unique identifier for the attachment
272
407
  */
273
408
  attachment_id: string;
274
409
 
@@ -366,7 +501,7 @@ export interface AttachmentRetrieveResponse {
366
501
  size_bytes: number;
367
502
 
368
503
  /**
369
- * Current upload/processing status
504
+ * @deprecated status is no longer a useful signal
370
505
  */
371
506
  status: 'pending' | 'complete' | 'failed';
372
507
 
@@ -312,7 +312,7 @@ export interface Chat {
312
312
  health_status: Chat.HealthStatus;
313
313
 
314
314
  /**
315
- * Whether the chat is archived
315
+ * @deprecated is_archived is no longer a useful signal
316
316
  */
317
317
  is_archived: boolean;
318
318
 
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const VERSION = '0.22.0'; // x-release-please-version
1
+ export const VERSION = '0.23.0'; // x-release-please-version
package/version.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.22.0";
1
+ export declare const VERSION = "0.23.0";
2
2
  //# sourceMappingURL=version.d.mts.map
package/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.22.0";
1
+ export declare const VERSION = "0.23.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.22.0'; // x-release-please-version
4
+ exports.VERSION = '0.23.0'; // x-release-please-version
5
5
  //# sourceMappingURL=version.js.map
package/version.mjs CHANGED
@@ -1,2 +1,2 @@
1
- export const VERSION = '0.22.0'; // x-release-please-version
1
+ export const VERSION = '0.23.0'; // x-release-please-version
2
2
  //# sourceMappingURL=version.mjs.map