SDK JavaScript
Complete reference for the official @ixblix/sdk-js TypeScript package.
Covers every exported class, function, type and constant — with signatures, parameters,
return values and runnable examples.
npm install @ixblix/sdk-js — requires Node.js 18+. Ships ESM + CJS with full TypeScript declarations.
Table of contents
- IxblixClient — HTTP client
- Crypto helpers — E2EE
- Keypair persistence
- Webhook verification
- IxblixError
- Shared types
IxblixClient
Typed HTTP client for the ixblix REST API. One instance per scope — integrator or company.
Constructor
import { IxblixClient } from '@ixblix/sdk-js';
const client = new IxblixClient({
baseUrl: 'https://api.ixblix.app',
apiKey?: string, // X-API-Key header (company scope)
integratorId?: string, // HTTP Basic user (integrator scope)
integratorAccessToken?: string,
operatorKey?: OperatorKeyPair, // required to encrypt outgoing messages
fetch?: typeof fetch, // optional custom fetch
}); Integrator methods
/integrators/register HTTP Basic client.registerIntegrator({
name: string,
hostname: string,
callbackUrl: string,
force?: boolean,
subscriptionId?: string,
}): Promise<RegisterIntegratorResult>
// Three-way handshake: ixblix POSTs a challenge to callbackUrl,
// your endpoint echoes the registration payload, then echoes the credentials. /plans HTTP Basic client.listPlans(): Promise<Plan[]>
// Returns all active subscription plans (billingType, includedConversations,
// includedMessages, durationDays, priceCents, overagePriceCents). /payment/providers HTTP Basic client.listPaymentProviders(): Promise<PaymentProvidersResult>
// { providers: string[] } — e.g. ['asaas', 'stripe']. /companies/register HTTP Basic client.registerCompany({
name: string,
planId?: string,
confirmationWebhookUrl?: string,
email?: string,
taxId?: string,
}): Promise<RegisterCompanyResult>
// Returns { company, payment } where payment contains transactionId,
// checkoutUrl (for paid plans) and confirmationUrl. /companies/{id}/activate/{transactionId} HTTP Basic client.activateCompany(
companyId: string,
transactionId: string,
): Promise<ActivateCompanyResult>
// Returns { apiKey, status }. Store the apiKey in a secret manager. Company methods — profile & customization
/companies/profile X-API-Key client.getProfile(): Promise<CompanyProfile>
// { id, name, status, websiteUrl, customizations } /companies/balance X-API-Key client.getBalance(): Promise<CompanyBalance>
// { id, name, balanceCents, planId, planExpiresAt } /companies/customization X-API-Key client.updateCustomization({
brandName?: string,
logoUrl?: string,
rectangularLogoUrl?: string,
squareIconUrl?: string,
primaryColor?: string,
faviconUrl?: string,
websiteUrl?: string,
welcomeMessage?: string,
}): Promise<CompanyCustomization> /companies/branding X-API-Key client.uploadBranding({
squareIcon?: BrandingFile,
rectangularLogo?: BrandingFile,
}): Promise<CompanyCustomization>
// BrandingFile = { data: Uint8Array, fileName: string, mimeType: string }
// Multipart/form-data upload. Returns the updated customization. /companies/webhook X-API-Key client.updateWebhook({
webhookUrl?: string | null,
rotateSecret?: boolean,
}): Promise<{ webhookUrl: string | null; webhookSecret: string | null }>
// The secret is returned ONCE. Store it to verify webhook signatures. Company methods — encryption
/companies/encryption-key X-API-Key client.registerEncryptionKey({
keyId: string,
publicKey: string, // base64 SPKI DER
}): Promise<CompanyEncryptionKey>
// Rotates the active key. The previous key is retired but kept for
// decrypting existing conversations. /companies/encryption-key X-API-Key client.getEncryptionKey(): Promise<CompanyEncryptionKey>
// Returns the currently active company encryption key. Company methods — conversations
/conversations X-API-Key client.createConversation({
contact: {
externalId: string,
name?: string,
metadata?: Record<string, unknown>,
},
operator?: {
uuid?: string,
name?: string,
image?: string,
gravatarHash?: string,
},
}): Promise<CreateConversationResult>
// Returns { conversation, contact, deeplink, company, operator }.
// Share the deeplink with the customer on the original channel. /conversations/{conversationId}/operator X-API-Key client.updateOperator(
conversationId: string,
operator: OperatorInput,
): Promise<UpdateOperatorResult>
// OperatorInput = { uuid?, name?, image?, gravatarHash? }
// Pass null to clear a field. Can be called at any time. /conversations/{conversationId}/keys X-API-Key client.getConversationKeys(
conversationId: string,
): Promise<ConversationKeys>
// { conversationId, keyStatus, operatorPublicKey, operatorKeyId, customerPublicKey }
// keyStatus: 'AWAITING_OPERATOR' | 'AWAITING_CUSTOMER' | 'ACTIVE'
// Poll until keyStatus === 'ACTIVE' and customerPublicKey is set,
// or wait for the CUSTOMER_JOINED webhook. Company methods — messages
/messages/company X-API-Key // High-level: encrypt and send in one call (recommended)
// Handles text, media, or both with a single AES key
await client.sendEncryptedMessage(
conversationId: string,
options: {
content?: string, // plaintext (required for text, optional caption for media)
file?: { data: Uint8Array, fileName: string, mimeType: string },
operatorUuid: string,
replyToId?: string | null,
attachments?: { buttons?, vcard?, location?, linkPreview? },
operatorIdentity?: { uuid, name, image?, gravatarHash? },
},
): Promise<Message>
// Low-level: send pre-encrypted envelope
client.sendCompanyMessage(
conversationId: string,
envelope: MessageEnvelope,
contentType?: 'text' | 'react', // default 'text'
operatorUuid?: string,
replyToId?: string | null,
file?: MediaUpload, // optional: { data: Uint8Array, fileName, mimeType }
contentIv?: string, // caption IV (for media messages)
contentAuthTag?: string, // caption auth tag (for media messages)
): Promise<Message>
// sendEncryptedMessage fetches keys, encrypts all parts (content/file/attachments)
// with a single AES key using distinct IVs, and sends.
// sendCompanyMessage requires a pre-built envelope.
// When file is provided, the message is sent as media (multipart/form-data).
// The operator identity is embedded in the encrypted attachments JSON. /messages/{conversationId} X-API-Key client.listMessages(
conversationId: string,
): Promise<Message[]>
// Returns all messages (content is always ciphertext when encrypted).
// Each message includes replyTo (one level) and reactions. /messages/company X-API-Key client.reactToMessage(
conversationId: string,
messageId: string,
emoji: string, // pass '' to clear
operatorUuid?: string,
): Promise<Message>
// Encrypts the emoji and sends it as contentType='react' with replyToId.
// Requires operatorKey in the client constructor. /messages/company/delivered X-API-Key client.markMessageDeliveredByCompany(
conversationId: string,
messageId: string,
): Promise<{ messageId: string; deliveredAt: string }>
// Emits a 'message_delivered' Socket.io event to the customer.
// Call it as soon as your client receives the message. /messages/company/read X-API-Key client.markMessageReadByCompany(
conversationId: string,
messageId: string,
): Promise<{ messageId: string; readAt: string }>
// Emits a 'message_read' Socket.io event to the customer.
// Only call it when the window is focused and the message is in the viewport. Company methods — presence
/conversations/{conversationId}/presence X-API-Key client.reportCompanyPresence(
conversationId: string,
type: 'typing' | 'stopped' | 'recording',
): Promise<{ status: string }>
// Relays operator presence to the customer's chat app via Socket.io. Company methods — media
Media messages are sent using sendEncryptedMessage with the optional file parameter. The content field becomes the media caption. All parts (caption, file, attachments) share a single AES key with distinct IVs. The endpoint is the same as for text messages: POST /api/messages/company.
/messages/company X-API-Key // Send media with optional caption and attachments
await client.sendEncryptedMessage(conversationId, {
content: 'Here is your invoice', // optional caption
file: { data: fileBytes, fileName: 'invoice.pdf', mimeType: 'application/pdf' },
operatorIdentity: { uuid: 'agent-42', name: 'Maria Silva', gravatarHash: '...' },
attachments: { buttons: [...] }, // optional rich attachments
});
// All parts (caption, file, attachments) are encrypted with a single AES key
// using distinct IVs so the nonce is never reused. /media/{mediaId} X-API-Key client.getMedia(mediaId: string): Promise<Media>
// Returns metadata: { id, companyId, conversationId, messageId, mimeType,
// fileName, sizeBytes, iv, authTag, encryptedKey, selfEncryptedKey, keyId, createdAt } /media/{mediaId}/content X-API-Key client.downloadCompanyMedia(
mediaId: string,
): Promise<MediaDownload>
// Returns { data: Uint8Array, media: Media }.
// Decrypt with decryptMediaEnvelope. Company methods — payments & credits
/companies/credits/purchase X-API-Key client.purchaseCredits({
amountCents: number,
currency?: string,
provider: string,
metadata?: Record<string, unknown>,
}): Promise<PurchaseCreditsResult>
// Top up the company's prepaid balance. /companies/credits/purchases X-API-Key client.listCreditPurchases(): Promise<CreditPurchase[]>
// Returns all credit purchases with status: PENDING | COMPLETED | FAILED | REFUNDED. /companies/payment-methods X-API-Key client.listPaymentMethods(): Promise<PaymentMethod[]>
// Returns stored cards and Pix methods, default first.
// { id, provider, type, brand, last4, expMonth, expYear, holderName, isDefault, status } /companies/payment-change/options X-API-Key client.getPaymentChangeOptions(): Promise<PaymentChangeOptions>
// { card, pixAutomatic, pixAutomaticCycle, currentPlanExpiresAt,
// stillActive, currentPaymentMethodType } /companies/payment-change/start X-API-Key client.startPaymentChange({
planId?: string,
}): Promise<StartPaymentChangeResult>
// Returns { transactionId, provider, amountCents, currency,
// confirmationUrl, status, checkoutUrl }.
// Redirect the company owner to checkoutUrl. Company methods — original channel relay
/webhooks/original-channel X-API-Key client.relayOriginalChannelMessage({
conversationId: string,
content: string, // base64 ciphertext
iv: string,
authTag: string,
encryptedKey: string,
selfEncryptedKey: string,
keyId: string,
metadata?: Record<string, unknown>,
}): Promise<Message>
// Relay a message from WhatsApp/Instagram/etc. into ixblix.
// The message must be encrypted to the operator's public key. Crypto helpers
End-to-end encryption uses hybrid RSA-OAEP + AES-256-GCM. Each message gets a fresh AES key, wrapped to both the recipient and the sender (so you can read back your own messages).
generateOperatorKeyPair
import { generateOperatorKeyPair } from '@ixblix/sdk-js';
const keypair = generateOperatorKeyPair({
modulusLength?: 2048 | 4096, // default 2048
}): OperatorKeyPair
// Returns { keyId, publicKeySpki, privateKey }.
// The private key never leaves your process. importPublicKey
import { importPublicKey } from '@ixblix/sdk-js';
const key = importPublicKey(spkiBase64: string): KeyObject
// Import a base64 SPKI DER RSA public key (e.g. the customer's key). encryptToRecipient
import { encryptToRecipient } from '@ixblix/sdk-js';
const envelope = encryptToRecipient(
plaintext: string,
recipientPublicKeySpki: string,
senderKeyId: string,
senderPublicKeySpki: string,
): MessageEnvelope
// Returns { content, iv, authTag, encryptedKey, selfEncryptedKey, keyId }.
// All fields are base64url-encoded. decryptEnvelope
import { decryptEnvelope } from '@ixblix/sdk-js';
const plaintext = decryptEnvelope(
envelope: { content, iv?, authTag?, encryptedKey?, selfEncryptedKey? },
privateKey: KeyObject,
): string | null
// Tries encryptedKey first, then selfEncryptedKey.
// Returns null when decryption fails. encryptRichMessage
import { encryptRichMessage } from '@ixblix/sdk-js';
const result = encryptRichMessage(
content: string,
attachments: MessageAttachments | null, // typed object — stringified internally
recipientPublicKeySpki: string,
senderKeyId: string,
senderPublicKeySpki: string,
): {
content: string,
attachments: string | null, // encrypted blob
iv: string,
authTag: string,
encryptedKey: string,
selfEncryptedKey: string,
keyId: string,
}
// MessageAttachments = {
// operator?: { uuid?, name?, image?, gravatarHash? },
// buttons?: MessageButton[],
// vcard?: MessageVcard,
// location?: MessageLocation,
// linkPreview?: MessageLinkPreview,
// }
// Encrypts content and attachments with different IVs but the same AES key.
// The attachments blob embeds its own iv and authTag. decryptAttachments
import { decryptAttachments } from '@ixblix/sdk-js';
const json = decryptAttachments(
attachmentsBlob: string,
envelope: { encryptedKey?, selfEncryptedKey? },
privateKey: KeyObject,
): string | null
// Decrypts the attachments blob from a rich message.
// Returns the JSON string or null. encryptMediaToRecipient
import { encryptMediaToRecipient } from '@ixblix/sdk-js';
const envelope = encryptMediaToRecipient(
fileBytes: Uint8Array,
recipientPublicKeySpki: string,
senderKeyId: string,
senderPublicKeySpki: string,
): MessageEnvelope
// Encrypts binary media (image/audio/document).
// Returns the envelope fields; the ciphertext is in envelope.content. encryptMediaWithAttachments
import { encryptMediaWithAttachments } from '@ixblix/sdk-js';
const result = encryptMediaWithAttachments(
fileBytes: Uint8Array,
attachments: MessageAttachments, // typed object — stringified internally
recipientPublicKeySpki: string,
senderKeyId: string,
senderPublicKeySpki: string,
): {
content: string,
iv: string,
authTag: string,
encryptedKey: string,
selfEncryptedKey: string,
keyId: string,
encryptedAttachments: string,
}
// Use this when sending media + rich attachments.
// Both share the same AES key so the recipient can decrypt both. decryptMediaEnvelope
import { decryptMediaEnvelope } from '@ixblix/sdk-js';
const bytes = decryptMediaEnvelope(
envelope: { content, iv?, authTag?, encryptedKey?, selfEncryptedKey? },
privateKey: KeyObject,
): Uint8Array | null
// Decrypts a media file. Returns the plaintext bytes or null. Keypair persistence
loadOrCreateOperatorKey
import { loadOrCreateOperatorKey } from '@ixblix/sdk-js';
const keypair = loadOrCreateOperatorKey(directory: string): OperatorKeyPair
// Loads the keypair from disk, or generates and persists it on first run.
// Files: operator-private.pem (mode 0600), operator-public.spki, operator-key-id.
// For production, use a secret manager or KMS instead. Webhook verification
ixblix signs every webhook with HMAC-SHA256 using the company's webhook secret. Always verify the signature before acting on the event.
Constants
import {
WEBHOOK_SIGNATURE_HEADER, // 'X-Ixblix-Signature'
WEBHOOK_ID_HEADER, // 'X-Ixblix-Event-Id'
WEBHOOK_EVENT_HEADER, // 'X-Ixblix-Event'
WEBHOOK_COMPANY_ID_HEADER, // 'X-Ixblix-Company-Id'
} from '@ixblix/sdk-js'; verifyWebhook
import { verifyWebhook } from '@ixblix/sdk-js';
const { event, raw } = verifyWebhook(
body: unknown,
secret: string,
signature?: string,
): ParsedWebhook
// Computes HMAC-SHA256 of the raw body and compares it (constant-time)
// against the signature. Throws on mismatch.
// Returns the typed event (WebhookEvent union). parseWebhook
import { parseWebhook } from '@ixblix/sdk-js';
const { event, raw } = parseWebhook(body: unknown): ParsedWebhook
// Parses and validates the event type without checking the signature.
// Use only when you trust the source (e.g. internal relay). Webhook event types
| Event | Payload |
|---|---|
COMPANY_ACTIVATED | { companyId, transactionId, apiKey } |
CUSTOMER_JOINED | { companyId, conversationId, customerPublicKey } |
MESSAGE_RECEIVED | { companyId, conversationId, messageId, replyToId?, sentAt } |
MESSAGE_DELIVERED | { companyId, conversationId, messageId, deliveredAt } |
MESSAGE_READ | { companyId, conversationId, messageId, readAt } |
CONVERSATION_CLOSED | { companyId, conversationId } |
TYPING / STOPPED_TYPING / RECORDING / CHAT_CLOSED | { companyId, conversationId, type } |
BALANCE_LOW | { companyId, balanceCents } |
IxblixError
import { IxblixError } from '@ixblix/sdk-js';
class IxblixError extends Error {
readonly status: number; // HTTP status (0 if request never reached the API)
readonly code: string; // e.g. 'UNAUTHORIZED', 'NOT_FOUND'
readonly details?: Array<{ path: string; message: string }>;
}
// Thrown by every client method when the API returns a non-2xx response.
// Catch and inspect error.code for programmatic handling. Shared types
All types are exported from the package root. Key types:
Contact,ContactInput— customer identityConversation,ConversationKeys— thread stateMessage,MessageEnvelope,Media— encrypted contentOperator,OperatorInput— agent identityCompanyProfile,CompanyCustomization— white-labelPlan,CompanyBalance,CreditPurchase— billingPaymentMethod,PaymentChangeOptions— payment instrumentsWebhookEvent— union of all webhook payloads