@sendly/node 3.30.0 → 3.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -185,8 +185,8 @@ const preview = await sendly.messages.previewBatch({
185
185
  { to: '+447700900123', text: 'Hello UK!' }
186
186
  ]
187
187
  });
188
- console.log(`Total credits needed: ${preview.totalCredits}`);
189
- console.log(`Valid: ${preview.valid}, Invalid: ${preview.invalid}`);
188
+ console.log(`Credits needed: ${preview.creditsNeeded}`);
189
+ console.log(`Will send: ${preview.willSend}, Blocked: ${preview.blocked}`);
190
190
  ```
191
191
 
192
192
  ### Rate Limit Information
@@ -233,7 +233,7 @@ const webhook = await sendly.webhooks.create({
233
233
  });
234
234
 
235
235
  console.log(`Webhook ID: ${webhook.id}`);
236
- console.log(`Secret: ${webhook.secret}`); // Store this securely!
236
+ console.log(`Secret: ${webhook.secret}`); // Only returned at creation - store securely!
237
237
 
238
238
  // List all webhooks
239
239
  const webhooks = await sendly.webhooks.list();
@@ -275,10 +275,11 @@ const webhooks = new Webhooks('your_webhook_secret');
275
275
  // In your webhook handler
276
276
  app.post('/webhooks/sendly', (req, res) => {
277
277
  const signature = req.headers['x-sendly-signature'];
278
+ const timestamp = req.headers['x-sendly-timestamp'];
278
279
  const payload = req.body;
279
280
 
280
281
  try {
281
- const event = webhooks.verifyAndParse(payload, signature);
282
+ const event = webhooks.parse(payload, signature, timestamp);
282
283
 
283
284
  switch (event.type) {
284
285
  case 'message.delivered':
@@ -311,13 +312,13 @@ console.log(`Reserved (scheduled): ${credits.reservedBalance} credits`);
311
312
  console.log(`Total: ${credits.balance} credits`);
312
313
 
313
314
  // View credit transaction history
314
- const { data: transactions } = await sendly.account.getCreditTransactions();
315
+ const transactions = await sendly.account.getCreditTransactions();
315
316
  for (const tx of transactions) {
316
317
  console.log(`${tx.type}: ${tx.amount} credits - ${tx.description}`);
317
318
  }
318
319
 
319
320
  // List API keys
320
- const { data: keys } = await sendly.account.listApiKeys();
321
+ const keys = await sendly.account.listApiKeys();
321
322
  for (const key of keys) {
322
323
  console.log(`${key.name}: ${key.prefix}*** (${key.type})`);
323
324
  }
@@ -328,12 +329,9 @@ console.log(`Messages sent: ${usage.messagesSent}`);
328
329
  console.log(`Credits used: ${usage.creditsUsed}`);
329
330
 
330
331
  // Create a new API key
331
- const newKey = await sendly.account.createApiKey({
332
- name: 'Production Key',
333
- type: 'live',
334
- scopes: ['sms:send', 'sms:read']
335
- });
336
- console.log(`New key: ${newKey.key}`); // Only shown once!
332
+ const { apiKey, key } = await sendly.account.createApiKey('Production Key');
333
+ console.log(`New key: ${key}`); // Only shown once!
334
+ console.log(`Key ID: ${apiKey.id}`);
337
335
 
338
336
  // Revoke an API key
339
337
  await sendly.account.revokeApiKey('key_xxx');
@@ -525,11 +523,11 @@ List scheduled messages.
525
523
 
526
524
  Get a scheduled message by ID.
527
525
 
528
- #### `cancelScheduled(id: string): Promise<CancelScheduledMessageResponse>`
526
+ #### `cancelScheduled(id: string): Promise<CancelledMessageResponse>`
529
527
 
530
528
  Cancel a scheduled message and refund credits.
531
529
 
532
- #### `sendBatch(request: SendBatchRequest): Promise<BatchMessageResponse>`
530
+ #### `sendBatch(request: BatchMessageRequest): Promise<BatchMessageResponse>`
533
531
 
534
532
  Send multiple messages in one API call.
535
533
 
@@ -543,9 +541,9 @@ List all batches.
543
541
 
544
542
  ### `sendly.webhooks`
545
543
 
546
- #### `create(request: CreateWebhookRequest): Promise<Webhook>`
544
+ #### `create(options: CreateWebhookOptions): Promise<WebhookCreatedResponse>`
547
545
 
548
- Create a new webhook endpoint.
546
+ Create a new webhook endpoint. The returned object includes a one-time `secret`.
549
547
 
550
548
  #### `list(): Promise<Webhook[]>`
551
549
 
@@ -555,7 +553,7 @@ List all webhooks.
555
553
 
556
554
  Get a webhook by ID.
557
555
 
558
- #### `update(id: string, request: UpdateWebhookRequest): Promise<Webhook>`
556
+ #### `update(id: string, options: UpdateWebhookOptions): Promise<Webhook>`
559
557
 
560
558
  Update a webhook.
561
559
 
@@ -589,11 +587,11 @@ Get account information.
589
587
 
590
588
  Get credit balance.
591
589
 
592
- #### `getCreditTransactions(): Promise<CreditTransactionListResponse>`
590
+ #### `getCreditTransactions(options?: { limit?: number; offset?: number }): Promise<CreditTransaction[]>`
593
591
 
594
592
  Get credit transaction history.
595
593
 
596
- #### `listApiKeys(): Promise<ApiKeyListResponse>`
594
+ #### `listApiKeys(): Promise<ApiKey[]>`
597
595
 
598
596
  List API keys.
599
597
 
@@ -662,25 +660,27 @@ await client.enterprise.workspaces.delete('ws_xxx');
662
660
  // Submit full verification
663
661
  await client.enterprise.workspaces.submitVerification('ws_xxx', {
664
662
  businessName: 'Acme Insurance LLC',
665
- businessType: 'llc',
666
- ein: '12-3456789',
667
- address: '100 Main St',
668
- city: 'Austin',
669
- state: 'TX',
670
- zip: '78701',
663
+ website: 'https://acme.com',
664
+ entityType: 'PRIVATE_PROFIT',
665
+ brn: '12-3456789',
666
+ brnType: 'EIN',
667
+ brnCountry: 'US',
668
+ address: { street: '100 Main St', city: 'Austin', state: 'TX', zip: '78701', country: 'US' },
669
+ contact: { firstName: 'Jane', lastName: 'Doe', email: 'jane@acme.com', phone: '+15551234567' },
671
670
  useCase: 'Policy renewal reminders',
672
- sampleMessages: ['Your policy renews on 3/15.']
671
+ sampleMessages: 'Your policy renews on 3/15.'
673
672
  });
674
673
 
675
- // Inherit from verified workspace
674
+ // Inherit from verified workspace (shares toll-free number)
676
675
  await client.enterprise.workspaces.inheritVerification('ws_new', {
677
676
  sourceWorkspaceId: 'ws_verified'
678
677
  });
679
678
 
680
- // Inherit with new number
681
- await client.enterprise.workspaces.inheritVerification('ws_new', {
679
+ // Inherit + new number: use provision() with inheritWithNewNumber instead
680
+ await client.enterprise.provision({
681
+ name: 'Acme Insurance - Austin',
682
682
  sourceWorkspaceId: 'ws_verified',
683
- purchaseNewNumber: true
683
+ inheritWithNewNumber: true
684
684
  });
685
685
  ```
