@sendly/node
Advanced tools
+125
-0
@@ -441,2 +441,72 @@ /** | ||
| /** | ||
| * Preview result for a single message in a batch | ||
| */ | ||
| interface BatchPreviewItem { | ||
| /** | ||
| * Destination phone number | ||
| */ | ||
| to: string; | ||
| /** | ||
| * Whether this message will be sent | ||
| */ | ||
| willSend: boolean; | ||
| /** | ||
| * Number of SMS segments | ||
| */ | ||
| segments: number; | ||
| /** | ||
| * Credits required for this message | ||
| */ | ||
| creditsNeeded: number; | ||
| /** | ||
| * Warning message (e.g., quiet hours) | ||
| */ | ||
| warning?: string; | ||
| /** | ||
| * Block reason if willSend is false | ||
| */ | ||
| blockReason?: string; | ||
| } | ||
| /** | ||
| * Response from previewing a batch (dry run) | ||
| */ | ||
| interface BatchPreviewResponse { | ||
| /** | ||
| * Whether the batch can be sent | ||
| */ | ||
| canSend: boolean; | ||
| /** | ||
| * Total number of messages | ||
| */ | ||
| totalMessages: number; | ||
| /** | ||
| * Number of messages that will be sent | ||
| */ | ||
| willSend: number; | ||
| /** | ||
| * Number of messages that will be blocked | ||
| */ | ||
| blocked: number; | ||
| /** | ||
| * Total credits required | ||
| */ | ||
| creditsNeeded: number; | ||
| /** | ||
| * Current credit balance | ||
| */ | ||
| currentBalance: number; | ||
| /** | ||
| * Whether user has enough credits | ||
| */ | ||
| hasEnoughCredits: boolean; | ||
| /** | ||
| * Per-message preview details | ||
| */ | ||
| messages: BatchPreviewItem[]; | ||
| /** | ||
| * Summary of why messages are blocked (if any) | ||
| */ | ||
| blockReasons?: Record<string, number>; | ||
| } | ||
| /** | ||
| * Error codes returned by the Sendly API | ||
@@ -1086,2 +1156,25 @@ */ | ||
| listBatches(options?: ListBatchesOptions): Promise<BatchListResponse>; | ||
| /** | ||
| * Preview a batch without sending (dry run) | ||
| * | ||
| * @param request - Batch request with array of messages | ||
| * @returns Preview showing what would happen if batch was sent | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * const preview = await sendly.messages.previewBatch({ | ||
| * messages: [ | ||
| * { to: '+15551234567', text: 'Hello User 1!' }, | ||
| * { to: '+15559876543', text: 'Hello User 2!' } | ||
| * ] | ||
| * }); | ||
| * | ||
| * console.log(preview.canSend); // true/false | ||
| * console.log(preview.creditsNeeded); // 2 | ||
| * console.log(preview.hasEnoughCredits); // true/false | ||
| * ``` | ||
| * | ||
| * @throws {ValidationError} If any message is invalid | ||
| */ | ||
| previewBatch(request: BatchMessageRequest): Promise<BatchPreviewResponse>; | ||
| } | ||
@@ -1412,2 +1505,34 @@ | ||
| }>; | ||
| /** | ||
| * Create a new API key | ||
| * | ||
| * @param name - Display name for the API key | ||
| * @param options - Optional settings | ||
| * @returns The created API key with the full key value (only shown once) | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * const { apiKey, key } = await sendly.account.createApiKey('Production'); | ||
| * console.log(`Created key: ${key}`); // Full key - save this! | ||
| * console.log(`Key ID: ${apiKey.id}`); | ||
| * ``` | ||
| */ | ||
| createApiKey(name: string, options?: { | ||
| expiresAt?: string; | ||
| }): Promise<{ | ||
| apiKey: ApiKey; | ||
| key: string; | ||
| }>; | ||
| /** | ||
| * Revoke an API key | ||
| * | ||
| * @param id - API key ID to revoke | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * await sendly.account.revokeApiKey('key_xxx'); | ||
| * console.log('API key revoked'); | ||
| * ``` | ||
| */ | ||
| revokeApiKey(id: string): Promise<void>; | ||
| } | ||
@@ -1414,0 +1539,0 @@ |
+125
-0
@@ -441,2 +441,72 @@ /** | ||
| /** | ||
| * Preview result for a single message in a batch | ||
| */ | ||
| interface BatchPreviewItem { | ||
| /** | ||
| * Destination phone number | ||
| */ | ||
| to: string; | ||
| /** | ||
| * Whether this message will be sent | ||
| */ | ||
| willSend: boolean; | ||
| /** | ||
| * Number of SMS segments | ||
| */ | ||
| segments: number; | ||
| /** | ||
| * Credits required for this message | ||
| */ | ||
| creditsNeeded: number; | ||
| /** | ||
| * Warning message (e.g., quiet hours) | ||
| */ | ||
| warning?: string; | ||
| /** | ||
| * Block reason if willSend is false | ||
| */ | ||
| blockReason?: string; | ||
| } | ||
| /** | ||
| * Response from previewing a batch (dry run) | ||
| */ | ||
| interface BatchPreviewResponse { | ||
| /** | ||
| * Whether the batch can be sent | ||
| */ | ||
| canSend: boolean; | ||
| /** | ||
| * Total number of messages | ||
| */ | ||
| totalMessages: number; | ||
| /** | ||
| * Number of messages that will be sent | ||
| */ | ||
| willSend: number; | ||
| /** | ||
| * Number of messages that will be blocked | ||
| */ | ||
| blocked: number; | ||
| /** | ||
| * Total credits required | ||
| */ | ||
| creditsNeeded: number; | ||
| /** | ||
| * Current credit balance | ||
| */ | ||
| currentBalance: number; | ||
| /** | ||
| * Whether user has enough credits | ||
| */ | ||
| hasEnoughCredits: boolean; | ||
| /** | ||
| * Per-message preview details | ||
| */ | ||
| messages: BatchPreviewItem[]; | ||
| /** | ||
| * Summary of why messages are blocked (if any) | ||
| */ | ||
| blockReasons?: Record<string, number>; | ||
| } | ||
| /** | ||
| * Error codes returned by the Sendly API | ||
@@ -1086,2 +1156,25 @@ */ | ||
| listBatches(options?: ListBatchesOptions): Promise<BatchListResponse>; | ||
| /** | ||
| * Preview a batch without sending (dry run) | ||
| * | ||
| * @param request - Batch request with array of messages | ||
| * @returns Preview showing what would happen if batch was sent | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * const preview = await sendly.messages.previewBatch({ | ||
| * messages: [ | ||
| * { to: '+15551234567', text: 'Hello User 1!' }, | ||
| * { to: '+15559876543', text: 'Hello User 2!' } | ||
| * ] | ||
| * }); | ||
| * | ||
| * console.log(preview.canSend); // true/false | ||
| * console.log(preview.creditsNeeded); // 2 | ||
| * console.log(preview.hasEnoughCredits); // true/false | ||
| * ``` | ||
| * | ||
| * @throws {ValidationError} If any message is invalid | ||
| */ | ||
| previewBatch(request: BatchMessageRequest): Promise<BatchPreviewResponse>; | ||
| } | ||
@@ -1412,2 +1505,34 @@ | ||
| }>; | ||
| /** | ||
| * Create a new API key | ||
| * | ||
| * @param name - Display name for the API key | ||
| * @param options - Optional settings | ||
| * @returns The created API key with the full key value (only shown once) | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * const { apiKey, key } = await sendly.account.createApiKey('Production'); | ||
| * console.log(`Created key: ${key}`); // Full key - save this! | ||
| * console.log(`Key ID: ${apiKey.id}`); | ||
| * ``` | ||
| */ | ||
| createApiKey(name: string, options?: { | ||
| expiresAt?: string; | ||
| }): Promise<{ | ||
| apiKey: ApiKey; | ||
| key: string; | ||
| }>; | ||
| /** | ||
| * Revoke an API key | ||
| * | ||
| * @param id - API key ID to revoke | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * await sendly.account.revokeApiKey('key_xxx'); | ||
| * console.log('API key revoked'); | ||
| * ``` | ||
| */ | ||
| revokeApiKey(id: string): Promise<void>; | ||
| } | ||
@@ -1414,0 +1539,0 @@ |
+95
-0
@@ -989,2 +989,49 @@ "use strict"; | ||
| } | ||
| /** | ||
| * Preview a batch without sending (dry run) | ||
| * | ||
| * @param request - Batch request with array of messages | ||
| * @returns Preview showing what would happen if batch was sent | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * const preview = await sendly.messages.previewBatch({ | ||
| * messages: [ | ||
| * { to: '+15551234567', text: 'Hello User 1!' }, | ||
| * { to: '+15559876543', text: 'Hello User 2!' } | ||
| * ] | ||
| * }); | ||
| * | ||
| * console.log(preview.canSend); // true/false | ||
| * console.log(preview.creditsNeeded); // 2 | ||
| * console.log(preview.hasEnoughCredits); // true/false | ||
| * ``` | ||
| * | ||
| * @throws {ValidationError} If any message is invalid | ||
| */ | ||
| async previewBatch(request) { | ||
| if (!request.messages || !Array.isArray(request.messages) || request.messages.length === 0) { | ||
| throw new Error("messages must be a non-empty array"); | ||
| } | ||
| if (request.messages.length > 1e3) { | ||
| throw new Error("Maximum 1000 messages per batch"); | ||
| } | ||
| for (const msg of request.messages) { | ||
| validatePhoneNumber(msg.to); | ||
| validateMessageText(msg.text); | ||
| } | ||
| if (request.from) { | ||
| validateSenderId(request.from); | ||
| } | ||
| const preview = await this.http.request({ | ||
| method: "POST", | ||
| path: "/messages/batch/preview", | ||
| body: { | ||
| messages: request.messages, | ||
| ...request.from && { from: request.from }, | ||
| ...request.messageType && { messageType: request.messageType } | ||
| } | ||
| }); | ||
| return preview; | ||
| } | ||
| }; | ||
@@ -1429,2 +1476,50 @@ | ||
| } | ||
| /** | ||
| * Create a new API key | ||
| * | ||
| * @param name - Display name for the API key | ||
| * @param options - Optional settings | ||
| * @returns The created API key with the full key value (only shown once) | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * const { apiKey, key } = await sendly.account.createApiKey('Production'); | ||
| * console.log(`Created key: ${key}`); // Full key - save this! | ||
| * console.log(`Key ID: ${apiKey.id}`); | ||
| * ``` | ||
| */ | ||
| async createApiKey(name, options) { | ||
| if (!name) { | ||
| throw new Error("API key name is required"); | ||
| } | ||
| const response = await this.http.request({ | ||
| method: "POST", | ||
| path: "/account/keys", | ||
| body: { | ||
| name, | ||
| ...options?.expiresAt && { expiresAt: options.expiresAt } | ||
| } | ||
| }); | ||
| return response; | ||
| } | ||
| /** | ||
| * Revoke an API key | ||
| * | ||
| * @param id - API key ID to revoke | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * await sendly.account.revokeApiKey('key_xxx'); | ||
| * console.log('API key revoked'); | ||
| * ``` | ||
| */ | ||
| async revokeApiKey(id) { | ||
| if (!id) { | ||
| throw new Error("API key ID is required"); | ||
| } | ||
| await this.http.request({ | ||
| method: "DELETE", | ||
| path: `/account/keys/${encodeURIComponent(id)}` | ||
| }); | ||
| } | ||
| }; | ||
@@ -1431,0 +1526,0 @@ |
+95
-0
@@ -929,2 +929,49 @@ // src/errors.ts | ||
| } | ||
| /** | ||
| * Preview a batch without sending (dry run) | ||
| * | ||
| * @param request - Batch request with array of messages | ||
| * @returns Preview showing what would happen if batch was sent | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * const preview = await sendly.messages.previewBatch({ | ||
| * messages: [ | ||
| * { to: '+15551234567', text: 'Hello User 1!' }, | ||
| * { to: '+15559876543', text: 'Hello User 2!' } | ||
| * ] | ||
| * }); | ||
| * | ||
| * console.log(preview.canSend); // true/false | ||
| * console.log(preview.creditsNeeded); // 2 | ||
| * console.log(preview.hasEnoughCredits); // true/false | ||
| * ``` | ||
| * | ||
| * @throws {ValidationError} If any message is invalid | ||
| */ | ||
| async previewBatch(request) { | ||
| if (!request.messages || !Array.isArray(request.messages) || request.messages.length === 0) { | ||
| throw new Error("messages must be a non-empty array"); | ||
| } | ||
| if (request.messages.length > 1e3) { | ||
| throw new Error("Maximum 1000 messages per batch"); | ||
| } | ||
| for (const msg of request.messages) { | ||
| validatePhoneNumber(msg.to); | ||
| validateMessageText(msg.text); | ||
| } | ||
| if (request.from) { | ||
| validateSenderId(request.from); | ||
| } | ||
| const preview = await this.http.request({ | ||
| method: "POST", | ||
| path: "/messages/batch/preview", | ||
| body: { | ||
| messages: request.messages, | ||
| ...request.from && { from: request.from }, | ||
| ...request.messageType && { messageType: request.messageType } | ||
| } | ||
| }); | ||
| return preview; | ||
| } | ||
| }; | ||
@@ -1369,2 +1416,50 @@ | ||
| } | ||
| /** | ||
| * Create a new API key | ||
| * | ||
| * @param name - Display name for the API key | ||
| * @param options - Optional settings | ||
| * @returns The created API key with the full key value (only shown once) | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * const { apiKey, key } = await sendly.account.createApiKey('Production'); | ||
| * console.log(`Created key: ${key}`); // Full key - save this! | ||
| * console.log(`Key ID: ${apiKey.id}`); | ||
| * ``` | ||
| */ | ||
| async createApiKey(name, options) { | ||
| if (!name) { | ||
| throw new Error("API key name is required"); | ||
| } | ||
| const response = await this.http.request({ | ||
| method: "POST", | ||
| path: "/account/keys", | ||
| body: { | ||
| name, | ||
| ...options?.expiresAt && { expiresAt: options.expiresAt } | ||
| } | ||
| }); | ||
| return response; | ||
| } | ||
| /** | ||
| * Revoke an API key | ||
| * | ||
| * @param id - API key ID to revoke | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * await sendly.account.revokeApiKey('key_xxx'); | ||
| * console.log('API key revoked'); | ||
| * ``` | ||
| */ | ||
| async revokeApiKey(id) { | ||
| if (!id) { | ||
| throw new Error("API key ID is required"); | ||
| } | ||
| await this.http.request({ | ||
| method: "DELETE", | ||
| path: `/account/keys/${encodeURIComponent(id)}` | ||
| }); | ||
| } | ||
| }; | ||
@@ -1371,0 +1466,0 @@ |
+1
-1
| { | ||
| "name": "@sendly/node", | ||
| "version": "3.6.0", | ||
| "version": "3.8.0", | ||
| "description": "Official Sendly Node.js SDK for SMS messaging", | ||
@@ -5,0 +5,0 @@ "main": "./dist/index.js", |
+21
-0
@@ -171,2 +171,12 @@ # @sendly/node | ||
| const { data: batches } = await sendly.messages.listBatches(); | ||
| // Preview batch (dry run) - validates without sending | ||
| const preview = await sendly.messages.previewBatch({ | ||
| messages: [ | ||
| { to: '+15551234567', text: 'Hello User 1!' }, | ||
| { to: '+447700900123', text: 'Hello UK!' } | ||
| ] | ||
| }); | ||
| console.log(`Total credits needed: ${preview.totalCredits}`); | ||
| console.log(`Valid: ${preview.valid}, Invalid: ${preview.invalid}`); | ||
| ``` | ||
@@ -311,2 +321,13 @@ | ||
| console.log(`Credits used: ${usage.creditsUsed}`); | ||
| // Create a new API key | ||
| const newKey = await sendly.account.createApiKey({ | ||
| name: 'Production Key', | ||
| type: 'live', | ||
| scopes: ['sms:send', 'sms:read'] | ||
| }); | ||
| console.log(`New key: ${newKey.key}`); // Only shown once! | ||
| // Revoke an API key | ||
| await sendly.account.revokeApiKey('key_xxx'); | ||
| ``` | ||
@@ -313,0 +334,0 @@ |
227977
5.64%5637
5.92%608
3.58%