@sendly/node 3.29.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 +30 -30
- package/dist/index.d.mts +205 -12
- package/dist/index.d.ts +205 -12
- package/dist/index.js +133 -12
- package/dist/index.mjs +133 -12
- package/package.json +1 -1
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(`
|
|
189
|
-
console.log(`
|
|
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}`); //
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
332
|
-
|
|
333
|
-
|
|
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<
|
|
526
|
+
#### `cancelScheduled(id: string): Promise<CancelledMessageResponse>`
|
|
529
527
|
|
|
530
528
|
Cancel a scheduled message and refund credits.
|
|
531
529
|
|
|
532
|
-
#### `sendBatch(request:
|
|
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(
|
|
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,
|
|
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<
|
|
590
|
+
#### `getCreditTransactions(options?: { limit?: number; offset?: number }): Promise<CreditTransaction[]>`
|
|
593
591
|
|
|
594
592
|
Get credit transaction history.
|
|
595
593
|
|
|
596
|
-
#### `listApiKeys(): Promise<
|
|
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
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
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:
|
|
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
|
|
681
|
-
await client.enterprise.
|
|
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
|
-
|
|
683
|
+
inheritWithNewNumber: true
|
|
684
684
|
});
|
|
685
685
|
```
|
|
686
686
|
|
package/dist/index.d.mts
CHANGED
|
@@ -978,6 +978,72 @@ interface UpdateWebhookOptions {
|
|
|
978
978
|
/** Custom metadata */
|
|
979
979
|
metadata?: Record<string, unknown>;
|
|
980
980
|
}
|
|
981
|
+
/**
|
|
982
|
+
* Options for replaying webhook deliveries
|
|
983
|
+
*/
|
|
984
|
+
interface WebhookRedeliverOptions {
|
|
985
|
+
/** Earliest delivery created_at to consider, ISO-8601 (default: now − 24h) */
|
|
986
|
+
since?: string;
|
|
987
|
+
/** Latest delivery created_at to consider, ISO-8601 (default: now) */
|
|
988
|
+
until?: string;
|
|
989
|
+
/** Filter by event type (default: all) */
|
|
990
|
+
eventTypes?: WebhookEventType[];
|
|
991
|
+
/** Replay deliveries in any of these statuses (default: ['failed', 'cancelled']) */
|
|
992
|
+
statuses?: DeliveryStatus[];
|
|
993
|
+
/** Maximum number of deliveries to requeue (default: 1000, max 10000) */
|
|
994
|
+
limit?: number;
|
|
995
|
+
}
|
|
996
|
+
/**
|
|
997
|
+
* Result of replaying webhook deliveries
|
|
998
|
+
*/
|
|
999
|
+
interface WebhookRedeliverResult {
|
|
1000
|
+
message: string;
|
|
1001
|
+
/** Number of deliveries that were re-queued */
|
|
1002
|
+
requeued: number;
|
|
1003
|
+
/** Number of deliveries that failed to re-queue */
|
|
1004
|
+
skipped: number;
|
|
1005
|
+
/** True if the matching set was larger than `limit` */
|
|
1006
|
+
truncated: boolean;
|
|
1007
|
+
/** Total number of matching deliveries before the limit was applied */
|
|
1008
|
+
windowSize: number;
|
|
1009
|
+
/** IDs of the new delivery records created by the replay */
|
|
1010
|
+
deliveryIds: string[];
|
|
1011
|
+
since: string;
|
|
1012
|
+
until: string;
|
|
1013
|
+
limit: number;
|
|
1014
|
+
}
|
|
1015
|
+
/**
|
|
1016
|
+
* Options for backfilling missed webhook deliveries from the message log
|
|
1017
|
+
*/
|
|
1018
|
+
interface WebhookBackfillOptions {
|
|
1019
|
+
/** Earliest message created_at to consider, ISO-8601 (default: now − 24h) */
|
|
1020
|
+
since?: string;
|
|
1021
|
+
/** Latest message created_at to consider, ISO-8601 (default: now) */
|
|
1022
|
+
until?: string;
|
|
1023
|
+
/** Filter by event type (default: subscribed message events) */
|
|
1024
|
+
eventTypes?: WebhookEventType[];
|
|
1025
|
+
/** Maximum number of events to synthesize (default: 1000, max 10000) */
|
|
1026
|
+
limit?: number;
|
|
1027
|
+
}
|
|
1028
|
+
/**
|
|
1029
|
+
* Result of backfilling missed webhook deliveries
|
|
1030
|
+
*/
|
|
1031
|
+
interface WebhookBackfillResult {
|
|
1032
|
+
message: string;
|
|
1033
|
+
/** Number of deliveries synthesized and dispatched */
|
|
1034
|
+
synthesized: number;
|
|
1035
|
+
/** Synthesized count grouped by event type */
|
|
1036
|
+
byType: Record<string, number>;
|
|
1037
|
+
/** True if there were more eligible events than `limit` */
|
|
1038
|
+
truncated: boolean;
|
|
1039
|
+
/** Total number of messages scanned for the window */
|
|
1040
|
+
candidatesScanned: number;
|
|
1041
|
+
/** IDs of the new delivery records */
|
|
1042
|
+
deliveryIds: string[];
|
|
1043
|
+
since: string;
|
|
1044
|
+
until: string;
|
|
1045
|
+
limit: number;
|
|
1046
|
+
}
|
|
981
1047
|
/**
|
|
982
1048
|
* A webhook delivery attempt
|
|
983
1049
|
*/
|
|
@@ -2651,6 +2717,62 @@ declare class WebhooksResource {
|
|
|
2651
2717
|
message: string;
|
|
2652
2718
|
webhook: Webhook;
|
|
2653
2719
|
}>;
|
|
2720
|
+
/**
|
|
2721
|
+
* Replay failed or cancelled webhook deliveries from the audit log.
|
|
2722
|
+
*
|
|
2723
|
+
* Use after a customer endpoint has recovered from an outage to re-fire
|
|
2724
|
+
* deliveries that we recorded but couldn't deliver. Each replay creates
|
|
2725
|
+
* a new delivery row preserving the original `event_id` so customers can
|
|
2726
|
+
* dedupe.
|
|
2727
|
+
*
|
|
2728
|
+
* Rejects with HTTP 409 if the circuit is currently open — call
|
|
2729
|
+
* {@link WebhooksResource.resetCircuit} first.
|
|
2730
|
+
*
|
|
2731
|
+
* @param id - Webhook ID
|
|
2732
|
+
* @param options - Window and filter options
|
|
2733
|
+
* @returns Counts of requeued deliveries plus the new delivery IDs
|
|
2734
|
+
*
|
|
2735
|
+
* @example
|
|
2736
|
+
* ```typescript
|
|
2737
|
+
* await sendly.webhooks.resetCircuit('whk_xxx');
|
|
2738
|
+
* const result = await sendly.webhooks.redeliver('whk_xxx', {
|
|
2739
|
+
* since: '2026-05-01T00:00:00Z',
|
|
2740
|
+
* eventTypes: ['message.delivered', 'message.failed'],
|
|
2741
|
+
* limit: 5000,
|
|
2742
|
+
* });
|
|
2743
|
+
* console.log(`Requeued ${result.requeued} deliveries`);
|
|
2744
|
+
* ```
|
|
2745
|
+
*/
|
|
2746
|
+
redeliver(id: string, options?: WebhookRedeliverOptions): Promise<WebhookRedeliverResult>;
|
|
2747
|
+
/**
|
|
2748
|
+
* Backfill missed webhook events from the underlying message log.
|
|
2749
|
+
*
|
|
2750
|
+
* Use this when a circuit-breaker outage left events with no audit row
|
|
2751
|
+
* (the case `redeliver` cannot recover). The endpoint scans the
|
|
2752
|
+
* `messages` table for the window and synthesizes a webhook delivery
|
|
2753
|
+
* for any message whose `message.sent` / `message.delivered` /
|
|
2754
|
+
* `message.failed` event has not been successfully delivered yet.
|
|
2755
|
+
*
|
|
2756
|
+
* Synthesized events have fresh IDs — your endpoint should dedupe by
|
|
2757
|
+
* `event.data.object.id` (the message ID).
|
|
2758
|
+
*
|
|
2759
|
+
* Rejects with HTTP 409 if the circuit is currently open — call
|
|
2760
|
+
* {@link WebhooksResource.resetCircuit} first.
|
|
2761
|
+
*
|
|
2762
|
+
* @param id - Webhook ID
|
|
2763
|
+
* @param options - Window and filter options
|
|
2764
|
+
* @returns Counts grouped by event type plus the new delivery IDs
|
|
2765
|
+
*
|
|
2766
|
+
* @example
|
|
2767
|
+
* ```typescript
|
|
2768
|
+
* const result = await sendly.webhooks.backfill('whk_xxx', {
|
|
2769
|
+
* since: '2026-05-01T00:00:00Z',
|
|
2770
|
+
* eventTypes: ['message.delivered', 'message.failed'],
|
|
2771
|
+
* });
|
|
2772
|
+
* console.log(`Synthesized ${result.synthesized} events`, result.byType);
|
|
2773
|
+
* ```
|
|
2774
|
+
*/
|
|
2775
|
+
backfill(id: string, options?: WebhookBackfillOptions): Promise<WebhookBackfillResult>;
|
|
2654
2776
|
/**
|
|
2655
2777
|
* Rotate the webhook signing secret
|
|
2656
2778
|
*
|
|
@@ -3773,6 +3895,49 @@ declare class MediaResource {
|
|
|
3773
3895
|
upload(file: Buffer | NodeJS.ReadableStream, options?: MediaUploadOptions): Promise<MediaFile>;
|
|
3774
3896
|
}
|
|
3775
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
|
+
|
|
3776
3941
|
declare class WorkspacesSubResource {
|
|
3777
3942
|
private readonly http;
|
|
3778
3943
|
constructor(http: HttpClient);
|
|
@@ -3797,18 +3962,46 @@ declare class WorkspacesSubResource {
|
|
|
3797
3962
|
}>;
|
|
3798
3963
|
get(workspaceId: string): Promise<EnterpriseWorkspaceDetail>;
|
|
3799
3964
|
delete(workspaceId: string): Promise<void>;
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
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>;
|
|
3812
4005
|
inheritVerification(workspaceId: string, options: {
|
|
3813
4006
|
sourceWorkspaceId: string;
|
|
3814
4007
|
}): Promise<unknown>;
|
package/dist/index.d.ts
CHANGED
|
@@ -978,6 +978,72 @@ interface UpdateWebhookOptions {
|
|
|
978
978
|
/** Custom metadata */
|
|
979
979
|
metadata?: Record<string, unknown>;
|
|
980
980
|
}
|
|
981
|
+
/**
|
|
982
|
+
* Options for replaying webhook deliveries
|
|
983
|
+
*/
|
|
984
|
+
interface WebhookRedeliverOptions {
|
|
985
|
+
/** Earliest delivery created_at to consider, ISO-8601 (default: now − 24h) */
|
|
986
|
+
since?: string;
|
|
987
|
+
/** Latest delivery created_at to consider, ISO-8601 (default: now) */
|
|
988
|
+
until?: string;
|
|
989
|
+
/** Filter by event type (default: all) */
|
|
990
|
+
eventTypes?: WebhookEventType[];
|
|
991
|
+
/** Replay deliveries in any of these statuses (default: ['failed', 'cancelled']) */
|
|
992
|
+
statuses?: DeliveryStatus[];
|
|
993
|
+
/** Maximum number of deliveries to requeue (default: 1000, max 10000) */
|
|
994
|
+
limit?: number;
|
|
995
|
+
}
|
|
996
|
+
/**
|
|
997
|
+
* Result of replaying webhook deliveries
|
|
998
|
+
*/
|
|
999
|
+
interface WebhookRedeliverResult {
|
|
1000
|
+
message: string;
|
|
1001
|
+
/** Number of deliveries that were re-queued */
|
|
1002
|
+
requeued: number;
|
|
1003
|
+
/** Number of deliveries that failed to re-queue */
|
|
1004
|
+
skipped: number;
|
|
1005
|
+
/** True if the matching set was larger than `limit` */
|
|
1006
|
+
truncated: boolean;
|
|
1007
|
+
/** Total number of matching deliveries before the limit was applied */
|
|
1008
|
+
windowSize: number;
|
|
1009
|
+
/** IDs of the new delivery records created by the replay */
|
|
1010
|
+
deliveryIds: string[];
|
|
1011
|
+
since: string;
|
|
1012
|
+
until: string;
|
|
1013
|
+
limit: number;
|
|
1014
|
+
}
|
|
1015
|
+
/**
|
|
1016
|
+
* Options for backfilling missed webhook deliveries from the message log
|
|
1017
|
+
*/
|
|
1018
|
+
interface WebhookBackfillOptions {
|
|
1019
|
+
/** Earliest message created_at to consider, ISO-8601 (default: now − 24h) */
|
|
1020
|
+
since?: string;
|
|
1021
|
+
/** Latest message created_at to consider, ISO-8601 (default: now) */
|
|
1022
|
+
until?: string;
|
|
1023
|
+
/** Filter by event type (default: subscribed message events) */
|
|
1024
|
+
eventTypes?: WebhookEventType[];
|
|
1025
|
+
/** Maximum number of events to synthesize (default: 1000, max 10000) */
|
|
1026
|
+
limit?: number;
|
|
1027
|
+
}
|
|
1028
|
+
/**
|
|
1029
|
+
* Result of backfilling missed webhook deliveries
|
|
1030
|
+
*/
|
|
1031
|
+
interface WebhookBackfillResult {
|
|
1032
|
+
message: string;
|
|
1033
|
+
/** Number of deliveries synthesized and dispatched */
|
|
1034
|
+
synthesized: number;
|
|
1035
|
+
/** Synthesized count grouped by event type */
|
|
1036
|
+
byType: Record<string, number>;
|
|
1037
|
+
/** True if there were more eligible events than `limit` */
|
|
1038
|
+
truncated: boolean;
|
|
1039
|
+
/** Total number of messages scanned for the window */
|
|
1040
|
+
candidatesScanned: number;
|
|
1041
|
+
/** IDs of the new delivery records */
|
|
1042
|
+
deliveryIds: string[];
|
|
1043
|
+
since: string;
|
|
1044
|
+
until: string;
|
|
1045
|
+
limit: number;
|
|
1046
|
+
}
|
|
981
1047
|
/**
|
|
982
1048
|
* A webhook delivery attempt
|
|
983
1049
|
*/
|
|
@@ -2651,6 +2717,62 @@ declare class WebhooksResource {
|
|
|
2651
2717
|
message: string;
|
|
2652
2718
|
webhook: Webhook;
|
|
2653
2719
|
}>;
|
|
2720
|
+
/**
|
|
2721
|
+
* Replay failed or cancelled webhook deliveries from the audit log.
|
|
2722
|
+
*
|
|
2723
|
+
* Use after a customer endpoint has recovered from an outage to re-fire
|
|
2724
|
+
* deliveries that we recorded but couldn't deliver. Each replay creates
|
|
2725
|
+
* a new delivery row preserving the original `event_id` so customers can
|
|
2726
|
+
* dedupe.
|
|
2727
|
+
*
|
|
2728
|
+
* Rejects with HTTP 409 if the circuit is currently open — call
|
|
2729
|
+
* {@link WebhooksResource.resetCircuit} first.
|
|
2730
|
+
*
|
|
2731
|
+
* @param id - Webhook ID
|
|
2732
|
+
* @param options - Window and filter options
|
|
2733
|
+
* @returns Counts of requeued deliveries plus the new delivery IDs
|
|
2734
|
+
*
|
|
2735
|
+
* @example
|
|
2736
|
+
* ```typescript
|
|
2737
|
+
* await sendly.webhooks.resetCircuit('whk_xxx');
|
|
2738
|
+
* const result = await sendly.webhooks.redeliver('whk_xxx', {
|
|
2739
|
+
* since: '2026-05-01T00:00:00Z',
|
|
2740
|
+
* eventTypes: ['message.delivered', 'message.failed'],
|
|
2741
|
+
* limit: 5000,
|
|
2742
|
+
* });
|
|
2743
|
+
* console.log(`Requeued ${result.requeued} deliveries`);
|
|
2744
|
+
* ```
|
|
2745
|
+
*/
|
|
2746
|
+
redeliver(id: string, options?: WebhookRedeliverOptions): Promise<WebhookRedeliverResult>;
|
|
2747
|
+
/**
|
|
2748
|
+
* Backfill missed webhook events from the underlying message log.
|
|
2749
|
+
*
|
|
2750
|
+
* Use this when a circuit-breaker outage left events with no audit row
|
|
2751
|
+
* (the case `redeliver` cannot recover). The endpoint scans the
|
|
2752
|
+
* `messages` table for the window and synthesizes a webhook delivery
|
|
2753
|
+
* for any message whose `message.sent` / `message.delivered` /
|
|
2754
|
+
* `message.failed` event has not been successfully delivered yet.
|
|
2755
|
+
*
|
|
2756
|
+
* Synthesized events have fresh IDs — your endpoint should dedupe by
|
|
2757
|
+
* `event.data.object.id` (the message ID).
|
|
2758
|
+
*
|
|
2759
|
+
* Rejects with HTTP 409 if the circuit is currently open — call
|
|
2760
|
+
* {@link WebhooksResource.resetCircuit} first.
|
|
2761
|
+
*
|
|
2762
|
+
* @param id - Webhook ID
|
|
2763
|
+
* @param options - Window and filter options
|
|
2764
|
+
* @returns Counts grouped by event type plus the new delivery IDs
|
|
2765
|
+
*
|
|
2766
|
+
* @example
|
|
2767
|
+
* ```typescript
|
|
2768
|
+
* const result = await sendly.webhooks.backfill('whk_xxx', {
|
|
2769
|
+
* since: '2026-05-01T00:00:00Z',
|
|
2770
|
+
* eventTypes: ['message.delivered', 'message.failed'],
|
|
2771
|
+
* });
|
|
2772
|
+
* console.log(`Synthesized ${result.synthesized} events`, result.byType);
|
|
2773
|
+
* ```
|
|
2774
|
+
*/
|
|
2775
|
+
backfill(id: string, options?: WebhookBackfillOptions): Promise<WebhookBackfillResult>;
|
|
2654
2776
|
/**
|
|
2655
2777
|
* Rotate the webhook signing secret
|
|
2656
2778
|
*
|
|
@@ -3773,6 +3895,49 @@ declare class MediaResource {
|
|
|
3773
3895
|
upload(file: Buffer | NodeJS.ReadableStream, options?: MediaUploadOptions): Promise<MediaFile>;
|
|
3774
3896
|
}
|
|
3775
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
|
+
|
|
3776
3941
|
declare class WorkspacesSubResource {
|
|
3777
3942
|
private readonly http;
|
|
3778
3943
|
constructor(http: HttpClient);
|
|
@@ -3797,18 +3962,46 @@ declare class WorkspacesSubResource {
|
|
|
3797
3962
|
}>;
|
|
3798
3963
|
get(workspaceId: string): Promise<EnterpriseWorkspaceDetail>;
|
|
3799
3964
|
delete(workspaceId: string): Promise<void>;
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
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>;
|
|
3812
4005
|
inheritVerification(workspaceId: string, options: {
|
|
3813
4006
|
sourceWorkspaceId: string;
|
|
3814
4007
|
}): Promise<unknown>;
|
package/dist/index.js
CHANGED
|
@@ -1316,6 +1316,93 @@ var WebhooksResource = class {
|
|
|
1316
1316
|
});
|
|
1317
1317
|
return transformKeys(response);
|
|
1318
1318
|
}
|
|
1319
|
+
/**
|
|
1320
|
+
* Replay failed or cancelled webhook deliveries from the audit log.
|
|
1321
|
+
*
|
|
1322
|
+
* Use after a customer endpoint has recovered from an outage to re-fire
|
|
1323
|
+
* deliveries that we recorded but couldn't deliver. Each replay creates
|
|
1324
|
+
* a new delivery row preserving the original `event_id` so customers can
|
|
1325
|
+
* dedupe.
|
|
1326
|
+
*
|
|
1327
|
+
* Rejects with HTTP 409 if the circuit is currently open — call
|
|
1328
|
+
* {@link WebhooksResource.resetCircuit} first.
|
|
1329
|
+
*
|
|
1330
|
+
* @param id - Webhook ID
|
|
1331
|
+
* @param options - Window and filter options
|
|
1332
|
+
* @returns Counts of requeued deliveries plus the new delivery IDs
|
|
1333
|
+
*
|
|
1334
|
+
* @example
|
|
1335
|
+
* ```typescript
|
|
1336
|
+
* await sendly.webhooks.resetCircuit('whk_xxx');
|
|
1337
|
+
* const result = await sendly.webhooks.redeliver('whk_xxx', {
|
|
1338
|
+
* since: '2026-05-01T00:00:00Z',
|
|
1339
|
+
* eventTypes: ['message.delivered', 'message.failed'],
|
|
1340
|
+
* limit: 5000,
|
|
1341
|
+
* });
|
|
1342
|
+
* console.log(`Requeued ${result.requeued} deliveries`);
|
|
1343
|
+
* ```
|
|
1344
|
+
*/
|
|
1345
|
+
async redeliver(id, options = {}) {
|
|
1346
|
+
if (!id || !id.startsWith("whk_")) {
|
|
1347
|
+
throw new Error("Invalid webhook ID format");
|
|
1348
|
+
}
|
|
1349
|
+
const body = {};
|
|
1350
|
+
if (options.since !== void 0) body.since = options.since;
|
|
1351
|
+
if (options.until !== void 0) body.until = options.until;
|
|
1352
|
+
if (options.eventTypes !== void 0) body.event_types = options.eventTypes;
|
|
1353
|
+
if (options.statuses !== void 0) body.statuses = options.statuses;
|
|
1354
|
+
if (options.limit !== void 0) body.limit = options.limit;
|
|
1355
|
+
const response = await this.http.request({
|
|
1356
|
+
method: "POST",
|
|
1357
|
+
path: `/webhooks/${encodeURIComponent(id)}/redeliver`,
|
|
1358
|
+
body
|
|
1359
|
+
});
|
|
1360
|
+
return transformKeys(response);
|
|
1361
|
+
}
|
|
1362
|
+
/**
|
|
1363
|
+
* Backfill missed webhook events from the underlying message log.
|
|
1364
|
+
*
|
|
1365
|
+
* Use this when a circuit-breaker outage left events with no audit row
|
|
1366
|
+
* (the case `redeliver` cannot recover). The endpoint scans the
|
|
1367
|
+
* `messages` table for the window and synthesizes a webhook delivery
|
|
1368
|
+
* for any message whose `message.sent` / `message.delivered` /
|
|
1369
|
+
* `message.failed` event has not been successfully delivered yet.
|
|
1370
|
+
*
|
|
1371
|
+
* Synthesized events have fresh IDs — your endpoint should dedupe by
|
|
1372
|
+
* `event.data.object.id` (the message ID).
|
|
1373
|
+
*
|
|
1374
|
+
* Rejects with HTTP 409 if the circuit is currently open — call
|
|
1375
|
+
* {@link WebhooksResource.resetCircuit} first.
|
|
1376
|
+
*
|
|
1377
|
+
* @param id - Webhook ID
|
|
1378
|
+
* @param options - Window and filter options
|
|
1379
|
+
* @returns Counts grouped by event type plus the new delivery IDs
|
|
1380
|
+
*
|
|
1381
|
+
* @example
|
|
1382
|
+
* ```typescript
|
|
1383
|
+
* const result = await sendly.webhooks.backfill('whk_xxx', {
|
|
1384
|
+
* since: '2026-05-01T00:00:00Z',
|
|
1385
|
+
* eventTypes: ['message.delivered', 'message.failed'],
|
|
1386
|
+
* });
|
|
1387
|
+
* console.log(`Synthesized ${result.synthesized} events`, result.byType);
|
|
1388
|
+
* ```
|
|
1389
|
+
*/
|
|
1390
|
+
async backfill(id, options = {}) {
|
|
1391
|
+
if (!id || !id.startsWith("whk_")) {
|
|
1392
|
+
throw new Error("Invalid webhook ID format");
|
|
1393
|
+
}
|
|
1394
|
+
const body = {};
|
|
1395
|
+
if (options.since !== void 0) body.since = options.since;
|
|
1396
|
+
if (options.until !== void 0) body.until = options.until;
|
|
1397
|
+
if (options.eventTypes !== void 0) body.event_types = options.eventTypes;
|
|
1398
|
+
if (options.limit !== void 0) body.limit = options.limit;
|
|
1399
|
+
const response = await this.http.request({
|
|
1400
|
+
method: "POST",
|
|
1401
|
+
path: `/webhooks/${encodeURIComponent(id)}/backfill`,
|
|
1402
|
+
body
|
|
1403
|
+
});
|
|
1404
|
+
return transformKeys(response);
|
|
1405
|
+
}
|
|
1319
1406
|
/**
|
|
1320
1407
|
* Rotate the webhook signing secret
|
|
1321
1408
|
*
|
|
@@ -2988,25 +3075,59 @@ var WorkspacesSubResource = class {
|
|
|
2988
3075
|
path: `/enterprise/workspaces/${encodeURIComponent(workspaceId)}`
|
|
2989
3076
|
});
|
|
2990
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
|
+
*/
|
|
2991
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
|
+
}
|
|
2992
3117
|
const response = await this.http.request({
|
|
2993
3118
|
method: "POST",
|
|
2994
3119
|
path: `/enterprise/workspaces/${encodeURIComponent(workspaceId)}/verification/submit`,
|
|
2995
|
-
body
|
|
2996
|
-
business_name: data.businessName,
|
|
2997
|
-
business_type: data.businessType,
|
|
2998
|
-
ein: data.ein,
|
|
2999
|
-
address: data.address,
|
|
3000
|
-
city: data.city,
|
|
3001
|
-
state: data.state,
|
|
3002
|
-
zip: data.zip,
|
|
3003
|
-
use_case: data.useCase,
|
|
3004
|
-
sample_messages: data.sampleMessages,
|
|
3005
|
-
...data.monthlyVolume && { monthly_volume: data.monthlyVolume }
|
|
3006
|
-
}
|
|
3120
|
+
body
|
|
3007
3121
|
});
|
|
3008
3122
|
return transformKeys(response);
|
|
3009
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
|
+
}
|
|
3010
3131
|
async inheritVerification(workspaceId, options) {
|
|
3011
3132
|
const response = await this.http.request({
|
|
3012
3133
|
method: "POST",
|
package/dist/index.mjs
CHANGED
|
@@ -1256,6 +1256,93 @@ var WebhooksResource = class {
|
|
|
1256
1256
|
});
|
|
1257
1257
|
return transformKeys(response);
|
|
1258
1258
|
}
|
|
1259
|
+
/**
|
|
1260
|
+
* Replay failed or cancelled webhook deliveries from the audit log.
|
|
1261
|
+
*
|
|
1262
|
+
* Use after a customer endpoint has recovered from an outage to re-fire
|
|
1263
|
+
* deliveries that we recorded but couldn't deliver. Each replay creates
|
|
1264
|
+
* a new delivery row preserving the original `event_id` so customers can
|
|
1265
|
+
* dedupe.
|
|
1266
|
+
*
|
|
1267
|
+
* Rejects with HTTP 409 if the circuit is currently open — call
|
|
1268
|
+
* {@link WebhooksResource.resetCircuit} first.
|
|
1269
|
+
*
|
|
1270
|
+
* @param id - Webhook ID
|
|
1271
|
+
* @param options - Window and filter options
|
|
1272
|
+
* @returns Counts of requeued deliveries plus the new delivery IDs
|
|
1273
|
+
*
|
|
1274
|
+
* @example
|
|
1275
|
+
* ```typescript
|
|
1276
|
+
* await sendly.webhooks.resetCircuit('whk_xxx');
|
|
1277
|
+
* const result = await sendly.webhooks.redeliver('whk_xxx', {
|
|
1278
|
+
* since: '2026-05-01T00:00:00Z',
|
|
1279
|
+
* eventTypes: ['message.delivered', 'message.failed'],
|
|
1280
|
+
* limit: 5000,
|
|
1281
|
+
* });
|
|
1282
|
+
* console.log(`Requeued ${result.requeued} deliveries`);
|
|
1283
|
+
* ```
|
|
1284
|
+
*/
|
|
1285
|
+
async redeliver(id, options = {}) {
|
|
1286
|
+
if (!id || !id.startsWith("whk_")) {
|
|
1287
|
+
throw new Error("Invalid webhook ID format");
|
|
1288
|
+
}
|
|
1289
|
+
const body = {};
|
|
1290
|
+
if (options.since !== void 0) body.since = options.since;
|
|
1291
|
+
if (options.until !== void 0) body.until = options.until;
|
|
1292
|
+
if (options.eventTypes !== void 0) body.event_types = options.eventTypes;
|
|
1293
|
+
if (options.statuses !== void 0) body.statuses = options.statuses;
|
|
1294
|
+
if (options.limit !== void 0) body.limit = options.limit;
|
|
1295
|
+
const response = await this.http.request({
|
|
1296
|
+
method: "POST",
|
|
1297
|
+
path: `/webhooks/${encodeURIComponent(id)}/redeliver`,
|
|
1298
|
+
body
|
|
1299
|
+
});
|
|
1300
|
+
return transformKeys(response);
|
|
1301
|
+
}
|
|
1302
|
+
/**
|
|
1303
|
+
* Backfill missed webhook events from the underlying message log.
|
|
1304
|
+
*
|
|
1305
|
+
* Use this when a circuit-breaker outage left events with no audit row
|
|
1306
|
+
* (the case `redeliver` cannot recover). The endpoint scans the
|
|
1307
|
+
* `messages` table for the window and synthesizes a webhook delivery
|
|
1308
|
+
* for any message whose `message.sent` / `message.delivered` /
|
|
1309
|
+
* `message.failed` event has not been successfully delivered yet.
|
|
1310
|
+
*
|
|
1311
|
+
* Synthesized events have fresh IDs — your endpoint should dedupe by
|
|
1312
|
+
* `event.data.object.id` (the message ID).
|
|
1313
|
+
*
|
|
1314
|
+
* Rejects with HTTP 409 if the circuit is currently open — call
|
|
1315
|
+
* {@link WebhooksResource.resetCircuit} first.
|
|
1316
|
+
*
|
|
1317
|
+
* @param id - Webhook ID
|
|
1318
|
+
* @param options - Window and filter options
|
|
1319
|
+
* @returns Counts grouped by event type plus the new delivery IDs
|
|
1320
|
+
*
|
|
1321
|
+
* @example
|
|
1322
|
+
* ```typescript
|
|
1323
|
+
* const result = await sendly.webhooks.backfill('whk_xxx', {
|
|
1324
|
+
* since: '2026-05-01T00:00:00Z',
|
|
1325
|
+
* eventTypes: ['message.delivered', 'message.failed'],
|
|
1326
|
+
* });
|
|
1327
|
+
* console.log(`Synthesized ${result.synthesized} events`, result.byType);
|
|
1328
|
+
* ```
|
|
1329
|
+
*/
|
|
1330
|
+
async backfill(id, options = {}) {
|
|
1331
|
+
if (!id || !id.startsWith("whk_")) {
|
|
1332
|
+
throw new Error("Invalid webhook ID format");
|
|
1333
|
+
}
|
|
1334
|
+
const body = {};
|
|
1335
|
+
if (options.since !== void 0) body.since = options.since;
|
|
1336
|
+
if (options.until !== void 0) body.until = options.until;
|
|
1337
|
+
if (options.eventTypes !== void 0) body.event_types = options.eventTypes;
|
|
1338
|
+
if (options.limit !== void 0) body.limit = options.limit;
|
|
1339
|
+
const response = await this.http.request({
|
|
1340
|
+
method: "POST",
|
|
1341
|
+
path: `/webhooks/${encodeURIComponent(id)}/backfill`,
|
|
1342
|
+
body
|
|
1343
|
+
});
|
|
1344
|
+
return transformKeys(response);
|
|
1345
|
+
}
|
|
1259
1346
|
/**
|
|
1260
1347
|
* Rotate the webhook signing secret
|
|
1261
1348
|
*
|
|
@@ -2928,25 +3015,59 @@ var WorkspacesSubResource = class {
|
|
|
2928
3015
|
path: `/enterprise/workspaces/${encodeURIComponent(workspaceId)}`
|
|
2929
3016
|
});
|
|
2930
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
|
+
*/
|
|
2931
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
|
+
}
|
|
2932
3057
|
const response = await this.http.request({
|
|
2933
3058
|
method: "POST",
|
|
2934
3059
|
path: `/enterprise/workspaces/${encodeURIComponent(workspaceId)}/verification/submit`,
|
|
2935
|
-
body
|
|
2936
|
-
business_name: data.businessName,
|
|
2937
|
-
business_type: data.businessType,
|
|
2938
|
-
ein: data.ein,
|
|
2939
|
-
address: data.address,
|
|
2940
|
-
city: data.city,
|
|
2941
|
-
state: data.state,
|
|
2942
|
-
zip: data.zip,
|
|
2943
|
-
use_case: data.useCase,
|
|
2944
|
-
sample_messages: data.sampleMessages,
|
|
2945
|
-
...data.monthlyVolume && { monthly_volume: data.monthlyVolume }
|
|
2946
|
-
}
|
|
3060
|
+
body
|
|
2947
3061
|
});
|
|
2948
3062
|
return transformKeys(response);
|
|
2949
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
|
+
}
|
|
2950
3071
|
async inheritVerification(workspaceId, options) {
|
|
2951
3072
|
const response = await this.http.request({
|
|
2952
3073
|
method: "POST",
|