686
686
 
package/dist/index.d.mts CHANGED
@@ -3895,6 +3895,49 @@ declare class MediaResource {
3895
3895
  upload(file: Buffer | NodeJS.ReadableStream, options?: MediaUploadOptions): Promise<MediaFile>;
3896
3896
  }
3897
3897
 
3898
+ /**
3899
+ * Verification submit/resubmit payload. All fields optional for resubmits
3900
+ * (server merges with existing record). For initial provision via
3901
+ * `submitVerification` (no existing record), the validator requires:
3902
+ * businessName, website, address, contact, useCase, useCaseSummary,
3903
+ * sampleMessages, optInWorkflow.
3904
+ */
3905
+ interface VerificationSubmitInput {
3906
+ businessName?: string;
3907
+ doingBusinessAs?: string;
3908
+ website?: string;
3909
+ address?: {
3910
+ street?: string;
3911
+ address1?: string;
3912
+ address2?: string | null;
3913
+ city?: string;
3914
+ state?: string;
3915
+ zip?: string;
3916
+ country?: string;
3917
+ };
3918
+ contact?: {
3919
+ firstName?: string;
3920
+ lastName?: string;
3921
+ email?: string;
3922
+ phone?: string;
3923
+ };
3924
+ brn?: string | null;
3925
+ brnType?: "EIN" | "SSN" | "DUNS" | "CRA" | "VAT" | "LEI" | "OTHER" | null;
3926
+ brnCountry?: string | null;
3927
+ entityType?: "SOLE_PROPRIETOR" | "PRIVATE_PROFIT" | "PUBLIC_PROFIT" | "NON_PROFIT" | "GOVERNMENT";
3928
+ useCase?: string;
3929
+ useCaseSummary?: string;
3930
+ sampleMessages?: string;
3931
+ optInWorkflow?: string;
3932
+ optInImageUrls?: string;
3933
+ monthlyVolume?: string;
3934
+ additionalInformation?: string;
3935
+ ageGatedContent?: boolean;
3936
+ isvReseller?: string;
3937
+ privacyUrl?: string;
3938
+ termsUrl?: string;
3939
+ }
3940
+
3898
3941
  declare class WorkspacesSubResource {
3899
3942
  private readonly http;
3900
3943
  constructor(http: HttpClient);
@@ -3919,18 +3962,46 @@ declare class WorkspacesSubResource {
3919
3962
  }>;
3920
3963
  get(workspaceId: string): Promise<EnterpriseWorkspaceDetail>;
3921
3964
  delete(workspaceId: string): Promise<void>;
3922
- submitVerification(workspaceId: string, data: {
3923
- businessName: string;
3924
- businessType: string;
3925
- ein: string;
3926
- address: string;
3927
- city: string;
3928
- state: string;
3929
- zip: string;
3930
- useCase: string;
3931
- sampleMessages: string[];
3932
- monthlyVolume?: number;
3933
- }): Promise<unknown>;
3965
+ /**
3966
+ * Submit (or resubmit) a verification for an enterprise workspace.
3967
+ *
3968
+ * Partial-update friendly (May 2026): for resubmit on an existing
3969
+ * workspace, you only need to send the fields you want to change —
3970
+ * everything else is preserved from the existing record. Hosted page
3971
+ * URLs (`/biz/`, `/opt-in/`, `/legal/`) generated during provision
3972
+ * are auto-preserved.
3973
+ *
3974
+ * For sole proprietors, leave `brn`, `brnType`, `brnCountry` undefined
3975
+ * — the server strips them before forwarding to the carrier.
3976
+ *
3977
+ * @example Full submit
3978
+ * ```ts
3979
+ * await sendly.enterprise.workspaces.submitVerification(workspaceId, {
3980
+ * businessName: "Acme LLC",
3981
+ * website: "https://acme.com",
3982
+ * address: { street: "...", city: "...", state: "California", zip: "90001", country: "US" },
3983
+ * contact: { firstName: "...", lastName: "...", email: "...", phone: "+15551234567" },
3984
+ * useCase: "Insurance Services",
3985
+ * useCaseSummary: "...",
3986
+ * sampleMessages: "...",
3987
+ * optInWorkflow: "...",
3988
+ * entityType: "SOLE_PROPRIETOR",
3989
+ * });
3990
+ * ```
3991
+ *
3992
+ * @example Partial-update resubmit (only changing email)
3993
+ * ```ts
3994
+ * await sendly.enterprise.workspaces.submitVerification(workspaceId, {
3995
+ * contact: { email: "new@email.com" },
3996
+ * });
3997
+ * ```
3998
+ */
3999
+ submitVerification(workspaceId: string, data: VerificationSubmitInput): Promise<unknown>;
4000
+ /**
4001
+ * Convenience alias for resubmits. Reads more naturally when you only
4002
+ * want to update a few fields after a rejection.
4003
+ */
4004
+ resubmitVerification(workspaceId: string, partialUpdates: VerificationSubmitInput): Promise<unknown>;
3934
4005
  inheritVerification(workspaceId: string, options: {
3935
4006
  sourceWorkspaceId: string;
3936
4007
  }): Promise<unknown>;
package/dist/index.d.ts CHANGED
@@ -3895,6 +3895,49 @@ declare class MediaResource {
3895
3895
  upload(file: Buffer | NodeJS.ReadableStream, options?: MediaUploadOptions): Promise<MediaFile>;
3896
3896
  }
3897
3897
 
3898
+ /**
3899
+ * Verification submit/resubmit payload. All fields optional for resubmits
3900
+ * (server merges with existing record). For initial provision via
3901
+ * `submitVerification` (no existing record), the validator requires:
3902
+ * businessName, website, address, contact, useCase, useCaseSummary,
3903
+ * sampleMessages, optInWorkflow.
3904
+ */
3905
+ interface VerificationSubmitInput {
3906
+ businessName?: string;
3907
+ doingBusinessAs?: string;
3908
+ website?: string;
3909
+ address?: {
3910
+ street?: string;
3911
+ address1?: string;
3912
+ address2?: string | null;
3913
+ city?: string;
3914
+ state?: string;
3915
+ zip?: string;
3916
+ country?: string;
3917
+ };
3918
+ contact?: {
3919
+ firstName?: string;
3920
+ lastName?: string;
3921
+ email?: string;
3922
+ phone?: string;
3923
+ };
3924
+ brn?: string | null;
3925
+ brnType?: "EIN" | "SSN" | "DUNS" | "CRA" | "VAT" | "LEI" | "OTHER" | null;
3926
+ brnCountry?: string | null;
3927
+ entityType?: "SOLE_PROPRIETOR" | "PRIVATE_PROFIT" | "PUBLIC_PROFIT" | "NON_PROFIT" | "GOVERNMENT";
3928
+ useCase?: string;
3929
+ useCaseSummary?: string;
3930
+ sampleMessages?: string;
3931
+ optInWorkflow?: string;
3932
+ optInImageUrls?: string;
3933
+ monthlyVolume?: string;
3934
+ additionalInformation?: string;
3935
+ ageGatedContent?: boolean;
3936
+ isvReseller?: string;
3937
+ privacyUrl?: string;
3938
+ termsUrl?: string;
3939
+ }
3940
+
3898
3941
  declare class WorkspacesSubResource {
3899
3942
  private readonly http;
3900
3943
  constructor(http: HttpClient);
@@ -3919,18 +3962,46 @@ declare class WorkspacesSubResource {
3919
3962
  }>;
3920
3963
  get(workspaceId: string): Promise<EnterpriseWorkspaceDetail>;
3921
3964
  delete(workspaceId: string): Promise<void>;
3922
- submitVerification(workspaceId: string, data: {
3923
- businessName: string;
3924
- businessType: string;
3925
- ein: string;
3926
- address: string;
3927
- city: string;
3928
- state: string;
3929
- zip: string;
3930
- useCase: string;
3931
- sampleMessages: string[];
3932
- monthlyVolume?: number;
3933
- }): Promise<unknown>;
3965
+ /**
3966
+ * Submit (or resubmit) a verification for an enterprise workspace.
3967
+ *
3968
+ * Partial-update friendly (May 2026): for resubmit on an existing
3969
+ * workspace, you only need to send the fields you want to change —
3970
+ * everything else is preserved from the existing record. Hosted page
3971
+ * URLs (`/biz/`, `/opt-in/`, `/legal/`) generated during provision
3972
+ * are auto-preserved.
3973
+ *
3974
+ * For sole proprietors, leave `brn`, `brnType`, `brnCountry` undefined
3975
+ * — the server strips them before forwarding to the carrier.
3976
+ *
3977
+ * @example Full submit
3978
+ * ```ts
3979
+ * await sendly.enterprise.workspaces.submitVerification(workspaceId, {
3980
+ * businessName: "Acme LLC",
3981
+ * website: "https://acme.com",
3982
+ * address: { street: "...", city: "...", state: "California", zip: "90001", country: "US" },
3983
+ * contact: { firstName: "...", lastName: "...", email: "...", phone: "+15551234567" },
3984
+ * useCase: "Insurance Services",
3985
+ * useCaseSummary: "...",
3986
+ * sampleMessages: "...",
3987
+ * optInWorkflow: "...",
3988
+ * entityType: "SOLE_PROPRIETOR",
3989
+ * });
3990
+ * ```
3991
+ *
3992
+ * @example Partial-update resubmit (only changing email)
3993
+ * ```ts
3994
+ * await sendly.enterprise.workspaces.submitVerification(workspaceId, {
3995
+ * contact: { email: "new@email.com" },
3996
+ * });
3997
+ * ```
3998
+ */
3999
+ submitVerification(workspaceId: string, data: VerificationSubmitInput): Promise<unknown>;
4000
+ /**
4001
+ * Convenience alias for resubmits. Reads more naturally when you only
4002
+ * want to update a few fields after a rejection.
4003
+ */
4004
+ resubmitVerification(workspaceId: string, partialUpdates: VerificationSubmitInput): Promise<unknown>;
3934
4005
  inheritVerification(workspaceId: string, options: {
3935
4006
  sourceWorkspaceId: string;
3936
4007
  }): Promise<unknown>;
package/dist/index.js CHANGED
@@ -3075,25 +3075,59 @@ var WorkspacesSubResource = class {
3075
3075
  path: `/enterprise/workspaces/${encodeURIComponent(workspaceId)}`
3076
3076
  });
3077
3077
  }
