@sendly/node 3.30.0 → 3.33.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>;
@@ -4080,6 +4151,251 @@ declare class RulesResource {
4080
4151
  delete(id: string): Promise<void>;
4081
4152
  }
4082
4153
 
4154
+ /**
4155
+ * Business Upgrade Resource — Entity-Upgrade ("fork-with-new-number")
4156
+ *
4157
+ * @packageDocumentation
4158
+ *
4159
+ * Manages the toll-free business entity upgrade flow: when a customer
4160
+ * forms a new legal entity (e.g. an LLC), this resource lets them
4161
+ * reserve a new toll-free number under the new entity, submit it for
4162
+ * carrier review, and atomically swap to it on approval — without
4163
+ * disrupting outbound SMS during the 1-2 week review window.
4164
+ *
4165
+ * @see https://sendly.live/docs/business-upgrade
4166
+ */
4167
+
4168
+ type EntityType = "SOLE_PROPRIETOR" | "PRIVATE_PROFIT" | "PUBLIC_PROFIT" | "NON_PROFIT" | "GOVERNMENT";
4169
+ type BrnType = "EIN" | "SSN" | "DUNS" | "CRA" | "VAT" | "LEI" | "OTHER";
4170
+ type Disposition = "moved" | "released";
4171
+ interface PreflightCandidate {
4172
+ businessName: string;
4173
+ doingBusinessAs?: string;
4174
+ brn: string;
4175
+ brnType: BrnType;
4176
+ brnCountry: string;
4177
+ entityType: EntityType;
4178
+ website?: string;
4179
+ address1?: string;
4180
+ address2?: string;
4181
+ city?: string;
4182
+ state?: string;
4183
+ zip?: string;
4184
+ addressCountry?: string;
4185
+ contactFirstName?: string;
4186
+ contactLastName?: string;
4187
+ contactEmail?: string;
4188
+ contactPhone?: string;
4189
+ monthlyVolume?: string;
4190
+ useCase?: string;
4191
+ useCaseSummary?: string;
4192
+ sampleMessages?: string;
4193
+ optInWorkflow?: string;
4194
+ privacyUrl?: string;
4195
+ termsUrl?: string;
4196
+ additionalInformation?: string;
4197
+ ageGatedContent?: boolean;
4198
+ }
4199
+ interface PreflightIssue {
4200
+ severity: "blocker" | "warning" | "info";
4201
+ field: string;
4202
+ code: string;
4203
+ message: string;
4204
+ suggestion?: string;
4205
+ }
4206
+ interface PreflightProposedFix {
4207
+ field: string;
4208
+ current: unknown;
4209
+ proposed: unknown;
4210
+ reason: string;
4211
+ }
4212
+ interface PreflightReport {
4213
+ verificationId: string;
4214
+ businessName: string | null;
4215
+ country: "CA" | "US" | "OTHER" | "UNKNOWN";
4216
+ verdict: "ready" | "warnings" | "blocked";
4217
+ issues: PreflightIssue[];
4218
+ proposedFixes: PreflightProposedFix[];
4219
+ }
4220
+ interface StartUpgradeParams {
4221
+ businessName: string;
4222
+ brn: string;
4223
+ brnType: BrnType;
4224
+ brnCountry: string;
4225
+ entityType: EntityType;
4226
+ doingBusinessAs?: string;
4227
+ website?: string;
4228
+ address1?: string;
4229
+ address2?: string;
4230
+ city?: string;
4231
+ state?: string;
4232
+ zip?: string;
4233
+ addressCountry?: string;
4234
+ contactFirstName?: string;
4235
+ contactLastName?: string;
4236
+ contactEmail?: string;
4237
+ contactPhone?: string;
4238
+ monthlyVolume?: string;
4239
+ useCase?: string;
4240
+ useCaseSummary?: string;
4241
+ sampleMessages?: string;
4242
+ optInWorkflow?: string;
4243
+ privacyUrl?: string;
4244
+ termsUrl?: string;
4245
+ additionalInformation?: string;
4246
+ ageGatedContent?: boolean;
4247
+ }
4248
+ interface EinDocumentInput {
4249
+ /** Buffer containing the PDF bytes */
4250
+ buffer: Buffer | Uint8Array;
4251
+ /** Filename (defaults to "ein-doc.pdf") */
4252
+ filename?: string;
4253
+ /** Content-Type (defaults to "application/pdf") */
4254
+ contentType?: string;
4255
+ }
4256
+ interface StartUpgradeResponse {
4257
+ success: true;
4258
+ pendingVerificationId: string;
4259
+ telnyxVerificationId: string;
4260
+ tollFreeNumber: string;
4261
+ telnyxMessagingProfileId: string;
4262
+ einDocStored: boolean;
4263
+ message: string;
4264
+ }
4265
+ interface UpgradeStatusResponse {
4266
+ pending: {
4267
+ id: string;
4268
+ businessName: string;
4269
+ status: string;
4270
+ entityType: string | null;
4271
+ brnType: string | null;
4272
+ brnCountry: string | null;
4273
+ tollFreeNumber: string | null;
4274
+ rejectionReason: string | null;
4275
+ createdAt: string;
4276
+ updatedAt: string;
4277
+ } | null;
4278
+ }
4279
+ interface CancelUpgradeResponse {
4280
+ success: boolean;
4281
+ cancelled: boolean;
4282
+ cancelledVerificationId?: string;
4283
+ message: string;
4284
+ }
4285
+ interface ResubmitUpgradeResponse {
4286
+ success: boolean;
4287
+ pendingVerificationId: string;
4288
+ message: string;
4289
+ }
4290
+ interface DispositionResponse {
4291
+ success: boolean;
4292
+ disposition: Disposition;
4293
+ supersededVerificationId: string;
4294
+ message: string;
4295
+ }
4296
+ interface BestPrefillResponse {
4297
+ prefill: {
4298
+ monthlyVolume?: string;
4299
+ useCase?: string;
4300
+ useCaseSummary?: string;
4301
+ sampleMessages?: string;
4302
+ optInWorkflow?: string;
4303
+ optInImageUrls?: string;
4304
+ optInSource?: string;
4305
+ privacyUrl?: string;
4306
+ termsUrl?: string;
4307
+ additionalInformation?: string;
4308
+ isvReseller?: string;
4309
+ ageGatedContent?: boolean;
4310
+ };
4311
+ sourceWorkspaceCount: number;
4312
+ }
4313
+ /**
4314
+ * BusinessUpgrade resource
4315
+ *
4316
+ * @example
4317
+ * ```typescript
4318
+ * // Preview validation before submitting
4319
+ * const preview = await sendly.businessUpgrade.preflight({
4320
+ * businessName: "Acme Holdings LLC",
4321
+ * brn: "12-3456789",
4322
+ * brnType: "EIN",
4323
+ * brnCountry: "US",
4324
+ * entityType: "PRIVATE_PROFIT",
4325
+ * });
4326
+ *
4327
+ * // Submit the upgrade with the IRS letter
4328
+ * import { readFileSync } from "fs";
4329
+ * const result = await sendly.businessUpgrade.start("ws_abc", {
4330
+ * businessName: "Acme Holdings LLC",
4331
+ * brn: "12-3456789",
4332
+ * brnType: "EIN",
4333
+ * brnCountry: "US",
4334
+ * entityType: "PRIVATE_PROFIT",
4335
+ * }, {
4336
+ * einDoc: { buffer: readFileSync("./CP-575.pdf"), filename: "CP-575.pdf" }
4337
+ * });
4338
+ * ```
4339
+ */
4340
+ declare class BusinessUpgradeResource {
4341
+ private readonly http;
4342
+ constructor(http: HttpClient);
4343
+ /**
4344
+ * Validate a candidate entity upgrade payload before submission.
4345
+ * Returns issues + proposed auto-fixes. No writes — purely advisory.
4346
+ */
4347
+ preflight(candidate: PreflightCandidate): Promise<PreflightReport>;
4348
+ /**
4349
+ * Get a "best-of" prefill across all the caller's verified workspaces.
4350
+ * Returns most-recent non-empty values per messaging field. Use this
4351
+ * to pre-populate the upgrade form for users whose current workspace
4352
+ * has incomplete data.
4353
+ */
4354
+ bestPrefill(): Promise<BestPrefillResponse>;
4355
+ /**
4356
+ * Start an entity upgrade for the given workspace. Auto-provisions
4357
+ * a new toll-free number + messaging profile and submits to the
4358
+ * carrier for review. Returns the pending verification details.
4359
+ *
4360
+ * The current toll-free number continues sending throughout the
4361
+ * 1-2 week carrier review; on approval, an atomic swap promotes
4362
+ * the new number.
4363
+ */
4364
+ start(workspaceId: string, params: StartUpgradeParams, options?: {
4365
+ einDoc?: EinDocumentInput;
4366
+ }): Promise<StartUpgradeResponse>;
4367
+ /**
4368
+ * Check whether the given workspace has a pending entity upgrade.
4369
+ * Returns `{ pending: null }` if no upgrade is in flight.
4370
+ */
4371
+ status(workspaceId: string): Promise<UpgradeStatusResponse>;
4372
+ /**
4373
+ * Cancel a pending entity upgrade for the given workspace. Releases
4374
+ * the reserved toll-free number, deletes the new messaging profile,
4375
+ * and removes the stored EIN document. Idempotent.
4376
+ */
4377
+ cancel(workspaceId: string): Promise<CancelUpgradeResponse>;
4378
+ /**
4379
+ * Resubmit a rejected (or waiting-for-customer) entity upgrade with
4380
+ * updated fields and optionally a new EIN document.
4381
+ */
4382
+ resubmit(workspaceId: string, params: Partial<StartUpgradeParams>, options?: {
4383
+ einDoc?: EinDocumentInput;
4384
+ }): Promise<ResubmitUpgradeResponse>;
4385
+ /**
4386
+ * After a successful entity-upgrade approval, choose what happens to
4387
+ * the old toll-free number:
4388
+ *
4389
+ * - `moved`: keep it active under another workspace owned by the
4390
+ * same user (requires `targetWorkspaceId`)
4391
+ * - `released`: return it to the carrier pool
4392
+ */
4393
+ setDisposition(workspaceId: string, body: {
4394
+ disposition: Disposition;
4395
+ targetWorkspaceId?: string;
4396
+ }): Promise<DispositionResponse>;
4397
+ }
4398
+
4083
4399
  /**
4084
4400
  * Sendly Client
4085
4401
  * @packageDocumentation
@@ -4290,6 +4606,31 @@ declare class Sendly {
4290
4606
  * ```
4291
4607
  */
