@sendly/node 3.27.2 → 3.30.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/dist/index.d.mts +265 -2
- package/dist/index.d.ts +265 -2
- package/dist/index.js +193 -4
- package/dist/index.mjs +193 -4
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -877,7 +877,12 @@ declare const ALL_SUPPORTED_COUNTRIES: string[];
|
|
|
877
877
|
/**
|
|
878
878
|
* Webhook event types
|
|
879
879
|
*/
|
|
880
|
-
type WebhookEventType = "message.sent" | "message.delivered" | "message.failed" | "message.bounced" | "message.retrying" | "message.queued" | "message.received" | "message.opt_out" | "message.opt_in" | "verification.created" | "verification.delivered" | "verification.verified" | "verification.expired" | "verification.failed" | "verification.resent" | "verification.delivery_failed";
|
|
880
|
+
type WebhookEventType = "message.sent" | "message.delivered" | "message.failed" | "message.bounced" | "message.retrying" | "message.queued" | "message.received" | "message.opt_out" | "message.opt_in" | "verification.created" | "verification.delivered" | "verification.verified" | "verification.expired" | "verification.failed" | "verification.resent" | "verification.delivery_failed" | "contact.auto_flagged" | "contact.marked_valid" | "contacts.lookup_completed" | "contacts.bulk_marked_valid";
|
|
881
|
+
/**
|
|
882
|
+
* Source of a list-health event. Frozen enum — new values will be
|
|
883
|
+
* added in minor SDK versions, never removed.
|
|
884
|
+
*/
|
|
885
|
+
type ListHealthEventSource = "send_failure" | "carrier_lookup" | "user_action" | "bulk_mark_valid";
|
|
881
886
|
/**
|
|
882
887
|
* Webhook mode - filters which events are delivered
|
|
883
888
|
* - "all": Receives all events (sandbox + production)
|
|
@@ -973,6 +978,72 @@ interface UpdateWebhookOptions {
|
|
|
973
978
|
/** Custom metadata */
|
|
974
979
|
metadata?: Record<string, unknown>;
|
|
975
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
|
+
}
|
|
976
1047
|
/**
|
|
977
1048
|
* A webhook delivery attempt
|
|
978
1049
|
*/
|
|
@@ -1527,6 +1598,39 @@ interface Contact {
|
|
|
1527
1598
|
* Whether the contact has opted out
|
|
1528
1599
|
*/
|
|
1529
1600
|
optedOut?: boolean;
|
|
1601
|
+
/**
|
|
1602
|
+
* Carrier-reported line type for this number. One of: `mobile`, `voip`,
|
|
1603
|
+
* `toll free`, `fixed line`, `fixed line or mobile`, `pager`, `voicemail`,
|
|
1604
|
+
* `shared cost`, `premium rate`, `uan`, `personal number`, `unknown`.
|
|
1605
|
+
* Populated after a carrier lookup (either automatic or via checkNumbers).
|
|
1606
|
+
*/
|
|
1607
|
+
lineType?: string | null;
|
|
1608
|
+
/**
|
|
1609
|
+
* Carrier name reported by the lookup (e.g., "AT&T", "Verizon").
|
|
1610
|
+
*/
|
|
1611
|
+
carrierName?: string | null;
|
|
1612
|
+
/**
|
|
1613
|
+
* When the carrier lookup last ran for this contact.
|
|
1614
|
+
*/
|
|
1615
|
+
lineTypeCheckedAt?: string | null;
|
|
1616
|
+
/**
|
|
1617
|
+
* Reason this contact is excluded from future campaigns. One of:
|
|
1618
|
+
* `landline`, `invalid_number`, `non_sms_capable`. Set automatically
|
|
1619
|
+
* after terminal send failures or by a carrier lookup. Clear it with
|
|
1620
|
+
* `contacts.markValid(id)`.
|
|
1621
|
+
*/
|
|
1622
|
+
invalidReason?: string | null;
|
|
1623
|
+
/**
|
|
1624
|
+
* When the invalid flag was set.
|
|
1625
|
+
*/
|
|
1626
|
+
invalidatedAt?: string | null;
|
|
1627
|
+
/**
|
|
1628
|
+
* When a user manually cleared an auto-flag on this contact. Carrier
|
|
1629
|
+
* re-checks that would re-flag the contact as invalid respect this
|
|
1630
|
+
* timestamp and leave the contact clean, so your manual decisions
|
|
1631
|
+
* survive future lookups.
|
|
1632
|
+
*/
|
|
1633
|
+
userMarkedValidAt?: string | null;
|
|
1530
1634
|
/**
|
|
1531
1635
|
* When the contact was created
|
|
1532
1636
|
*/
|
|
@@ -1543,6 +1647,38 @@ interface Contact {
|
|
|
1543
1647
|
name: string;
|
|
1544
1648
|
}>;
|
|
1545
1649
|
}
|
|
1650
|
+
/**
|
|
1651
|
+
* Response from triggering a bulk carrier lookup via `contacts.checkNumbers()`.
|
|
1652
|
+
*/
|
|
1653
|
+
interface CheckNumbersResponse {
|
|
1654
|
+
success: boolean;
|
|
1655
|
+
/**
|
|
1656
|
+
* True if a carrier lookup for this scope was already running when you
|
|
1657
|
+
* called this. The dashboard renders an "already in progress" toast when
|
|
1658
|
+
* it sees this flag; server-side integrators can treat it as a soft
|
|
1659
|
+
* no-op and wait for `contacts.lookup_completed` webhook.
|
|
1660
|
+
*/
|
|
1661
|
+
alreadyRunning?: boolean;
|
|
1662
|
+
message?: string;
|
|
1663
|
+
}
|
|
1664
|
+
/**
|
|
1665
|
+
* Scope for `contacts.bulkMarkValid()`. Pass either an explicit id array
|
|
1666
|
+
* (up to 10,000 per call) OR a `listId` — not both. Foreign ids silently
|
|
1667
|
+
* no-op via the per-org filter.
|
|
1668
|
+
*/
|
|
1669
|
+
interface BulkMarkValidOptions {
|
|
1670
|
+
/** Explicit contact ids to clear (max 10,000). */
|
|
1671
|
+
ids?: string[];
|
|
1672
|
+
/** Clear every flagged member of this list. */
|
|
1673
|
+
listId?: string;
|
|
1674
|
+
}
|
|
1675
|
+
/**
|
|
1676
|
+
* Response from `contacts.bulkMarkValid()`.
|
|
1677
|
+
*/
|
|
1678
|
+
interface BulkMarkValidResponse {
|
|
1679
|
+
/** Number of contacts whose invalid flag was actually cleared. */
|
|
1680
|
+
cleared: number;
|
|
1681
|
+
}
|
|
1546
1682
|
/**
|
|
1547
1683
|
* Request to create a contact
|
|
1548
1684
|
*/
|
|
@@ -2581,6 +2717,62 @@ declare class WebhooksResource {
|
|
|
2581
2717
|
message: string;
|
|
2582
2718
|
webhook: Webhook;
|
|
2583
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>;
|
|
2584
2776
|
/**
|
|
2585
2777
|
* Rotate the webhook signing secret
|
|
2586
2778
|
*
|
|
@@ -3459,6 +3651,77 @@ declare class ContactsResource {
|
|
|
3459
3651
|
*/
|
|
3460
3652
|
delete(id: string): Promise<void>;
|
|
3461
3653
|
import(request: ImportContactsRequest): Promise<ImportContactsResponse>;
|
|
3654
|
+
/**
|
|
3655
|
+
* Clear the invalid flag on a contact so future campaigns include it again.
|
|
3656
|
+
*
|
|
3657
|
+
* Contacts get auto-flagged as invalid when a send fails with a terminal
|
|
3658
|
+
* bad-number error (landline, invalid number) or when a carrier lookup
|
|
3659
|
+
* reports they can't receive SMS. Use this when you disagree with the
|
|
3660
|
+
* auto-flag — e.g. the recipient ported from a landline to mobile.
|
|
3661
|
+
*
|
|
3662
|
+
* @param id - Contact ID
|
|
3663
|
+
* @returns The contact with the flag cleared
|
|
3664
|
+
*
|
|
3665
|
+
* @example
|
|
3666
|
+
* ```typescript
|
|
3667
|
+
* const contact = await sendly.contacts.markValid('cnt_xxx');
|
|
3668
|
+
* console.log(contact.invalidReason); // null
|
|
3669
|
+
* ```
|
|
3670
|
+
*/
|
|
3671
|
+
markValid(id: string): Promise<Contact>;
|
|
3672
|
+
/**
|
|
3673
|
+
* Clear the invalid flag on many contacts at once — the escape hatch
|
|
3674
|
+
* for when auto-flag misclassifies at scale. Pass either an explicit
|
|
3675
|
+
* id array (up to 10,000 per call) OR a `listId`, not both. Foreign
|
|
3676
|
+
* ids silently no-op via the per-organization filter.
|
|
3677
|
+
*
|
|
3678
|
+
* @param options - `{ ids }` or `{ listId }`
|
|
3679
|
+
* @returns `{ cleared }` — number of contacts whose flag was actually
|
|
3680
|
+
* cleared. Already-clean contacts and foreign ids don't count.
|
|
3681
|
+
*
|
|
3682
|
+
* @example
|
|
3683
|
+
* ```typescript
|
|
3684
|
+
* // Clear a specific set of ids
|
|
3685
|
+
* const { cleared } = await sendly.contacts.bulkMarkValid({
|
|
3686
|
+
* ids: ['cnt_abc', 'cnt_def', 'cnt_ghi'],
|
|
3687
|
+
* });
|
|
3688
|
+
*
|
|
3689
|
+
* // Clear every flagged member of a list
|
|
3690
|
+
* await sendly.contacts.bulkMarkValid({ listId: 'lst_xxx' });
|
|
3691
|
+
* ```
|
|
3692
|
+
*/
|
|
3693
|
+
bulkMarkValid(options: BulkMarkValidOptions): Promise<BulkMarkValidResponse>;
|
|
3694
|
+
/**
|
|
3695
|
+
* Trigger a background carrier lookup across your contacts. Landlines and
|
|
3696
|
+
* other non-SMS-capable numbers are auto-excluded from future campaigns.
|
|
3697
|
+
*
|
|
3698
|
+
* The lookup runs asynchronously and takes 1–5 minutes depending on list
|
|
3699
|
+
* size. Results populate the `lineType`, `carrierName`, and `invalidReason`
|
|
3700
|
+
* fields on affected contacts — fetch the contact again after a few minutes
|
|
3701
|
+
* to see updated state.
|
|
3702
|
+
*
|
|
3703
|
+
* Idempotent: re-triggering while a lookup is already running for the same
|
|
3704
|
+
* scope is a no-op.
|
|
3705
|
+
*
|
|
3706
|
+
* @param options - Optional: scope to a single list, or force re-check
|
|
3707
|
+
* @returns Acknowledgement
|
|
3708
|
+
*
|
|
3709
|
+
* @example
|
|
3710
|
+
* ```typescript
|
|
3711
|
+
* // Check all un-checked contacts
|
|
3712
|
+
* await sendly.contacts.checkNumbers();
|
|
3713
|
+
*
|
|
3714
|
+
* // Check a specific list only
|
|
3715
|
+
* await sendly.contacts.checkNumbers({ listId: 'lst_xxx' });
|
|
3716
|
+
*
|
|
3717
|
+
* // Re-check contacts even if previously looked up
|
|
3718
|
+
* await sendly.contacts.checkNumbers({ force: true });
|
|
3719
|
+
* ```
|
|
3720
|
+
*/
|
|
3721
|
+
checkNumbers(options?: {
|
|
3722
|
+
listId?: string;
|
|
3723
|
+
force?: boolean;
|
|
3724
|
+
}): Promise<CheckNumbersResponse>;
|
|
3462
3725
|
private transformContact;
|
|
3463
3726
|
}
|
|
3464
3727
|
/**
|
|
@@ -4480,4 +4743,4 @@ declare class Webhooks {
|
|
|
4480
4743
|
*/
|
|
4481
4744
|
type WebhookMessageData = WebhookMessageObject;
|
|
4482
4745
|
|
|
4483
|
-
export { ALL_SUPPORTED_COUNTRIES, type Account, type AddLabelsRequest, type AnalyticsOverview, type AnalyticsPeriod, type ApiErrorResponse, type ApiKey, AuthenticationError, type AutoTopUpSettings, type BatchListResponse, type BatchMessageItem, type BatchMessageRequest, type BatchMessageResponse, type BatchMessageResult, type BatchStatus, type BillingBreakdown, type BillingBreakdownOptions, type BulkProvisionResult, type BulkProvisionResultItem, type BulkProvisionWorkspace, CREDITS_PER_SMS, type Campaign, type CampaignListResponse, type CampaignPreview, type CampaignStatus, type CancelledMessageResponse, type CheckVerificationRequest, type CheckVerificationResponse, type CircuitState, type Contact, type ContactList, type ContactListResponse, type ContactListsResponse, type Conversation, type ConversationListResponse, type ConversationStatus, type ConversationWithMessages, type CreateCampaignRequest, type CreateContactListRequest, type CreateContactRequest, type CreateDraftRequest, type CreateKeyOptions, type CreateLabelRequest, type CreateOptInPageOptions, type CreateOptInPageResult, type CreateTemplateRequest, type CreateVerifySessionRequest, type CreateWebhookOptions, type CreateWorkspaceOptions, type CreatedApiKey, type CreditAnalytics, type CreditAnalyticsDataPoint, type CreditTransaction, type Credits, type DeliveryAnalyticsItem, type DeliveryStatus, type DnsRecord, type DraftListResponse, type DraftStatus, type EnterpriseAccount, type EnterpriseWebhook, type EnterpriseWebhookTestResult, type EnterpriseWorkspace, type EnterpriseWorkspaceDetail, type EnterpriseWorkspaceSummary, type GenerateBusinessPageOptions, type GenerateBusinessPageResponse, type GetConversationOptions, type ImportContactItem, type ImportContactsError, type ImportContactsRequest, type ImportContactsResponse, InsufficientCreditsError, type Invitation, type Label, type LabelListResponse, type ListBatchesOptions, type ListCampaignsOptions, type ListContactsOptions, type ListConversationsOptions, type ListDraftsOptions, type ListMessagesOptions, type ListScheduledMessagesOptions, type ListVerificationsOptions, type MediaFile, type MediaUploadOptions, type Message, type MessageAnalytics, type MessageAnalyticsDataPoint, type MessageDraft, type MessageListResponse, type MessageStatus, type MessageType, NetworkError, NotFoundError, type OptInPage, type PricingTier, type ProvisionWorkspaceOptions, type ProvisionWorkspaceResult, type QuotaSettings, RateLimitError, type RateLimitInfo, type ReplyToConversationRequest, type ResumeWorkspaceResult, SANDBOX_TEST_NUMBERS, SUPPORTED_COUNTRIES, type ScheduleCampaignRequest, type ScheduleMessageRequest, type ScheduledMessage, type ScheduledMessageListResponse, type ScheduledMessageStatus, type SendInvitationOptions, type SendMessageRequest, type SendVerificationRequest, type SendVerificationResponse, type SenderType, Sendly, type SendlyConfig, SendlyError, type SendlyErrorCode, type SetCustomDomainResult, type SetWorkspaceWebhookOptions, type SetWorkspaceWebhookResult, type SuggestRepliesResponse, type SuggestedReply, type SuspendWorkspaceOptions, type SuspendWorkspaceResult, type Template, type TemplateListResponse, type TemplatePreview, type TemplateStatus, type TemplateVariable, TimeoutError, type TransferCreditsOptions, type TransferCreditsResult, type UpdateAutoTopUpOptions, type UpdateCampaignRequest, type UpdateContactListRequest, type UpdateContactRequest, type UpdateConversationRequest, type UpdateDraftRequest, type UpdateOptInPageOptions, type UpdateQuotaOptions, type UpdateTemplateRequest, type UpdateWebhookOptions, type ValidateSessionTokenRequest, type ValidateSessionTokenResponse, ValidationError, type Verification, type VerificationDeliveryStatus, type VerificationListResponse, type VerificationStatus, type VerifySession, type VerifySessionStatus, type Webhook, type WebhookCreatedResponse, type WebhookDelivery, type WebhookEvent, type WebhookEventType, type WebhookMessageData, type WebhookMessageStatus, type WebhookSecretRotation, WebhookSignatureError, type WebhookTestResult, Webhooks, type WorkspaceBillingItem, type WorkspaceCredits, type WorkspaceWebhook, calculateSegments, Sendly as default, generateWebhookSignature, getCountryFromPhone, isCountrySupported, parseWebhookEvent, validateMessageText, validatePhoneNumber, validateSenderId, verifyWebhookSignature };
|
|
4746
|
+
export { ALL_SUPPORTED_COUNTRIES, type Account, type AddLabelsRequest, type AnalyticsOverview, type AnalyticsPeriod, type ApiErrorResponse, type ApiKey, AuthenticationError, type AutoTopUpSettings, type BatchListResponse, type BatchMessageItem, type BatchMessageRequest, type BatchMessageResponse, type BatchMessageResult, type BatchStatus, type BillingBreakdown, type BillingBreakdownOptions, type BulkMarkValidOptions, type BulkMarkValidResponse, type BulkProvisionResult, type BulkProvisionResultItem, type BulkProvisionWorkspace, CREDITS_PER_SMS, type Campaign, type CampaignListResponse, type CampaignPreview, type CampaignStatus, type CancelledMessageResponse, type CheckNumbersResponse, type CheckVerificationRequest, type CheckVerificationResponse, type CircuitState, type Contact, type ContactList, type ContactListResponse, type ContactListsResponse, type Conversation, type ConversationListResponse, type ConversationStatus, type ConversationWithMessages, type CreateCampaignRequest, type CreateContactListRequest, type CreateContactRequest, type CreateDraftRequest, type CreateKeyOptions, type CreateLabelRequest, type CreateOptInPageOptions, type CreateOptInPageResult, type CreateTemplateRequest, type CreateVerifySessionRequest, type CreateWebhookOptions, type CreateWorkspaceOptions, type CreatedApiKey, type CreditAnalytics, type CreditAnalyticsDataPoint, type CreditTransaction, type Credits, type DeliveryAnalyticsItem, type DeliveryStatus, type DnsRecord, type DraftListResponse, type DraftStatus, type EnterpriseAccount, type EnterpriseWebhook, type EnterpriseWebhookTestResult, type EnterpriseWorkspace, type EnterpriseWorkspaceDetail, type EnterpriseWorkspaceSummary, type GenerateBusinessPageOptions, type GenerateBusinessPageResponse, type GetConversationOptions, type ImportContactItem, type ImportContactsError, type ImportContactsRequest, type ImportContactsResponse, InsufficientCreditsError, type Invitation, type Label, type LabelListResponse, type ListBatchesOptions, type ListCampaignsOptions, type ListContactsOptions, type ListConversationsOptions, type ListDraftsOptions, type ListHealthEventSource, type ListMessagesOptions, type ListScheduledMessagesOptions, type ListVerificationsOptions, type MediaFile, type MediaUploadOptions, type Message, type MessageAnalytics, type MessageAnalyticsDataPoint, type MessageDraft, type MessageListResponse, type MessageStatus, type MessageType, NetworkError, NotFoundError, type OptInPage, type PricingTier, type ProvisionWorkspaceOptions, type ProvisionWorkspaceResult, type QuotaSettings, RateLimitError, type RateLimitInfo, type ReplyToConversationRequest, type ResumeWorkspaceResult, SANDBOX_TEST_NUMBERS, SUPPORTED_COUNTRIES, type ScheduleCampaignRequest, type ScheduleMessageRequest, type ScheduledMessage, type ScheduledMessageListResponse, type ScheduledMessageStatus, type SendInvitationOptions, type SendMessageRequest, type SendVerificationRequest, type SendVerificationResponse, type SenderType, Sendly, type SendlyConfig, SendlyError, type SendlyErrorCode, type SetCustomDomainResult, type SetWorkspaceWebhookOptions, type SetWorkspaceWebhookResult, type SuggestRepliesResponse, type SuggestedReply, type SuspendWorkspaceOptions, type SuspendWorkspaceResult, type Template, type TemplateListResponse, type TemplatePreview, type TemplateStatus, type TemplateVariable, TimeoutError, type TransferCreditsOptions, type TransferCreditsResult, type UpdateAutoTopUpOptions, type UpdateCampaignRequest, type UpdateContactListRequest, type UpdateContactRequest, type UpdateConversationRequest, type UpdateDraftRequest, type UpdateOptInPageOptions, type UpdateQuotaOptions, type UpdateTemplateRequest, type UpdateWebhookOptions, type ValidateSessionTokenRequest, type ValidateSessionTokenResponse, ValidationError, type Verification, type VerificationDeliveryStatus, type VerificationListResponse, type VerificationStatus, type VerifySession, type VerifySessionStatus, type Webhook, type WebhookCreatedResponse, type WebhookDelivery, type WebhookEvent, type WebhookEventType, type WebhookMessageData, type WebhookMessageStatus, type WebhookSecretRotation, WebhookSignatureError, type WebhookTestResult, Webhooks, type WorkspaceBillingItem, type WorkspaceCredits, type WorkspaceWebhook, calculateSegments, Sendly as default, generateWebhookSignature, getCountryFromPhone, isCountrySupported, parseWebhookEvent, validateMessageText, validatePhoneNumber, validateSenderId, verifyWebhookSignature };
|
package/dist/index.d.ts
CHANGED
|
@@ -877,7 +877,12 @@ declare const ALL_SUPPORTED_COUNTRIES: string[];
|
|
|
877
877
|
/**
|
|
878
878
|
* Webhook event types
|
|
879
879
|
*/
|
|
880
|
-
type WebhookEventType = "message.sent" | "message.delivered" | "message.failed" | "message.bounced" | "message.retrying" | "message.queued" | "message.received" | "message.opt_out" | "message.opt_in" | "verification.created" | "verification.delivered" | "verification.verified" | "verification.expired" | "verification.failed" | "verification.resent" | "verification.delivery_failed";
|
|
880
|
+
type WebhookEventType = "message.sent" | "message.delivered" | "message.failed" | "message.bounced" | "message.retrying" | "message.queued" | "message.received" | "message.opt_out" | "message.opt_in" | "verification.created" | "verification.delivered" | "verification.verified" | "verification.expired" | "verification.failed" | "verification.resent" | "verification.delivery_failed" | "contact.auto_flagged" | "contact.marked_valid" | "contacts.lookup_completed" | "contacts.bulk_marked_valid";
|
|
881
|
+
/**
|
|
882
|
+
* Source of a list-health event. Frozen enum — new values will be
|
|
883
|
+
* added in minor SDK versions, never removed.
|
|
884
|
+
*/
|
|
885
|
+
type ListHealthEventSource = "send_failure" | "carrier_lookup" | "user_action" | "bulk_mark_valid";
|
|
881
886
|
/**
|
|
882
887
|
* Webhook mode - filters which events are delivered
|
|
883
888
|
* - "all": Receives all events (sandbox + production)
|
|
@@ -973,6 +978,72 @@ interface UpdateWebhookOptions {
|
|
|
973
978
|
/** Custom metadata */
|
|
974
979
|
metadata?: Record<string, unknown>;
|
|
975
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
|
+
}
|
|
976
1047
|
/**
|
|
977
1048
|
* A webhook delivery attempt
|
|
978
1049
|
*/
|
|
@@ -1527,6 +1598,39 @@ interface Contact {
|
|
|
1527
1598
|
* Whether the contact has opted out
|
|
1528
1599
|
*/
|
|
1529
1600
|
optedOut?: boolean;
|
|
1601
|
+
/**
|
|
1602
|
+
* Carrier-reported line type for this number. One of: `mobile`, `voip`,
|
|
1603
|
+
* `toll free`, `fixed line`, `fixed line or mobile`, `pager`, `voicemail`,
|
|
1604
|
+
* `shared cost`, `premium rate`, `uan`, `personal number`, `unknown`.
|
|
1605
|
+
* Populated after a carrier lookup (either automatic or via checkNumbers).
|
|
1606
|
+
*/
|
|
1607
|
+
lineType?: string | null;
|
|
1608
|
+
/**
|
|
1609
|
+
* Carrier name reported by the lookup (e.g., "AT&T", "Verizon").
|
|
1610
|
+
*/
|
|
1611
|
+
carrierName?: string | null;
|
|
1612
|
+
/**
|
|
1613
|
+
* When the carrier lookup last ran for this contact.
|
|
1614
|
+
*/
|
|
1615
|
+
lineTypeCheckedAt?: string | null;
|
|
1616
|
+
/**
|
|
1617
|
+
* Reason this contact is excluded from future campaigns. One of:
|
|
1618
|
+
* `landline`, `invalid_number`, `non_sms_capable`. Set automatically
|
|
1619
|
+
* after terminal send failures or by a carrier lookup. Clear it with
|
|
1620
|
+
* `contacts.markValid(id)`.
|
|
1621
|
+
*/
|
|
1622
|
+
invalidReason?: string | null;
|
|
1623
|
+
/**
|
|
1624
|
+
* When the invalid flag was set.
|
|
1625
|
+
*/
|
|
1626
|
+
invalidatedAt?: string | null;
|
|
1627
|
+
/**
|
|
1628
|
+
* When a user manually cleared an auto-flag on this contact. Carrier
|
|
1629
|
+
* re-checks that would re-flag the contact as invalid respect this
|
|
1630
|
+
* timestamp and leave the contact clean, so your manual decisions
|
|
1631
|
+
* survive future lookups.
|
|
1632
|
+
*/
|
|
1633
|
+
userMarkedValidAt?: string | null;
|
|
1530
1634
|
/**
|
|
1531
1635
|
* When the contact was created
|
|
1532
1636
|
*/
|
|
@@ -1543,6 +1647,38 @@ interface Contact {
|
|
|
1543
1647
|
name: string;
|
|
1544
1648
|
}>;
|
|
1545
1649
|
}
|
|
1650
|
+
/**
|
|
1651
|
+
* Response from triggering a bulk carrier lookup via `contacts.checkNumbers()`.
|
|
1652
|
+
*/
|
|
1653
|
+
interface CheckNumbersResponse {
|
|
1654
|
+
success: boolean;
|
|
1655
|
+
/**
|
|
1656
|
+
* True if a carrier lookup for this scope was already running when you
|
|
1657
|
+
* called this. The dashboard renders an "already in progress" toast when
|
|
1658
|
+
* it sees this flag; server-side integrators can treat it as a soft
|
|
1659
|
+
* no-op and wait for `contacts.lookup_completed` webhook.
|
|
1660
|
+
*/
|
|
1661
|
+
alreadyRunning?: boolean;
|
|
1662
|
+
message?: string;
|
|
1663
|
+
}
|
|
1664
|
+
/**
|
|
1665
|
+
* Scope for `contacts.bulkMarkValid()`. Pass either an explicit id array
|
|
1666
|
+
* (up to 10,000 per call) OR a `listId` — not both. Foreign ids silently
|
|
1667
|
+
* no-op via the per-org filter.
|
|
1668
|
+
*/
|
|
1669
|
+
interface BulkMarkValidOptions {
|
|
1670
|
+
/** Explicit contact ids to clear (max 10,000). */
|
|
1671
|
+
ids?: string[];
|
|
1672
|
+
/** Clear every flagged member of this list. */
|
|
1673
|
+
listId?: string;
|
|
1674
|
+
}
|
|
1675
|
+
/**
|
|
1676
|
+
* Response from `contacts.bulkMarkValid()`.
|
|
1677
|
+
*/
|
|
1678
|
+
interface BulkMarkValidResponse {
|
|
1679
|
+
/** Number of contacts whose invalid flag was actually cleared. */
|
|
1680
|
+
cleared: number;
|
|
1681
|
+
}
|
|
1546
1682
|
/**
|
|
1547
1683
|
* Request to create a contact
|
|
1548
1684
|
*/
|
|
@@ -2581,6 +2717,62 @@ declare class WebhooksResource {
|
|
|
2581
2717
|
message: string;
|
|
2582
2718
|
webhook: Webhook;
|
|
2583
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>;
|
|
2584
2776
|
/**
|
|
2585
2777
|
* Rotate the webhook signing secret
|
|
2586
2778
|
*
|
|
@@ -3459,6 +3651,77 @@ declare class ContactsResource {
|
|
|
3459
3651
|
*/
|
|
3460
3652
|
delete(id: string): Promise<void>;
|
|
3461
3653
|
import(request: ImportContactsRequest): Promise<ImportContactsResponse>;
|
|
3654
|
+
/**
|
|
3655
|
+
* Clear the invalid flag on a contact so future campaigns include it again.
|
|
3656
|
+
*
|
|
3657
|
+
* Contacts get auto-flagged as invalid when a send fails with a terminal
|
|
3658
|
+
* bad-number error (landline, invalid number) or when a carrier lookup
|
|
3659
|
+
* reports they can't receive SMS. Use this when you disagree with the
|
|
3660
|
+
* auto-flag — e.g. the recipient ported from a landline to mobile.
|
|
3661
|
+
*
|
|
3662
|
+
* @param id - Contact ID
|
|
3663
|
+
* @returns The contact with the flag cleared
|
|
3664
|
+
*
|
|
3665
|
+
* @example
|
|
3666
|
+
* ```typescript
|
|
3667
|
+
* const contact = await sendly.contacts.markValid('cnt_xxx');
|
|
3668
|
+
* console.log(contact.invalidReason); // null
|
|
3669
|
+
* ```
|
|
3670
|
+
*/
|
|
3671
|
+
markValid(id: string): Promise<Contact>;
|
|
3672
|
+
/**
|
|
3673
|
+
* Clear the invalid flag on many contacts at once — the escape hatch
|
|
3674
|
+
* for when auto-flag misclassifies at scale. Pass either an explicit
|
|
3675
|
+
* id array (up to 10,000 per call) OR a `listId`, not both. Foreign
|
|
3676
|
+
* ids silently no-op via the per-organization filter.
|
|
3677
|
+
*
|
|
3678
|
+
* @param options - `{ ids }` or `{ listId }`
|
|
3679
|
+
* @returns `{ cleared }` — number of contacts whose flag was actually
|
|
3680
|
+
* cleared. Already-clean contacts and foreign ids don't count.
|
|
3681
|
+
*
|
|
3682
|
+
* @example
|
|
3683
|
+
* ```typescript
|
|
3684
|
+
* // Clear a specific set of ids
|
|
3685
|
+
* const { cleared } = await sendly.contacts.bulkMarkValid({
|
|
3686
|
+
* ids: ['cnt_abc', 'cnt_def', 'cnt_ghi'],
|
|
3687
|
+
* });
|
|
3688
|
+
*
|
|
3689
|
+
* // Clear every flagged member of a list
|
|
3690
|
+
* await sendly.contacts.bulkMarkValid({ listId: 'lst_xxx' });
|
|
3691
|
+
* ```
|
|
3692
|
+
*/
|
|
3693
|
+
bulkMarkValid(options: BulkMarkValidOptions): Promise<BulkMarkValidResponse>;
|
|
3694
|
+
/**
|
|
3695
|
+
* Trigger a background carrier lookup across your contacts. Landlines and
|
|
3696
|
+
* other non-SMS-capable numbers are auto-excluded from future campaigns.
|
|
3697
|
+
*
|
|
3698
|
+
* The lookup runs asynchronously and takes 1–5 minutes depending on list
|
|
3699
|
+
* size. Results populate the `lineType`, `carrierName`, and `invalidReason`
|
|
3700
|
+
* fields on affected contacts — fetch the contact again after a few minutes
|
|
3701
|
+
* to see updated state.
|
|
3702
|
+
*
|
|
3703
|
+
* Idempotent: re-triggering while a lookup is already running for the same
|
|
3704
|
+
* scope is a no-op.
|
|
3705
|
+
*
|
|
3706
|
+
* @param options - Optional: scope to a single list, or force re-check
|
|
3707
|
+
* @returns Acknowledgement
|
|
3708
|
+
*
|
|
3709
|
+
* @example
|
|
3710
|
+
* ```typescript
|
|
3711
|
+
* // Check all un-checked contacts
|
|
3712
|
+
* await sendly.contacts.checkNumbers();
|
|
3713
|
+
*
|
|
3714
|
+
* // Check a specific list only
|
|
3715
|
+
* await sendly.contacts.checkNumbers({ listId: 'lst_xxx' });
|
|
3716
|
+
*
|
|
3717
|
+
* // Re-check contacts even if previously looked up
|
|
3718
|
+
* await sendly.contacts.checkNumbers({ force: true });
|
|
3719
|
+
* ```
|
|
3720
|
+
*/
|
|
3721
|
+
checkNumbers(options?: {
|
|
3722
|
+
listId?: string;
|
|
3723
|
+
force?: boolean;
|
|
3724
|
+
}): Promise<CheckNumbersResponse>;
|
|
3462
3725
|
private transformContact;
|
|
3463
3726
|
}
|
|
3464
3727
|
/**
|
|
@@ -4480,4 +4743,4 @@ declare class Webhooks {
|
|
|
4480
4743
|
*/
|
|
4481
4744
|
type WebhookMessageData = WebhookMessageObject;
|
|
4482
4745
|
|
|
4483
|
-
export { ALL_SUPPORTED_COUNTRIES, type Account, type AddLabelsRequest, type AnalyticsOverview, type AnalyticsPeriod, type ApiErrorResponse, type ApiKey, AuthenticationError, type AutoTopUpSettings, type BatchListResponse, type BatchMessageItem, type BatchMessageRequest, type BatchMessageResponse, type BatchMessageResult, type BatchStatus, type BillingBreakdown, type BillingBreakdownOptions, type BulkProvisionResult, type BulkProvisionResultItem, type BulkProvisionWorkspace, CREDITS_PER_SMS, type Campaign, type CampaignListResponse, type CampaignPreview, type CampaignStatus, type CancelledMessageResponse, type CheckVerificationRequest, type CheckVerificationResponse, type CircuitState, type Contact, type ContactList, type ContactListResponse, type ContactListsResponse, type Conversation, type ConversationListResponse, type ConversationStatus, type ConversationWithMessages, type CreateCampaignRequest, type CreateContactListRequest, type CreateContactRequest, type CreateDraftRequest, type CreateKeyOptions, type CreateLabelRequest, type CreateOptInPageOptions, type CreateOptInPageResult, type CreateTemplateRequest, type CreateVerifySessionRequest, type CreateWebhookOptions, type CreateWorkspaceOptions, type CreatedApiKey, type CreditAnalytics, type CreditAnalyticsDataPoint, type CreditTransaction, type Credits, type DeliveryAnalyticsItem, type DeliveryStatus, type DnsRecord, type DraftListResponse, type DraftStatus, type EnterpriseAccount, type EnterpriseWebhook, type EnterpriseWebhookTestResult, type EnterpriseWorkspace, type EnterpriseWorkspaceDetail, type EnterpriseWorkspaceSummary, type GenerateBusinessPageOptions, type GenerateBusinessPageResponse, type GetConversationOptions, type ImportContactItem, type ImportContactsError, type ImportContactsRequest, type ImportContactsResponse, InsufficientCreditsError, type Invitation, type Label, type LabelListResponse, type ListBatchesOptions, type ListCampaignsOptions, type ListContactsOptions, type ListConversationsOptions, type ListDraftsOptions, type ListMessagesOptions, type ListScheduledMessagesOptions, type ListVerificationsOptions, type MediaFile, type MediaUploadOptions, type Message, type MessageAnalytics, type MessageAnalyticsDataPoint, type MessageDraft, type MessageListResponse, type MessageStatus, type MessageType, NetworkError, NotFoundError, type OptInPage, type PricingTier, type ProvisionWorkspaceOptions, type ProvisionWorkspaceResult, type QuotaSettings, RateLimitError, type RateLimitInfo, type ReplyToConversationRequest, type ResumeWorkspaceResult, SANDBOX_TEST_NUMBERS, SUPPORTED_COUNTRIES, type ScheduleCampaignRequest, type ScheduleMessageRequest, type ScheduledMessage, type ScheduledMessageListResponse, type ScheduledMessageStatus, type SendInvitationOptions, type SendMessageRequest, type SendVerificationRequest, type SendVerificationResponse, type SenderType, Sendly, type SendlyConfig, SendlyError, type SendlyErrorCode, type SetCustomDomainResult, type SetWorkspaceWebhookOptions, type SetWorkspaceWebhookResult, type SuggestRepliesResponse, type SuggestedReply, type SuspendWorkspaceOptions, type SuspendWorkspaceResult, type Template, type TemplateListResponse, type TemplatePreview, type TemplateStatus, type TemplateVariable, TimeoutError, type TransferCreditsOptions, type TransferCreditsResult, type UpdateAutoTopUpOptions, type UpdateCampaignRequest, type UpdateContactListRequest, type UpdateContactRequest, type UpdateConversationRequest, type UpdateDraftRequest, type UpdateOptInPageOptions, type UpdateQuotaOptions, type UpdateTemplateRequest, type UpdateWebhookOptions, type ValidateSessionTokenRequest, type ValidateSessionTokenResponse, ValidationError, type Verification, type VerificationDeliveryStatus, type VerificationListResponse, type VerificationStatus, type VerifySession, type VerifySessionStatus, type Webhook, type WebhookCreatedResponse, type WebhookDelivery, type WebhookEvent, type WebhookEventType, type WebhookMessageData, type WebhookMessageStatus, type WebhookSecretRotation, WebhookSignatureError, type WebhookTestResult, Webhooks, type WorkspaceBillingItem, type WorkspaceCredits, type WorkspaceWebhook, calculateSegments, Sendly as default, generateWebhookSignature, getCountryFromPhone, isCountrySupported, parseWebhookEvent, validateMessageText, validatePhoneNumber, validateSenderId, verifyWebhookSignature };
|
|
4746
|
+
export { ALL_SUPPORTED_COUNTRIES, type Account, type AddLabelsRequest, type AnalyticsOverview, type AnalyticsPeriod, type ApiErrorResponse, type ApiKey, AuthenticationError, type AutoTopUpSettings, type BatchListResponse, type BatchMessageItem, type BatchMessageRequest, type BatchMessageResponse, type BatchMessageResult, type BatchStatus, type BillingBreakdown, type BillingBreakdownOptions, type BulkMarkValidOptions, type BulkMarkValidResponse, type BulkProvisionResult, type BulkProvisionResultItem, type BulkProvisionWorkspace, CREDITS_PER_SMS, type Campaign, type CampaignListResponse, type CampaignPreview, type CampaignStatus, type CancelledMessageResponse, type CheckNumbersResponse, type CheckVerificationRequest, type CheckVerificationResponse, type CircuitState, type Contact, type ContactList, type ContactListResponse, type ContactListsResponse, type Conversation, type ConversationListResponse, type ConversationStatus, type ConversationWithMessages, type CreateCampaignRequest, type CreateContactListRequest, type CreateContactRequest, type CreateDraftRequest, type CreateKeyOptions, type CreateLabelRequest, type CreateOptInPageOptions, type CreateOptInPageResult, type CreateTemplateRequest, type CreateVerifySessionRequest, type CreateWebhookOptions, type CreateWorkspaceOptions, type CreatedApiKey, type CreditAnalytics, type CreditAnalyticsDataPoint, type CreditTransaction, type Credits, type DeliveryAnalyticsItem, type DeliveryStatus, type DnsRecord, type DraftListResponse, type DraftStatus, type EnterpriseAccount, type EnterpriseWebhook, type EnterpriseWebhookTestResult, type EnterpriseWorkspace, type EnterpriseWorkspaceDetail, type EnterpriseWorkspaceSummary, type GenerateBusinessPageOptions, type GenerateBusinessPageResponse, type GetConversationOptions, type ImportContactItem, type ImportContactsError, type ImportContactsRequest, type ImportContactsResponse, InsufficientCreditsError, type Invitation, type Label, type LabelListResponse, type ListBatchesOptions, type ListCampaignsOptions, type ListContactsOptions, type ListConversationsOptions, type ListDraftsOptions, type ListHealthEventSource, type ListMessagesOptions, type ListScheduledMessagesOptions, type ListVerificationsOptions, type MediaFile, type MediaUploadOptions, type Message, type MessageAnalytics, type MessageAnalyticsDataPoint, type MessageDraft, type MessageListResponse, type MessageStatus, type MessageType, NetworkError, NotFoundError, type OptInPage, type PricingTier, type ProvisionWorkspaceOptions, type ProvisionWorkspaceResult, type QuotaSettings, RateLimitError, type RateLimitInfo, type ReplyToConversationRequest, type ResumeWorkspaceResult, SANDBOX_TEST_NUMBERS, SUPPORTED_COUNTRIES, type ScheduleCampaignRequest, type ScheduleMessageRequest, type ScheduledMessage, type ScheduledMessageListResponse, type ScheduledMessageStatus, type SendInvitationOptions, type SendMessageRequest, type SendVerificationRequest, type SendVerificationResponse, type SenderType, Sendly, type SendlyConfig, SendlyError, type SendlyErrorCode, type SetCustomDomainResult, type SetWorkspaceWebhookOptions, type SetWorkspaceWebhookResult, type SuggestRepliesResponse, type SuggestedReply, type SuspendWorkspaceOptions, type SuspendWorkspaceResult, type Template, type TemplateListResponse, type TemplatePreview, type TemplateStatus, type TemplateVariable, TimeoutError, type TransferCreditsOptions, type TransferCreditsResult, type UpdateAutoTopUpOptions, type UpdateCampaignRequest, type UpdateContactListRequest, type UpdateContactRequest, type UpdateConversationRequest, type UpdateDraftRequest, type UpdateOptInPageOptions, type UpdateQuotaOptions, type UpdateTemplateRequest, type UpdateWebhookOptions, type ValidateSessionTokenRequest, type ValidateSessionTokenResponse, ValidationError, type Verification, type VerificationDeliveryStatus, type VerificationListResponse, type VerificationStatus, type VerifySession, type VerifySessionStatus, type Webhook, type WebhookCreatedResponse, type WebhookDelivery, type WebhookEvent, type WebhookEventType, type WebhookMessageData, type WebhookMessageStatus, type WebhookSecretRotation, WebhookSignatureError, type WebhookTestResult, Webhooks, type WorkspaceBillingItem, type WorkspaceCredits, type WorkspaceWebhook, calculateSegments, Sendly as default, generateWebhookSignature, getCountryFromPhone, isCountrySupported, parseWebhookEvent, validateMessageText, validatePhoneNumber, validateSenderId, verifyWebhookSignature };
|
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
|
*
|
|
@@ -2610,16 +2697,118 @@ var ContactsResource = class {
|
|
|
2610
2697
|
body
|
|
2611
2698
|
});
|
|
2612
2699
|
}
|
|
2700
|
+
/**
|
|
2701
|
+
* Clear the invalid flag on a contact so future campaigns include it again.
|
|
2702
|
+
*
|
|
2703
|
+
* Contacts get auto-flagged as invalid when a send fails with a terminal
|
|
2704
|
+
* bad-number error (landline, invalid number) or when a carrier lookup
|
|
2705
|
+
* reports they can't receive SMS. Use this when you disagree with the
|
|
2706
|
+
* auto-flag — e.g. the recipient ported from a landline to mobile.
|
|
2707
|
+
*
|
|
2708
|
+
* @param id - Contact ID
|
|
2709
|
+
* @returns The contact with the flag cleared
|
|
2710
|
+
*
|
|
2711
|
+
* @example
|
|
2712
|
+
* ```typescript
|
|
2713
|
+
* const contact = await sendly.contacts.markValid('cnt_xxx');
|
|
2714
|
+
* console.log(contact.invalidReason); // null
|
|
2715
|
+
* ```
|
|
2716
|
+
*/
|
|
2717
|
+
async markValid(id) {
|
|
2718
|
+
const response = await this.http.request({
|
|
2719
|
+
method: "POST",
|
|
2720
|
+
path: `/contacts/${id}/mark-valid`
|
|
2721
|
+
});
|
|
2722
|
+
return this.transformContact(response);
|
|
2723
|
+
}
|
|
2724
|
+
/**
|
|
2725
|
+
* Clear the invalid flag on many contacts at once — the escape hatch
|
|
2726
|
+
* for when auto-flag misclassifies at scale. Pass either an explicit
|
|
2727
|
+
* id array (up to 10,000 per call) OR a `listId`, not both. Foreign
|
|
2728
|
+
* ids silently no-op via the per-organization filter.
|
|
2729
|
+
*
|
|
2730
|
+
* @param options - `{ ids }` or `{ listId }`
|
|
2731
|
+
* @returns `{ cleared }` — number of contacts whose flag was actually
|
|
2732
|
+
* cleared. Already-clean contacts and foreign ids don't count.
|
|
2733
|
+
*
|
|
2734
|
+
* @example
|
|
2735
|
+
* ```typescript
|
|
2736
|
+
* // Clear a specific set of ids
|
|
2737
|
+
* const { cleared } = await sendly.contacts.bulkMarkValid({
|
|
2738
|
+
* ids: ['cnt_abc', 'cnt_def', 'cnt_ghi'],
|
|
2739
|
+
* });
|
|
2740
|
+
*
|
|
2741
|
+
* // Clear every flagged member of a list
|
|
2742
|
+
* await sendly.contacts.bulkMarkValid({ listId: 'lst_xxx' });
|
|
2743
|
+
* ```
|
|
2744
|
+
*/
|
|
2745
|
+
async bulkMarkValid(options) {
|
|
2746
|
+
if (!options.ids && !options.listId) {
|
|
2747
|
+
throw new Error("bulkMarkValid requires either 'ids' or 'listId'");
|
|
2748
|
+
}
|
|
2749
|
+
if (options.ids && options.listId) {
|
|
2750
|
+
throw new Error("bulkMarkValid accepts 'ids' OR 'listId', not both");
|
|
2751
|
+
}
|
|
2752
|
+
return this.http.request({
|
|
2753
|
+
method: "POST",
|
|
2754
|
+
path: "/contacts/bulk-mark-valid",
|
|
2755
|
+
body: options.ids ? { ids: options.ids } : { listId: options.listId }
|
|
2756
|
+
});
|
|
2757
|
+
}
|
|
2758
|
+
/**
|
|
2759
|
+
* Trigger a background carrier lookup across your contacts. Landlines and
|
|
2760
|
+
* other non-SMS-capable numbers are auto-excluded from future campaigns.
|
|
2761
|
+
*
|
|
2762
|
+
* The lookup runs asynchronously and takes 1–5 minutes depending on list
|
|
2763
|
+
* size. Results populate the `lineType`, `carrierName`, and `invalidReason`
|
|
2764
|
+
* fields on affected contacts — fetch the contact again after a few minutes
|
|
2765
|
+
* to see updated state.
|
|
2766
|
+
*
|
|
2767
|
+
* Idempotent: re-triggering while a lookup is already running for the same
|
|
2768
|
+
* scope is a no-op.
|
|
2769
|
+
*
|
|
2770
|
+
* @param options - Optional: scope to a single list, or force re-check
|
|
2771
|
+
* @returns Acknowledgement
|
|
2772
|
+
*
|
|
2773
|
+
* @example
|
|
2774
|
+
* ```typescript
|
|
2775
|
+
* // Check all un-checked contacts
|
|
2776
|
+
* await sendly.contacts.checkNumbers();
|
|
2777
|
+
*
|
|
2778
|
+
* // Check a specific list only
|
|
2779
|
+
* await sendly.contacts.checkNumbers({ listId: 'lst_xxx' });
|
|
2780
|
+
*
|
|
2781
|
+
* // Re-check contacts even if previously looked up
|
|
2782
|
+
* await sendly.contacts.checkNumbers({ force: true });
|
|
2783
|
+
* ```
|
|
2784
|
+
*/
|
|
2785
|
+
async checkNumbers(options = {}) {
|
|
2786
|
+
return this.http.request({
|
|
2787
|
+
method: "POST",
|
|
2788
|
+
path: "/contacts/lookup",
|
|
2789
|
+
body: {
|
|
2790
|
+
listId: options.listId ?? null,
|
|
2791
|
+
force: options.force ?? false
|
|
2792
|
+
}
|
|
2793
|
+
});
|
|
2794
|
+
}
|
|
2613
2795
|
transformContact(raw) {
|
|
2796
|
+
const r = raw;
|
|
2614
2797
|
return {
|
|
2615
2798
|
id: raw.id,
|
|
2616
|
-
phoneNumber: raw.phone_number,
|
|
2799
|
+
phoneNumber: raw.phone_number ?? r.phoneNumber,
|
|
2617
2800
|
name: raw.name,
|
|
2618
2801
|
email: raw.email,
|
|
2619
2802
|
metadata: raw.metadata,
|
|
2620
|
-
optedOut: raw.opted_out,
|
|
2621
|
-
|
|
2622
|
-
|
|
2803
|
+
optedOut: raw.opted_out ?? r.optedOut,
|
|
2804
|
+
lineType: raw.line_type ?? r.lineType ?? null,
|
|
2805
|
+
carrierName: raw.carrier_name ?? r.carrierName ?? null,
|
|
2806
|
+
lineTypeCheckedAt: raw.line_type_checked_at ?? r.lineTypeCheckedAt ?? null,
|
|
2807
|
+
invalidReason: raw.invalid_reason ?? r.invalidReason ?? null,
|
|
2808
|
+
invalidatedAt: raw.invalidated_at ?? r.invalidatedAt ?? null,
|
|
2809
|
+
userMarkedValidAt: raw.user_marked_valid_at ?? r.userMarkedValidAt ?? null,
|
|
2810
|
+
createdAt: raw.created_at ?? r.createdAt,
|
|
2811
|
+
updatedAt: raw.updated_at ?? r.updatedAt,
|
|
2623
2812
|
lists: raw.lists?.map((l) => ({ id: l.id, name: l.name }))
|
|
2624
2813
|
};
|
|
2625
2814
|
}
|
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
|
*
|
|
@@ -2550,16 +2637,118 @@ var ContactsResource = class {
|
|
|
2550
2637
|
body
|
|
2551
2638
|
});
|
|
2552
2639
|
}
|
|
2640
|
+
/**
|
|
2641
|
+
* Clear the invalid flag on a contact so future campaigns include it again.
|
|
2642
|
+
*
|
|
2643
|
+
* Contacts get auto-flagged as invalid when a send fails with a terminal
|
|
2644
|
+
* bad-number error (landline, invalid number) or when a carrier lookup
|
|
2645
|
+
* reports they can't receive SMS. Use this when you disagree with the
|
|
2646
|
+
* auto-flag — e.g. the recipient ported from a landline to mobile.
|
|
2647
|
+
*
|
|
2648
|
+
* @param id - Contact ID
|
|
2649
|
+
* @returns The contact with the flag cleared
|
|
2650
|
+
*
|
|
2651
|
+
* @example
|
|
2652
|
+
* ```typescript
|
|
2653
|
+
* const contact = await sendly.contacts.markValid('cnt_xxx');
|
|
2654
|
+
* console.log(contact.invalidReason); // null
|
|
2655
|
+
* ```
|
|
2656
|
+
*/
|
|
2657
|
+
async markValid(id) {
|
|
2658
|
+
const response = await this.http.request({
|
|
2659
|
+
method: "POST",
|
|
2660
|
+
path: `/contacts/${id}/mark-valid`
|
|
2661
|
+
});
|
|
2662
|
+
return this.transformContact(response);
|
|
2663
|
+
}
|
|
2664
|
+
/**
|
|
2665
|
+
* Clear the invalid flag on many contacts at once — the escape hatch
|
|
2666
|
+
* for when auto-flag misclassifies at scale. Pass either an explicit
|
|
2667
|
+
* id array (up to 10,000 per call) OR a `listId`, not both. Foreign
|
|
2668
|
+
* ids silently no-op via the per-organization filter.
|
|
2669
|
+
*
|
|
2670
|
+
* @param options - `{ ids }` or `{ listId }`
|
|
2671
|
+
* @returns `{ cleared }` — number of contacts whose flag was actually
|
|
2672
|
+
* cleared. Already-clean contacts and foreign ids don't count.
|
|
2673
|
+
*
|
|
2674
|
+
* @example
|
|
2675
|
+
* ```typescript
|
|
2676
|
+
* // Clear a specific set of ids
|
|
2677
|
+
* const { cleared } = await sendly.contacts.bulkMarkValid({
|
|
2678
|
+
* ids: ['cnt_abc', 'cnt_def', 'cnt_ghi'],
|
|
2679
|
+
* });
|
|
2680
|
+
*
|
|
2681
|
+
* // Clear every flagged member of a list
|
|
2682
|
+
* await sendly.contacts.bulkMarkValid({ listId: 'lst_xxx' });
|
|
2683
|
+
* ```
|
|
2684
|
+
*/
|
|
2685
|
+
async bulkMarkValid(options) {
|
|
2686
|
+
if (!options.ids && !options.listId) {
|
|
2687
|
+
throw new Error("bulkMarkValid requires either 'ids' or 'listId'");
|
|
2688
|
+
}
|
|
2689
|
+
if (options.ids && options.listId) {
|
|
2690
|
+
throw new Error("bulkMarkValid accepts 'ids' OR 'listId', not both");
|
|
2691
|
+
}
|
|
2692
|
+
return this.http.request({
|
|
2693
|
+
method: "POST",
|
|
2694
|
+
path: "/contacts/bulk-mark-valid",
|
|
2695
|
+
body: options.ids ? { ids: options.ids } : { listId: options.listId }
|
|
2696
|
+
});
|
|
2697
|
+
}
|
|
2698
|
+
/**
|
|
2699
|
+
* Trigger a background carrier lookup across your contacts. Landlines and
|
|
2700
|
+
* other non-SMS-capable numbers are auto-excluded from future campaigns.
|
|
2701
|
+
*
|
|
2702
|
+
* The lookup runs asynchronously and takes 1–5 minutes depending on list
|
|
2703
|
+
* size. Results populate the `lineType`, `carrierName`, and `invalidReason`
|
|
2704
|
+
* fields on affected contacts — fetch the contact again after a few minutes
|
|
2705
|
+
* to see updated state.
|
|
2706
|
+
*
|
|
2707
|
+
* Idempotent: re-triggering while a lookup is already running for the same
|
|
2708
|
+
* scope is a no-op.
|
|
2709
|
+
*
|
|
2710
|
+
* @param options - Optional: scope to a single list, or force re-check
|
|
2711
|
+
* @returns Acknowledgement
|
|
2712
|
+
*
|
|
2713
|
+
* @example
|
|
2714
|
+
* ```typescript
|
|
2715
|
+
* // Check all un-checked contacts
|
|
2716
|
+
* await sendly.contacts.checkNumbers();
|
|
2717
|
+
*
|
|
2718
|
+
* // Check a specific list only
|
|
2719
|
+
* await sendly.contacts.checkNumbers({ listId: 'lst_xxx' });
|
|
2720
|
+
*
|
|
2721
|
+
* // Re-check contacts even if previously looked up
|
|
2722
|
+
* await sendly.contacts.checkNumbers({ force: true });
|
|
2723
|
+
* ```
|
|
2724
|
+
*/
|
|
2725
|
+
async checkNumbers(options = {}) {
|
|
2726
|
+
return this.http.request({
|
|
2727
|
+
method: "POST",
|
|
2728
|
+
path: "/contacts/lookup",
|
|
2729
|
+
body: {
|
|
2730
|
+
listId: options.listId ?? null,
|
|
2731
|
+
force: options.force ?? false
|
|
2732
|
+
}
|
|
2733
|
+
});
|
|
2734
|
+
}
|
|
2553
2735
|
transformContact(raw) {
|
|
2736
|
+
const r = raw;
|
|
2554
2737
|
return {
|
|
2555
2738
|
id: raw.id,
|
|
2556
|
-
phoneNumber: raw.phone_number,
|
|
2739
|
+
phoneNumber: raw.phone_number ?? r.phoneNumber,
|
|
2557
2740
|
name: raw.name,
|
|
2558
2741
|
email: raw.email,
|
|
2559
2742
|
metadata: raw.metadata,
|
|
2560
|
-
optedOut: raw.opted_out,
|
|
2561
|
-
|
|
2562
|
-
|
|
2743
|
+
optedOut: raw.opted_out ?? r.optedOut,
|
|
2744
|
+
lineType: raw.line_type ?? r.lineType ?? null,
|
|
2745
|
+
carrierName: raw.carrier_name ?? r.carrierName ?? null,
|
|
2746
|
+
lineTypeCheckedAt: raw.line_type_checked_at ?? r.lineTypeCheckedAt ?? null,
|
|
2747
|
+
invalidReason: raw.invalid_reason ?? r.invalidReason ?? null,
|
|
2748
|
+
invalidatedAt: raw.invalidated_at ?? r.invalidatedAt ?? null,
|
|
2749
|
+
userMarkedValidAt: raw.user_marked_valid_at ?? r.userMarkedValidAt ?? null,
|
|
2750
|
+
createdAt: raw.created_at ?? r.createdAt,
|
|
2751
|
+
updatedAt: raw.updated_at ?? r.updatedAt,
|
|
2563
2752
|
lists: raw.lists?.map((l) => ({ id: l.id, name: l.name }))
|
|
2564
2753
|
};
|
|
2565
2754
|
}
|