3078
+ /**
3079
+ * Submit (or resubmit) a verification for an enterprise workspace.
3080
+ *
3081
+ * Partial-update friendly (May 2026): for resubmit on an existing
3082
+ * workspace, you only need to send the fields you want to change —
3083
+ * everything else is preserved from the existing record. Hosted page
3084
+ * URLs (`/biz/`, `/opt-in/`, `/legal/`) generated during provision
3085
+ * are auto-preserved.
3086
+ *
3087
+ * For sole proprietors, leave `brn`, `brnType`, `brnCountry` undefined
3088
+ * — the server strips them before forwarding to the carrier.
3089
+ *
3090
+ * @example Full submit
3091
+ * ```ts
3092
+ * await sendly.enterprise.workspaces.submitVerification(workspaceId, {
3093
+ * businessName: "Acme LLC",
3094
+ * website: "https://acme.com",
3095
+ * address: { street: "...", city: "...", state: "California", zip: "90001", country: "US" },
3096
+ * contact: { firstName: "...", lastName: "...", email: "...", phone: "+15551234567" },
3097
+ * useCase: "Insurance Services",
3098
+ * useCaseSummary: "...",
3099
+ * sampleMessages: "...",
3100
+ * optInWorkflow: "...",
3101
+ * entityType: "SOLE_PROPRIETOR",
3102
+ * });
3103
+ * ```
3104
+ *
3105
+ * @example Partial-update resubmit (only changing email)
3106
+ * ```ts
3107
+ * await sendly.enterprise.workspaces.submitVerification(workspaceId, {
3108
+ * contact: { email: "new@email.com" },
3109
+ * });
3110
+ * ```
3111
+ */
3078
3112
  async submitVerification(workspaceId, data) {
3113
+ const body = {};
3114
+ for (const [k, v] of Object.entries(data)) {
3115
+ if (v !== void 0) body[k] = v;
3116
+ }
3079
3117
  const response = await this.http.request({
3080
3118
  method: "POST",
3081
3119
  path: `/enterprise/workspaces/${encodeURIComponent(workspaceId)}/verification/submit`,
3082
- body: {
3083
- business_name: data.businessName,
3084
- business_type: data.businessType,
3085
- ein: data.ein,
3086
- address: data.address,
3087
- city: data.city,
3088
- state: data.state,
3089
- zip: data.zip,
3090
- use_case: data.useCase,
3091
- sample_messages: data.sampleMessages,
3092
- ...data.monthlyVolume && { monthly_volume: data.monthlyVolume }
3093
- }
3120
+ body
3094
3121
  });
3095
3122
  return transformKeys(response);
3096
3123
  }
