// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../../core/resource'; import * as TelegramAPI from './telegram'; import { Telegram, TelegramConnectParams, TelegramConnectResponse } from './telegram'; import * as WhatsappSyncAPI from './whatsapp-sync'; import { WhatsAppSyncContacts, WhatsAppSyncHistory, WhatsAppSyncStatus, WhatsappSync, WhatsappSyncRetrieveResponse, WhatsappSyncStartContactsSyncResponse, WhatsappSyncStartHistorySyncResponse, } from './whatsapp-sync'; import * as AgentAPI from './agent/agent'; import { Agent, AgentCreateParams, AgentExecution, AgentExecutionStatus, AgentProvider, AgentResource, AgentResponse, AgentStats, AgentUpdateParams, } from './agent/agent'; import { APIPromise } from '../../core/api-promise'; import { Cursor, type CursorParams, PagePromise } from '../../core/pagination'; import { buildHeaders } from '../../internal/headers'; import { RequestOptions } from '../../internal/request-options'; import { path } from '../../internal/utils/path'; export class Senders extends APIResource { agent: AgentAPI.AgentResource = new AgentAPI.AgentResource(this._client); whatsappSync: WhatsappSyncAPI.WhatsappSync = new WhatsappSyncAPI.WhatsappSync(this._client); telegram: TelegramAPI.Telegram = new TelegramAPI.Telegram(this._client); /** * Create sender * * @example * ```ts * const sender = await client.senders.create({ * name: 'name', * }); * ``` */ create(body: SenderCreateParams, options?: RequestOptions): APIPromise { return this._client.post('/v1/senders', { body, ...options }); } /** * Get sender * * @example * ```ts * const sender = await client.senders.retrieve('senderId'); * ``` */ retrieve(senderID: string, options?: RequestOptions): APIPromise { return this._client.get(path`/v1/senders/${senderID}`, options); } /** * Update sender * * @example * ```ts * const sender = await client.senders.update('senderId'); * ``` */ update(senderID: string, body: SenderUpdateParams, options?: RequestOptions): APIPromise { return this._client.patch(path`/v1/senders/${senderID}`, { body, ...options }); } /** * List senders * * @example * ```ts * // Automatically fetches more pages as needed. * for await (const sender of client.senders.list()) { * // ... * } * ``` */ list( query: SenderListParams | null | undefined = {}, options?: RequestOptions, ): PagePromise { return this._client.getAPIList('/v1/senders', Cursor, { query, ...options }); } /** * Delete sender * * @example * ```ts * await client.senders.delete('senderId'); * ``` */ delete(senderID: string, options?: RequestOptions): APIPromise { return this._client.delete(path`/v1/senders/${senderID}`, { ...options, headers: buildHeaders([{ Accept: '*/*' }, options?.headers]), }); } /** * Get the WhatsApp Business profile for a sender. The sender must have a WhatsApp * Business Account connected. * * @example * ```ts * const whatsappBusinessProfileResponse = * await client.senders.getProfile('senderId'); * ``` */ getProfile(senderID: string, options?: RequestOptions): APIPromise { return this._client.get(path`/v1/senders/${senderID}/profile`, options); } /** * Regenerate the webhook secret for a sender. The old secret will be invalidated * immediately. * * @example * ```ts * const webhookSecretResponse = * await client.senders.regenerateWebhookSecret('senderId'); * ``` */ regenerateWebhookSecret(senderID: string, options?: RequestOptions): APIPromise { return this._client.post(path`/v1/senders/${senderID}/webhook/secret`, options); } /** * Update the WhatsApp Business profile for a sender. The sender must have a * WhatsApp Business Account connected. * * @example * ```ts * const response = await client.senders.updateProfile( * 'senderId', * { * about: 'Succulent specialists!', * description: * 'We specialize in providing high-quality succulents.', * email: 'contact@example.com', * vertical: 'RETAIL', * websites: ['https://www.example.com'], * }, * ); * ``` */ updateProfile( senderID: string, body: SenderUpdateProfileParams, options?: RequestOptions, ): APIPromise { return this._client.patch(path`/v1/senders/${senderID}/profile`, { body, ...options }); } /** * Upload a new profile picture for the WhatsApp Business profile. The image will * be uploaded to Meta and set as the profile picture. * * @example * ```ts * const response = await client.senders.uploadProfilePicture( * 'senderId', * { * imageUrl: 'https://example.com/profile.jpg', * mimeType: 'image/jpeg', * }, * ); * ``` */ uploadProfilePicture( senderID: string, body: SenderUploadProfilePictureParams, options?: RequestOptions, ): APIPromise { return this._client.post(path`/v1/senders/${senderID}/profile/picture`, { body, ...options }); } } export type SendersCursor = Cursor; export interface Sender { id: string; name: string; /** * Phone number in E.164 format. */ phoneNumber: string; /** * Channels this sender can actually send on right now, computed from its * configuration. Empty means the sender cannot send or receive anything yet: a * phoneNumber alone does not enable SMS or voice. Check this rather than inferring * capability from phoneNumber or emailAddress. */ channels?: Array; createdAt?: string; /** * From-address for the email channel, if configured. */ emailAddress?: string; /** * Whether catch-all receiving is enabled. When true (and emailReceivingEnabled is * true), this sender receives email addressed to any local part at its domain, not * just its own address. The original recipient is delivered in the message.inbound * webhook's data.to. */ emailCatchAllEnabled?: boolean; /** * Whether inbound email receiving is enabled for this sender. */ emailReceivingEnabled?: boolean; /** * Whether this sender is the project's default. */ isDefault?: boolean; updatedAt?: string; /** * Webhook configuration for the sender. */ webhook?: SenderWebhook; /** * WhatsApp Business Account information. Only present if a WABA is connected. */ whatsapp?: Sender.Whatsapp; } export namespace Sender { /** * WhatsApp Business Account information. Only present if a WABA is connected. */ export interface Whatsapp { /** * Display phone number. */ displayPhoneNumber?: string; /** * Payment configuration status from Meta. */ paymentStatus?: Whatsapp.PaymentStatus; /** * WhatsApp phone number ID from Meta. */ phoneNumberId?: string; } export namespace Whatsapp { /** * Payment configuration status from Meta. */ export interface PaymentStatus { /** * Whether template messages can be sent. Requires setupStatus=COMPLETE and * methodStatus=VALID. */ canSendTemplates?: boolean; /** * Payment method status (VALID, NONE, etc.). */ methodStatus?: string; /** * Payment setup status (COMPLETE, NOT_STARTED, etc.). */ setupStatus?: string; } } } /** * Webhook configuration for the sender. */ export interface SenderWebhook { /** * Whether the webhook is active. */ active: boolean; /** * List of events the webhook is subscribed to. */ events: Array; /** * Which `X-Zavu-Signature` scheme this receiver is sent. * * - `v1`: `v1=HMAC_SHA256(secret, body)`. The scheme used before this was * configurable. Existing webhooks stay on it until you move them. * - `v2`: `v2=HMAC_SHA256(secret, "{t}.{body}")`. The current scheme, and the * default for new senders. It signs the timestamp together with the body. * - `v1+v2`: both signatures, sharing one `t`. The migration setting: a receiver * reading either one works, so you can deploy and confirm your new verifier * before switching over. * * Moving from `v1` straight to `v2` returns `400`. Set `v1+v2` first. See * https://docs.zavu.dev/guides/receiving-messages/signature-migration */ signatureVersion: 'v1' | 'v1+v2' | 'v2'; /** * HTTPS URL that will receive webhook events. */ url: string; /** * Webhook secret for signature verification. Only returned on create or * regenerate. */ secret?: string; } /** * Type of event that triggers the webhook. * * **Message lifecycle events:** * * - `message.queued`: Message created and queued for sending. `data.status` = * `queued` * - `message.sent`: Message accepted by the provider. `data.status` = `sent` * - `message.delivered`: Message delivered to recipient. `data.status` = * `delivered` * - `message.read`: Message was read by the recipient (WhatsApp only). * `data.status` = `read` * - `message.failed`: Message failed to send. `data.status` = `failed` * * **Inbound events:** * * - `message.inbound`: New message received from a contact. `data.conversationId` * is the inbox thread id (deep-link with * `https://dashboard.zavu.dev/{locale}/inbox?conv={conversationId}`); it is * `null` while the conversation row is still being created (the first message of * a brand-new thread, or several near-simultaneous first messages), where * `conversation.new` carries the id instead — `GET /v1/messages/{messageId}` * always has it. Reactions are delivered as `message.inbound` with * `messageType='reaction'`. When the contact replied to (quoted) an earlier * message, `data.content` carries the reply context: `replyToMessageId`, * `replyToProviderMessageId`, `replyToFrom`, `replyToText`, and * `replyToMessageType`. `data.providerTimestamp` is the provider's original * receive time in Unix milliseconds (the moment the channel received the message * from the contact — WhatsApp, Telegram, Instagram, Messenger; `null` for SMS * and email). Compare it against the top-level `timestamp` (when Zavu dispatched * the webhook) to detect and ignore delayed deliveries. When the conversation * was opened from a Click-to-WhatsApp ad or post, `data.referral` carries the ad * attribution — including `ctwaClid`, the identifier Meta's Conversions API * needs to credit a conversion back to that ad. WhatsApp only, and only on the * first message of the thread: it is absent from every later message, so persist * it when it arrives. * - `message.unsupported`: Received a message type that is not supported * * **Broadcast events:** * * - `broadcast.status_changed`: Broadcast status changed (pending_review, * approved, rejected, sending, completed, cancelled) * * **Other events:** * * - `conversation.new`: New conversation started with a contact. `data` carries * `conversationId` (the inbox thread id — deep-link with * `https://dashboard.zavu.dev/{locale}/inbox?conv={conversationId}`), the * `phoneNumber` or `email` key, `channel`, `firstMessageId`, `firstMessageText`, * and `profileName`. * - `template.status_changed`: WhatsApp template approval status changed * * **Partner events:** * * - `invitation.status_changed`: A partner invitation status changed (pending, * in_progress, completed, cancelled, failed). `data` carries `invitationId`, * `clientName`, `clientEmail`, `connectionType` (`whatsapp_waba` or * `messenger`), `previousStatus`, and `currentStatus`. On `completed` it also * carries `senderId` and `connectedAccount` (`channel`, `id`, `name`) — the * WhatsApp number or Facebook Page that was linked. On `failed` it carries * `failureReason`; the invitation link stays usable, so a client can retry it. * * **Voice Agent events:** For every voice event, `data` carries `callId`, * `direction`, `from`, `to`, `status`, `durationSeconds`, `endReason`, and * `transcriptAvailable`. The terminal events (`call.completed`, `call.failed`) * additionally carry `cost` — what the call was billed, in USD, combining * telephony and the managed voice pipeline — and `currency`. They are dispatched * after the call is charged, so `cost` is populated rather than zero; telephony * can still be settling on an outbound call, in which case * `GET /v1/calls/{callId}` holds the reconciled figure. * * - `call.initiated`: An outbound call was created and is dialing, or an inbound * call was received. `data.status` = `ringing` * - `call.answered`: The call was answered and the voice agent is connected. * `data.status` = `in_progress` * - `call.completed`: The call ended after a conversation. `data.status` = * `completed`; `durationSeconds` and `endReason` describe how it ended, and * `transcriptAvailable` indicates whether a transcript can be fetched. * - `call.failed`: The call could not be completed (busy, no answer, canceled, or * an error). `data.status` is the terminal status and `endReason` explains the * cause. * * **Custom domain events:** * * - `domain.verified`: A custom email domain passed verification (DKIM, and * SPF/DMARC/MAIL FROM if enhanced records are enabled) * - `domain.failed`: A custom email domain failed verification or is partially * verified */ export type WebhookEvent = | 'message.queued' | 'message.sent' | 'message.delivered' | 'message.read' | 'message.status' | 'message.failed' | 'message.inbound' | 'message.unsupported' | 'broadcast.status_changed' | 'conversation.new' | 'template.status_changed' | 'invitation.status_changed' | 'call.initiated' | 'call.answered' | 'call.completed' | 'call.failed' | 'domain.verified' | 'domain.failed'; export interface WebhookSecretResponse { /** * The new webhook secret. */ secret: string; } /** * WhatsApp Business profile information. */ export interface WhatsappBusinessProfile { /** * Short description of the business (max 139 characters). */ about?: string; /** * Physical address of the business (max 256 characters). */ address?: string; /** * Extended description of the business (max 512 characters). */ description?: string; /** * Business email address. */ email?: string; /** * URL of the business profile picture. */ profilePictureUrl?: string; /** * Business category for WhatsApp Business profile. */ vertical?: WhatsappBusinessProfileVertical; /** * Business website URLs (maximum 2). */ websites?: Array; } export interface WhatsappBusinessProfileResponse { /** * WhatsApp Business profile information. */ profile: WhatsappBusinessProfile; } /** * Business category for WhatsApp Business profile. */ export type WhatsappBusinessProfileVertical = | 'UNDEFINED' | 'OTHER' | 'AUTO' | 'BEAUTY' | 'APPAREL' | 'EDU' | 'ENTERTAIN' | 'EVENT_PLAN' | 'FINANCE' | 'GROCERY' | 'GOVT' | 'HOTEL' | 'HEALTH' | 'NONPROFIT' | 'PROF_SERVICES' | 'RETAIL' | 'TRAVEL' | 'RESTAURANT' | 'NOT_A_BIZ'; export interface SenderUpdateProfileResponse { /** * WhatsApp Business profile information. */ profile: WhatsappBusinessProfile; success: boolean; } export interface SenderUploadProfilePictureResponse { /** * WhatsApp Business profile information. */ profile: WhatsappBusinessProfile; success: boolean; } export interface SenderCreateParams { name: string; /** * From-address for the email channel (e.g. noreply@yourdomain.com). The address's * domain must be a verified email domain in your project. Setting this attaches * the email channel to the sender. */ emailAddress?: string; /** * ID of the verified email domain to attach. Optional — resolved from * `emailAddress`'s domain when omitted. */ emailDomainId?: string; /** * Display name shown in the recipient's inbox for the email channel. */ emailFromName?: string; /** * Enable inbound email receiving on this sender. Requires a verified MX record on * the domain; ignored otherwise. */ emailReceivingEnabled?: boolean; /** * Enable the one-way SMS channel (`sms_oneway`). Needs nothing else — no phone * number, no credential — so it is the fastest way to get a sender that can send. * Recipients cannot reply. Confirm with `sms_oneway` in the `channels` array on * the response. */ enableSmsOneway?: boolean; /** * Let this sender place and answer phone calls. Requires `phoneNumber`; enabling * it without one returns 400. Check the `channels` array on the response to * confirm `voice` is on. */ enableVoice?: boolean; /** * Phone number in E.164 format, and it must be a number your project already owns * (see `GET /v1/phone-numbers`). The number is routed to the sender as part of * this call, which is what turns the SMS channel on. Passing a number the project * does not own, or one already attached to another sender, returns 400 rather than * creating a sender that cannot send. Omit for an email-only sender. */ phoneNumber?: string; setAsDefault?: boolean; /** * Events to subscribe to. */ webhookEvents?: Array; /** * Which `X-Zavu-Signature` scheme this receiver is sent. * * - `v1`: `v1=HMAC_SHA256(secret, body)`. The scheme used before this was * configurable. Existing webhooks stay on it until you move them. * - `v2`: `v2=HMAC_SHA256(secret, "{t}.{body}")`. The current scheme, and the * default for new senders. It signs the timestamp together with the body. * - `v1+v2`: both signatures, sharing one `t`. The migration setting: a receiver * reading either one works, so you can deploy and confirm your new verifier * before switching over. * * Moving from `v1` straight to `v2` returns `400`. Set `v1+v2` first. See * https://docs.zavu.dev/guides/receiving-messages/signature-migration */ webhookSignatureVersion?: 'v1' | 'v1+v2' | 'v2'; /** * HTTPS URL for webhook events. */ webhookUrl?: string; } export interface SenderUpdateParams { /** * Attach or change the sender's email from-address (e.g. noreply@yourdomain.com). * The domain must be a verified email domain in your project. */ emailAddress?: string; /** * Enable or disable domain catch-all. When enabled (with emailReceivingEnabled * true), this sender receives email for any address at its domain. Ignored * (treated as false) if receiving is not enabled. */ emailCatchAllEnabled?: boolean; /** * ID of the verified email domain to attach. Optional — resolved from * `emailAddress`'s domain when omitted. */ emailDomainId?: string; /** * Display name shown in the recipient's inbox for the email channel. */ emailFromName?: string; /** * Enable or disable inbound email receiving for this sender. */ emailReceivingEnabled?: boolean; /** * Turn the one-way SMS channel on or off. Enabling needs nothing else and takes * effect immediately; disabling removes the channel from the sender. Confirm with * the `channels` array on the response. */ enableSmsOneway?: boolean; /** * Turn the voice channel on or off. The sender must already have a phone number * provisioned for calls; enabling it otherwise returns 400 instead of storing a * flag that changes nothing. Confirm with the `channels` array on the response. */ enableVoice?: boolean; name?: string; setAsDefault?: boolean; /** * Whether the webhook is active. */ webhookActive?: boolean; /** * Events to subscribe to. */ webhookEvents?: Array; /** * Which `X-Zavu-Signature` scheme this receiver is sent. * * - `v1`: `v1=HMAC_SHA256(secret, body)`. The scheme used before this was * configurable. Existing webhooks stay on it until you move them. * - `v2`: `v2=HMAC_SHA256(secret, "{t}.{body}")`. The current scheme, and the * default for new senders. It signs the timestamp together with the body. * - `v1+v2`: both signatures, sharing one `t`. The migration setting: a receiver * reading either one works, so you can deploy and confirm your new verifier * before switching over. * * Moving from `v1` straight to `v2` returns `400`. Set `v1+v2` first. See * https://docs.zavu.dev/guides/receiving-messages/signature-migration */ webhookSignatureVersion?: 'v1' | 'v1+v2' | 'v2'; /** * HTTPS URL for webhook events. Set to null to remove webhook. */ webhookUrl?: string | null; } export interface SenderListParams extends CursorParams {} export interface SenderUpdateProfileParams { /** * Short description of the business (max 139 characters). */ about?: string; /** * Physical address of the business (max 256 characters). */ address?: string; /** * Extended description of the business (max 512 characters). */ description?: string; /** * Business email address. */ email?: string; /** * Business category for WhatsApp Business profile. */ vertical?: WhatsappBusinessProfileVertical; /** * Business website URLs (maximum 2). */ websites?: Array; } export interface SenderUploadProfilePictureParams { /** * URL of the image to upload. */ imageUrl: string; /** * MIME type of the image. */ mimeType: 'image/jpeg' | 'image/png'; } Senders.AgentResource = AgentResource; Senders.WhatsappSync = WhatsappSync; Senders.Telegram = Telegram; export declare namespace Senders { export { type Sender as Sender, type SenderWebhook as SenderWebhook, type WebhookEvent as WebhookEvent, type WebhookSecretResponse as WebhookSecretResponse, type WhatsappBusinessProfile as WhatsappBusinessProfile, type WhatsappBusinessProfileResponse as WhatsappBusinessProfileResponse, type WhatsappBusinessProfileVertical as WhatsappBusinessProfileVertical, type SenderUpdateProfileResponse as SenderUpdateProfileResponse, type SenderUploadProfilePictureResponse as SenderUploadProfilePictureResponse, type SendersCursor as SendersCursor, type SenderCreateParams as SenderCreateParams, type SenderUpdateParams as SenderUpdateParams, type SenderListParams as SenderListParams, type SenderUpdateProfileParams as SenderUpdateProfileParams, type SenderUploadProfilePictureParams as SenderUploadProfilePictureParams, }; export { AgentResource as AgentResource, type Agent as Agent, type AgentExecution as AgentExecution, type AgentExecutionStatus as AgentExecutionStatus, type AgentProvider as AgentProvider, type AgentResponse as AgentResponse, type AgentStats as AgentStats, type AgentCreateParams as AgentCreateParams, type AgentUpdateParams as AgentUpdateParams, }; export { WhatsappSync as WhatsappSync, type WhatsAppSyncContacts as WhatsAppSyncContacts, type WhatsAppSyncHistory as WhatsAppSyncHistory, type WhatsAppSyncStatus as WhatsAppSyncStatus, type WhatsappSyncRetrieveResponse as WhatsappSyncRetrieveResponse, type WhatsappSyncStartContactsSyncResponse as WhatsappSyncStartContactsSyncResponse, type WhatsappSyncStartHistorySyncResponse as WhatsappSyncStartHistorySyncResponse, }; export { Telegram as Telegram, type TelegramConnectResponse as TelegramConnectResponse, type TelegramConnectParams as TelegramConnectParams, }; }