4292
4608
  readonly enterprise: EnterpriseResource;
4609
+ /**
4610
+ * Business Upgrade resource — toll-free entity-upgrade flow.
4611
+ *
4612
+ * @example
4613
+ * ```typescript
4614
+ * // Preview a candidate upgrade before submitting
4615
+ * const preview = await sendly.businessUpgrade.preflight({
4616
+ * businessName: "Acme Holdings LLC",
4617
+ * brn: "12-3456789",
4618
+ * brnType: "EIN",
4619
+ * brnCountry: "US",
4620
+ * entityType: "PRIVATE_PROFIT",
4621
+ * });
4622
+ *
4623
+ * // Start an upgrade — auto-reserves a new toll-free number
4624
+ * const { pendingVerificationId } = await sendly.businessUpgrade.start("ws_abc", {
4625
+ * businessName: "Acme Holdings LLC",
4626
+ * brn: "12-3456789",
4627
+ * brnType: "EIN",
4628
+ * brnCountry: "US",
4629
+ * entityType: "PRIVATE_PROFIT",
4630
+ * }, { einDoc: { buffer: pdfBuffer } });
4631
+ * ```
4632
+ */
4633
+ readonly businessUpgrade: BusinessUpgradeResource;
4293
4634
  private readonly http;
4294
4635
  private readonly config;
4295
4636
  /**