3124
+ /**
3125
+ * Convenience alias for resubmits. Reads more naturally when you only
3126
+ * want to update a few fields after a rejection.
3127
+ */
3128
+ async resubmitVerification(workspaceId, partialUpdates) {
3129
+ return this.submitVerification(workspaceId, partialUpdates);
3130
+ }
3097
3131
  async inheritVerification(workspaceId, options) {
3098
3132
  const response = await this.http.request({
3099
3133
  method: "POST",
package/dist/index.mjs CHANGED
@@ -3015,25 +3015,59 @@ var WorkspacesSubResource = class {
3015
3015
  path: `/enterprise/workspaces/${encodeURIComponent(workspaceId)}`
3016
3016
  });
3017
3017
  }
3018
+ /**
3019
+ * Submit (or resubmit) a verification for an enterprise workspace.
3020
+ *
3021
+ * Partial-update friendly (May 2026): for resubmit on an existing
3022
+ * workspace, you only need to send the fields you want to change —
3023
+ * everything else is preserved from the existing record. Hosted page
3024
+ * URLs (`/biz/`, `/opt-in/`, `/legal/`) generated during provision
3025
+ * are auto-preserved.
3026
+ *
3027
+ * For sole proprietors, leave `brn`, `brnType`, `brnCountry` undefined
3028
+ * — the server strips them before forwarding to the carrier.
3029
+ *
3030
+ * @example Full submit
3031
+ * ```ts
3032
+ * await sendly.enterprise.workspaces.submitVerification(workspaceId, {
3033
+ * businessName: "Acme LLC",
3034
+ * website: "https://acme.com",
3035
+ * address: { street: "...", city: "...", state: "California", zip: "90001", country: "US" },
3036
+ * contact: { firstName: "...", lastName: "...", email: "...", phone: "+15551234567" },
3037
+ * useCase: "Insurance Services",
3038
+ * useCaseSummary: "...",
3039
+ * sampleMessages: "...",
3040
+ * optInWorkflow: "...",
3041
+ * entityType: "SOLE_PROPRIETOR",
3042
+ * });
3043
+ * ```
3044
+ *
3045
+ * @example Partial-update resubmit (only changing email)
3046
+ * ```ts
3047
+ * await sendly.enterprise.workspaces.submitVerification(workspaceId, {
3048
+ * contact: { email: "new@email.com" },
3049
+ * });
3050
+ * ```
3051
+ */
3018
3052
  async submitVerification(workspaceId, data) {
3053
+ const body = {};
3054
+ for (const [k, v] of Object.entries(data)) {
3055
+ if (v !== void 0) body[k] = v;
3056
+ }
3019
3057
  const response = await this.http.request({
3020
3058
  method: "POST",
3021
3059
  path: `/enterprise/workspaces/${encodeURIComponent(workspaceId)}/verification/submit`,
3022
- body: {
3023
- business_name: data.businessName,
3024
- business_type: data.businessType,
3025
- ein: data.ein,
3026
- address: data.address,
3027
- city: data.city,
3028
- state: data.state,
3029
- zip: data.zip,
3030
- use_case: data.useCase,
3031
- sample_messages: data.sampleMessages,
3032
- ...data.monthlyVolume && { monthly_volume: data.monthlyVolume }
3033
- }
3060
+ body
3034
3061
  });
3035
3062
  return transformKeys(response);
3036
3063
  }
3064
+ /**
3065
+ * Convenience alias for resubmits. Reads more naturally when you only
3066
+ * want to update a few fields after a rejection.
3067
+ */
3068
+ async resubmitVerification(workspaceId, partialUpdates) {
3069
+ return this.submitVerification(workspaceId, partialUpdates);
3070
+ }
3037
3071
  async inheritVerification(workspaceId, options) {
3038
3072
  const response = await this.http.request({
3039
3073
  method: "POST",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sendly/node",
3
- "version": "3.30.0",
3
+ "version": "3.31.0",
4
4
  "description": "Official Sendly Node.js SDK for SMS messaging",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",