@messagebird/sdk 0.42.0 → 0.43.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.mjs CHANGED
@@ -785,6 +785,17 @@ var BirdTimeoutError = class extends BirdError {
785
785
  Object.setPrototypeOf(this, new.target.prototype);
786
786
  }
787
787
  };
788
+ /**
789
+ * An API call on a client constructed without `apiKey` (a receiver-only
790
+ * client, which can still `unwrap` webhooks). Thrown before any request.
791
+ */
792
+ var BirdMissingApiKeyError = class extends BirdError {
793
+ constructor(message) {
794
+ super(message);
795
+ this.name = "BirdMissingApiKeyError";
796
+ Object.setPrototypeOf(this, new.target.prototype);
797
+ }
798
+ };
788
799
  /** A webhook payload failed signature verification (bad signature, stale timestamp, malformed headers). */
789
800
  var BirdWebhookVerificationError = class extends BirdError {
790
801
  constructor(message) {
@@ -1050,6 +1061,7 @@ var BirdHTTPClient = class {
1050
1061
  * `AbortError` if the caller's signal aborts.
1051
1062
  */
1052
1063
  async request(call, options) {
1064
+ if (this.defaults.missingAuth) throw new BirdMissingApiKeyError(this.defaults.missingAuth);
1053
1065
  const maxRetries = options.maxRetries ?? this.defaults.maxRetries;
1054
1066
  const timeout = options.timeout ?? this.defaults.timeout;
1055
1067
  const idempotencyKey = options.idempotencyKey ?? (isMutation(options.method) ? crypto.randomUUID() : void 0);
@@ -3999,6 +4011,188 @@ const listMailboxLabels = (options) => (options.client ?? client).get({
3999
4011
  ...options
4000
4012
  });
4001
4013
  /**
4014
+ * List webhook endpoints
4015
+ *
4016
+ * Returns the workspace's webhook endpoints as a cursor-paginated list, newest first by default. Endpoint objects never include the signing secret; to inspect a single endpoint, use [Get a webhook endpoint](/docs/api/reference/get-webhook).
4017
+ *
4018
+ */
4019
+ const listWebhooks = (options) => (options?.client ?? client).get({
4020
+ security: [{
4021
+ scheme: "bearer",
4022
+ type: "http"
4023
+ }, {
4024
+ in: "cookie",
4025
+ name: "bird_session",
4026
+ type: "apiKey"
4027
+ }],
4028
+ url: "/v1/webhooks",
4029
+ ...options
4030
+ });
4031
+ /**
4032
+ * Create a webhook endpoint
4033
+ *
4034
+ * Registers an `active` webhook endpoint that receives the event types in `events` as signed HTTPS `POST` requests. See the [webhooks guide](/docs/guides/webhooks) for delivery, signing, and retry behavior.
4035
+ *
4036
+ * The `201` response is the only response that includes the signing secret (`whsec_` prefix). Store it immediately; if it is lost, [rotate the signing secret](/docs/api/reference/rotate-webhook-secret).
4037
+ *
4038
+ * A non-HTTPS or non-public `url`, an unknown event type, or exceeding the organization's endpoint limit returns `422`.
4039
+ *
4040
+ */
4041
+ const createWebhook = (options) => (options.client ?? client).post({
4042
+ security: [{
4043
+ scheme: "bearer",
4044
+ type: "http"
4045
+ }, {
4046
+ in: "cookie",
4047
+ name: "bird_session",
4048
+ type: "apiKey"
4049
+ }],
4050
+ url: "/v1/webhooks",
4051
+ ...options,
4052
+ headers: {
4053
+ "Content-Type": "application/json",
4054
+ ...options.headers
4055
+ }
4056
+ });
4057
+ /**
4058
+ * Delete a webhook endpoint
4059
+ *
4060
+ * Permanently removes the webhook endpoint and stops all deliveries to it, including retries of earlier failed deliveries. This cannot be undone: recreating an endpoint later mints a new `id` and signing secret. To stop deliveries temporarily instead, set `status` to `paused` with [Update a webhook endpoint](/docs/api/reference/update-webhook).
4061
+ *
4062
+ */
4063
+ const deleteWebhook = (options) => (options.client ?? client).delete({
4064
+ security: [{
4065
+ scheme: "bearer",
4066
+ type: "http"
4067
+ }, {
4068
+ in: "cookie",
4069
+ name: "bird_session",
4070
+ type: "apiKey"
4071
+ }],
4072
+ url: "/v1/webhooks/{webhook_id}",
4073
+ ...options
4074
+ });
4075
+ /**
4076
+ * Get a webhook endpoint
4077
+ *
4078
+ * Returns one webhook endpoint's configuration and current delivery `status`, including its URL and subscribed event types. The signing secret is never included; if you lost it, mint a new one with [Rotate webhook signing secret](/docs/api/reference/rotate-webhook-secret).
4079
+ *
4080
+ */
4081
+ const getWebhook = (options) => (options.client ?? client).get({
4082
+ security: [{
4083
+ scheme: "bearer",
4084
+ type: "http"
4085
+ }, {
4086
+ in: "cookie",
4087
+ name: "bird_session",
4088
+ type: "apiKey"
4089
+ }],
4090
+ url: "/v1/webhooks/{webhook_id}",
4091
+ ...options
4092
+ });
4093
+ /**
4094
+ * Update a webhook endpoint
4095
+ *
4096
+ * Updates the webhook endpoint. Only the fields you send change: `events` replaces the
4097
+ * whole subscription set, and `status` pauses or re-enables delivery.
4098
+ *
4099
+ * The `200` response is the updated endpoint. Invalid input (a non-HTTPS or non-public
4100
+ * `url`, an event type outside the catalog) returns a `422`.
4101
+ *
4102
+ */
4103
+ const updateWebhook = (options) => (options.client ?? client).patch({
4104
+ security: [{
4105
+ scheme: "bearer",
4106
+ type: "http"
4107
+ }, {
4108
+ in: "cookie",
4109
+ name: "bird_session",
4110
+ type: "apiKey"
4111
+ }],
4112
+ url: "/v1/webhooks/{webhook_id}",
4113
+ ...options,
4114
+ headers: {
4115
+ "Content-Type": "application/json",
4116
+ ...options.headers
4117
+ }
4118
+ });
4119
+ /**
4120
+ * Rotate webhook signing secret
4121
+ *
4122
+ * Generates a new signing secret for the endpoint and returns it exactly once: store it
4123
+ * immediately, it cannot be retrieved after this response. For 24 hours every delivery
4124
+ * is signed with both the old and the new secret, so a receiver verifying with either
4125
+ * keeps working while you roll the new one out. After the window the old secret stops
4126
+ * signing. Verification details are in the [webhooks guide](/docs/guides/webhooks).
4127
+ *
4128
+ * An endpoint holds at most 5 concurrently valid secrets, so rotating repeatedly within
4129
+ * the overlap window fails with `WebhookTooManySecrets` until an older secret expires.
4130
+ *
4131
+ */
4132
+ const rotateWebhookSecret = (options) => (options.client ?? client).post({
4133
+ security: [{
4134
+ scheme: "bearer",
4135
+ type: "http"
4136
+ }, {
4137
+ in: "cookie",
4138
+ name: "bird_session",
4139
+ type: "apiKey"
4140
+ }],
4141
+ url: "/v1/webhooks/{webhook_id}/rotate-secret",
4142
+ ...options
4143
+ });
4144
+ /**
4145
+ * Test a webhook with a sample event
4146
+ *
4147
+ * Sends a signed synthetic event and returns whether your endpoint accepted it, its HTTP status, and the round-trip latency. An unreachable endpoint returns `status: failed` in the response body. The endpoint has 10 seconds to respond.
4148
+ *
4149
+ * The body is a minimal JSON object with the event `type`, signed like a real delivery. It does not mirror that event's payload. Tests work on paused endpoints and do not appear in [List delivery attempts](/docs/api/reference/list-webhook-attempts).
4150
+ *
4151
+ * The operation returns `412` if the endpoint lacks a valid signing secret or, when `event_type` is omitted, has no subscribed event type to use.
4152
+ *
4153
+ */
4154
+ const testWebhook = (options) => (options.client ?? client).post({
4155
+ security: [{
4156
+ scheme: "bearer",
4157
+ type: "http"
4158
+ }, {
4159
+ in: "cookie",
4160
+ name: "bird_session",
4161
+ type: "apiKey"
4162
+ }],
4163
+ url: "/v1/webhooks/{webhook_id}/test",
4164
+ ...options,
4165
+ headers: {
4166
+ "Content-Type": "application/json",
4167
+ ...options.headers
4168
+ }
4169
+ });
4170
+ /**
4171
+ * List delivery attempts
4172
+ *
4173
+ * Returns the endpoint's recent delivery attempts, newest first. Each entry is one HTTP
4174
+ * request, so a retried event appears once per try; use it to see what failed and why
4175
+ * before requesting redelivery with
4176
+ * [Replay missed events](/docs/api/reference/create-webhook-replay).
4177
+ *
4178
+ * Bound the window with the `before`/`after` timestamps and cap the page with `limit`.
4179
+ * To page further back without a cursor, pass the oldest `attempted_at`
4180
+ * you received as `before`.
4181
+ *
4182
+ */
4183
+ const listWebhookAttempts = (options) => (options.client ?? client).get({
4184
+ security: [{
4185
+ scheme: "bearer",
4186
+ type: "http"
4187
+ }, {
4188
+ in: "cookie",
4189
+ name: "bird_session",
4190
+ type: "apiKey"
4191
+ }],
4192
+ url: "/v1/webhooks/{webhook_id}/attempts",
4193
+ ...options
4194
+ });
4195
+ /**
4002
4196
  * List your allocated numbers
4003
4197
  *
4004
4198
  * Returns a paginated list of the phone numbers currently allocated to your workspace, newest first. Each entry is either a dedicated number you bought or a shared number managed for you, as its `kind` field indicates. Pass `number` to look one up, or narrow the list with `country_code`, `number_type`, `prefix`, and `capabilities`. An allocated number is not always enough to send from it: some countries also require an approved registration for the sender.
@@ -6567,10 +6761,155 @@ var VerifyResource = class {
6567
6761
  }
6568
6762
  };
6569
6763
  //#endregion
6764
+ //#region src/resources/webhooks.gen.ts
6765
+ var WebhooksResourceBase = class extends Resource {
6766
+ /**
6767
+ * List the workspace's webhook endpoints (URL, subscribed events, status) as a cursor page.
6768
+ *
6769
+ * @example Iterate every webhook endpoint
6770
+ * for await (const endpoint of bird.webhooks.list()) {
6771
+ * console.log(endpoint.id, endpoint.url, endpoint.status);
6772
+ * }
6773
+ */
6774
+ list(query, options) {
6775
+ return this.paginated("GET", options, ({ signal, headers }, cursor) => listWebhooks({
6776
+ client: this.client,
6777
+ query: {
6778
+ ...query,
6779
+ starting_after: cursor ?? query?.starting_after
6780
+ },
6781
+ headers,
6782
+ signal
6783
+ }));
6784
+ }
6785
+ /**
6786
+ * Read one endpoint's URL, subscribed event types, and current delivery status. The signing secret is never included, and can only be rotated rather than retrieved.
6787
+ *
6788
+ * @example Fetch one endpoint by id
6789
+ * const endpoint = await bird.webhooks.get("whk_01krdgeqcxet5s7t44vh8rt9mg");
6790
+ * console.log(endpoint.url, endpoint.events);
6791
+ */
6792
+ get(webhookId, options) {
6793
+ return this.call("GET", options, ({ signal, headers }) => getWebhook({
6794
+ client: this.client,
6795
+ path: { webhook_id: webhookId },
6796
+ headers,
6797
+ signal
6798
+ }));
6799
+ }
6800
+ /**
6801
+ * Register an HTTPS endpoint to receive this workspace's events, subscribed to the event types in `events` and active immediately. The response is the only place the signing secret appears, and it can never be read back afterward, only rotated.
6802
+ *
6803
+ * @example Subscribe an endpoint to events
6804
+ * const created = await bird.webhooks.create({
6805
+ * url: "https://acme.com/hooks/bird",
6806
+ * events: ["email.delivered", "email.bounced"],
6807
+ * description: "Delivery pipeline",
6808
+ * });
6809
+ * console.log(created.id, created.secret);
6810
+ */
6811
+ create(params, options) {
6812
+ return this.call("POST", options, ({ signal, headers }) => createWebhook({
6813
+ client: this.client,
6814
+ body: params,
6815
+ headers,
6816
+ signal
6817
+ }));
6818
+ }
6819
+ /**
6820
+ * Send a signed synthetic event and get the outcome synchronously: whether the endpoint accepted, the HTTP status it returned, and the round-trip latency. An unreachable endpoint comes back as a failed status in the body rather than a request error. The receiver has 10 seconds, the body is a minimal stub carrying only the event type, and a test reaches even a paused endpoint without being recorded in the delivery attempts.
6821
+ *
6822
+ * @example Send a test event to an endpoint
6823
+ * const result = await bird.webhooks.test("whk_01krdgeqcxet5s7t44vh8rt9mg", {
6824
+ * event_type: "email.delivered",
6825
+ * });
6826
+ * console.log(result.status);
6827
+ */
6828
+ test(webhookId, params = {}, options) {
6829
+ return this.call("POST", options, ({ signal, headers }) => testWebhook({
6830
+ client: this.client,
6831
+ path: { webhook_id: webhookId },
6832
+ body: params,
6833
+ headers,
6834
+ signal
6835
+ }));
6836
+ }
6837
+ /**
6838
+ * Permanently remove an endpoint and stop every delivery to it, including retries of earlier failures. Recreating it later mints a new ID and signing secret; to stop deliveries temporarily instead, set its status to `paused`.
6839
+ *
6840
+ * @example Stop delivery to an endpoint
6841
+ * await bird.webhooks.delete("whk_01krdgeqcxet5s7t44vh8rt9mg");
6842
+ */
6843
+ delete(webhookId, options) {
6844
+ return this.call("DELETE", options, ({ signal, headers }) => deleteWebhook({
6845
+ client: this.client,
6846
+ path: { webhook_id: webhookId },
6847
+ headers,
6848
+ signal
6849
+ }));
6850
+ }
6851
+ /**
6852
+ * List an endpoint's recent delivery attempts, newest first. Each entry is one HTTP request, so a retried event appears once per try. Pagination uses the `before`/`after` timestamps; page further back by passing the oldest `attempted_at` you received as `before`.
6853
+ *
6854
+ * @example Inspect recent delivery attempts
6855
+ * const attempts = await bird.webhooks.attempts(
6856
+ * "whk_01krdgeqcxet5s7t44vh8rt9mg",
6857
+ * );
6858
+ * for (const attempt of attempts.data) {
6859
+ * console.log(attempt.status, attempt.response_status_code);
6860
+ * }
6861
+ */
6862
+ attempts(webhookId, query, options) {
6863
+ return this.call("GET", options, ({ signal, headers }) => listWebhookAttempts({
6864
+ client: this.client,
6865
+ path: { webhook_id: webhookId },
6866
+ query,
6867
+ headers,
6868
+ signal
6869
+ }));
6870
+ }
6871
+ /**
6872
+ * Mint a new signing secret and return it exactly once; it cannot be retrieved afterward. Both the old and new secrets sign every delivery for 24 hours, after which the old one stops signing. An endpoint holds at most 5 valid secrets, so rotating repeatedly inside that window fails.
6873
+ *
6874
+ * @example Rotate an endpoint's signing secret
6875
+ * const rotated = await bird.webhooks.rotateSecret(
6876
+ * "whk_01krdgeqcxet5s7t44vh8rt9mg",
6877
+ * );
6878
+ * console.log(rotated.secret);
6879
+ */
6880
+ rotateSecret(webhookId, options) {
6881
+ return this.call("POST", options, ({ signal, headers }) => rotateWebhookSecret({
6882
+ client: this.client,
6883
+ path: { webhook_id: webhookId },
6884
+ headers,
6885
+ signal
6886
+ }));
6887
+ }
6888
+ /**
6889
+ * Change an endpoint's URL, description, subscribed event types, or delivery status. Only the fields sent change: `events` replaces the whole subscription set, and `status` pauses or re-enables delivery. Events fired while paused are not delivered.
6890
+ *
6891
+ * @example Change the subscribed event types
6892
+ * const endpoint = await bird.webhooks.update("whk_01krdgeqcxet5s7t44vh8rt9mg", {
6893
+ * events: ["email.delivered"],
6894
+ * });
6895
+ * console.log(endpoint.events);
6896
+ */
6897
+ update(webhookId, params = {}, options) {
6898
+ return this.call("PATCH", options, ({ signal, headers }) => updateWebhook({
6899
+ client: this.client,
6900
+ path: { webhook_id: webhookId },
6901
+ body: params,
6902
+ headers,
6903
+ signal
6904
+ }));
6905
+ }
6906
+ };
6907
+ //#endregion
6570
6908
  //#region src/resources/webhooks.ts
6571
- var WebhooksResource = class {
6909
+ var WebhooksResource = class extends WebhooksResourceBase {
6572
6910
  #secret;
6573
- constructor(config) {
6911
+ constructor(core, client, config) {
6912
+ super(core, client);
6574
6913
  this.#secret = config?.secret;
6575
6914
  }
6576
6915
  /**
@@ -7329,8 +7668,11 @@ const DEFAULT_TIMEOUT_MS = 6e4;
7329
7668
  const DEFAULT_MAX_RETRIES = 2;
7330
7669
  function resolveBaseUrl(options) {
7331
7670
  if (options.baseUrl) return options.baseUrl;
7332
- const region = options.region ?? regionFromApiKey(options.apiKey);
7333
- if (!region) throw new Error("Unable to determine region: API key is not in the expected bk_{region}_{token} format. Pass an explicit `region` or `baseUrl`.");
7671
+ const region = options.region ?? (options.apiKey ? regionFromApiKey(options.apiKey) : void 0);
7672
+ if (!region) {
7673
+ if (!options.apiKey) return void 0;
7674
+ throw new Error("Unable to determine region: API key is not in the expected bk_{region}_{token} format. Pass an explicit `region` or `baseUrl`.");
7675
+ }
7334
7676
  return baseUrlForRegion(region);
7335
7677
  }
7336
7678
  function resolveRawRequestUrl(baseUrl, path) {
@@ -7375,6 +7717,7 @@ var BirdClient = class {
7375
7717
  core;
7376
7718
  #client;
7377
7719
  #baseUrl;
7720
+ #missingAuth;
7378
7721
  #fetch;
7379
7722
  #headers;
7380
7723
  /** Email channel: `bird.email.send(...)`, `.get(...)`, `.list(...)`. */
@@ -7415,14 +7758,16 @@ var BirdClient = class {
7415
7758
  realtime;
7416
7759
  constructor(options) {
7417
7760
  const opts = options;
7761
+ if (!opts.apiKey && !opts.webhooks?.secret) throw new BirdError("Configure `apiKey` for API calls, or `webhooks: { secret }` for a receiver-only client.");
7762
+ if (!opts.apiKey) this.#missingAuth = "This client has no API key (webhook verification only); pass `apiKey` to call the API.";
7418
7763
  this.#baseUrl = resolveBaseUrl(opts);
7419
7764
  this.#fetch = opts.fetch ?? fetch;
7420
7765
  this.#headers = {
7421
7766
  ...opts.defaultHeaders,
7422
- Authorization: `Bearer ${opts.apiKey}`,
7423
- "User-Agent": `bird-sdk-js/0.42.0`,
7767
+ ...opts.apiKey ? { Authorization: `Bearer ${opts.apiKey}` } : {},
7768
+ "User-Agent": `bird-sdk-js/0.43.0`,
7424
7769
  "Bird-Surface": "sdk-js",
7425
- "Bird-Version": "0.42.0"
7770
+ "Bird-Version": "0.43.0"
7426
7771
  };
7427
7772
  const caller = detectCaller();
7428
7773
  if (caller) this.#headers["Bird-Caller"] = caller;
@@ -7434,6 +7779,7 @@ var BirdClient = class {
7434
7779
  this.core = new BirdHTTPClient({
7435
7780
  timeout: opts.timeout ?? DEFAULT_TIMEOUT_MS,
7436
7781
  maxRetries: opts.maxRetries ?? DEFAULT_MAX_RETRIES,
7782
+ missingAuth: this.#missingAuth,
7437
7783
  credentials: {
7438
7784
  RealtimeKey: {
7439
7785
  header: "X-Realtime-Key",
@@ -7463,7 +7809,7 @@ var BirdClient = class {
7463
7809
  this.domains = new DomainsResource(this.core, this.#client);
7464
7810
  this.lookup = new LookupResource(this.core, this.#client);
7465
7811
  this.numbers = new NumbersResource(this.core, this.#client);
7466
- this.webhooks = new WebhooksResource(opts.webhooks);
7812
+ this.webhooks = new WebhooksResource(this.core, this.#client, opts.webhooks);
7467
7813
  this.realtime = new RealtimeResource(this.core, this.#client, opts.realtime);
7468
7814
  }
7469
7815
  /**
@@ -7480,6 +7826,7 @@ var BirdClient = class {
7480
7826
  * console.log(suppressions.data.length);
7481
7827
  */
7482
7828
  request(req, options) {
7829
+ if (this.#missingAuth || this.#baseUrl === void 0) throw new BirdMissingApiKeyError(this.#missingAuth ?? "This client has no API key (webhook verification only); pass `apiKey` to call the API.");
7483
7830
  const url = resolveRawRequestUrl(this.#baseUrl, req.path);
7484
7831
  return apiPromise(this.core.request((ctx) => this.#raw(url, req, ctx, options?.headers), {
7485
7832
  method: req.method,
@@ -7891,6 +8238,6 @@ const WhatsAppTemplateParameterType = {
7891
8238
  Video: "video"
7892
8239
  };
7893
8240
  //#endregion
7894
- export { BirdAPIError, BirdAuthError, BirdBadRequestError, BirdBillingError, BirdClient, BirdConflictError, BirdConnectionError, BirdError, BirdInternalError, BirdMisdirectedError, BirdNotFoundError, BirdNotImplementedError, BirdPayloadTooLargeError, BirdPermissionError, BirdPreconditionError, BirdRateLimitError, BirdServiceUnavailableError, BirdTimeoutError, BirdValidationError, BirdWebhookVerificationError, EmailEventType, EmailLookupFlag, EmailLookupReason, EmailLookupResult, LookupFlag, LookupPropertyStatus, NumberCapability, NumberType, NumbersOrderStatus, PreferenceChannel, PreferenceOrigin, SMSErrorCode, SMSKeywordOperation, SMSSuppressionCoverage, SMSSuppressionEndReason, SMSSuppressionOrigin, SMSSuppressionReason, TemplateLanguageStatus, TemplateStatus, VerificationAttemptFailureReason, VerificationChannel, VerificationTerminalReason, WebhookEventType, WhatsAppErrorCode, WhatsAppEventType, WhatsAppTemplateCategory, WhatsAppTemplateParameterType, baseUrlForRegion, regionFromApiKey };
8241
+ export { BirdAPIError, BirdAuthError, BirdBadRequestError, BirdBillingError, BirdClient, BirdConflictError, BirdConnectionError, BirdError, BirdInternalError, BirdMisdirectedError, BirdMissingApiKeyError, BirdNotFoundError, BirdNotImplementedError, BirdPayloadTooLargeError, BirdPermissionError, BirdPreconditionError, BirdRateLimitError, BirdServiceUnavailableError, BirdTimeoutError, BirdValidationError, BirdWebhookVerificationError, EmailEventType, EmailLookupFlag, EmailLookupReason, EmailLookupResult, LookupFlag, LookupPropertyStatus, NumberCapability, NumberType, NumbersOrderStatus, PreferenceChannel, PreferenceOrigin, SMSErrorCode, SMSKeywordOperation, SMSSuppressionCoverage, SMSSuppressionEndReason, SMSSuppressionOrigin, SMSSuppressionReason, TemplateLanguageStatus, TemplateStatus, VerificationAttemptFailureReason, VerificationChannel, VerificationTerminalReason, WebhookEventType, WhatsAppErrorCode, WhatsAppEventType, WhatsAppTemplateCategory, WhatsAppTemplateParameterType, baseUrlForRegion, regionFromApiKey };
7895
8242
 
7896
8243
  //# sourceMappingURL=index.mjs.map