Complete API documentation for the Signal SDK classes and interfaces.
The core class for Signal messaging operations using JSON-RPC with signal-cli.
new SignalCli(accountOrPath?: string, account?: string, config?: SignalCliConfig)accountOrPath(optional): Phone number (e.g.,"+15551234567") OR path to thesignal-clibinary. The constructor uses smart detection - if it starts with+, it's treated as a phone number.account(optional): Phone number when the first argument is a path to the binary.config(optional): Advanced configuration object (see SignalCliConfig)
// Simple usage with phone number
const signal = new SignalCli("+15551234567");
// With custom signal-cli path
const signal = new SignalCli("/path/to/signal-cli", "+15551234567");
// With configuration
const signal = new SignalCli("+15551234567", undefined, {
maxRetries: 5,
retryDelay: 1000,
verbose: true,
});| Option | Type | Default | Description |
|---|---|---|---|
signalCliPath |
string |
auto-detected | Path to signal-cli binary |
maxRetries |
number |
3 |
Number of retry attempts on failure |
retryDelay |
number |
1000 |
Initial retry delay in milliseconds |
maxConcurrentRequests |
number |
10 |
Maximum parallel JSON-RPC requests |
minRequestInterval |
number |
100 |
Minimum delay between requests in ms |
requestTimeout |
number |
60000 |
Per-request timeout in milliseconds |
connectionTimeout |
number |
30000 |
Connection attempt timeout in milliseconds |
autoReconnect |
boolean |
true |
Automatically reconnect on disconnect |
verbose |
boolean |
false |
Enable debug logging |
logFile |
string |
undefined |
Write logs to a file path |
daemonMode |
'json-rpc' | 'unix-socket' | 'tcp' | 'http' |
'json-rpc' |
Connection mode |
socketPath |
string |
'/tmp/signal-cli.sock' |
Unix socket path (unix-socket mode) |
tcpHost |
string |
'localhost' |
TCP host (tcp mode) |
tcpPort |
number |
7583 |
TCP port (tcp mode) |
httpBaseUrl |
string |
'http://localhost:8080' |
Base URL (http mode) |
Establishes the JSON-RPC connection with the signal-cli daemon.
Parameters:
options(optional): Startup flags for the daemonignoreAttachments: Skip downloading attachmentsignoreStories: Ignore story messagesignoreAvatars: Skip downloading avatarsignoreStickers: Skip downloading sticker packssendReadReceipts: Auto-send read receiptsreceiveMode: When to start receiving ('on-start', 'on-connection', 'manual')
Example:
await signal.connect({
ignoreAttachments: true,
ignoreStories: true,
sendReadReceipts: true,
});Immediately terminates the connection.
Gracefully closes the connection, waiting for pending operations to complete.
Registers a new Signal account.
Parameters:
number: Phone number to register (E.164 format)voice: If true, verification is done via voice call instead of SMScaptcha: Captcha token (required if registration fails with captcha required)reregister: If true, register even if account is already registered
Verifies a new account with the code received via SMS/voice.
Links a new device to an existing Signal account with QR code support.
Parameters:
options.name: Device nameoptions.qrCodeOutput: 'console', 'file', or 'base64'options.qrCodePath: Path to save QR code (when qrCodeOutput is 'file')
Lists all linked devices for the account.
Updates a linked device's name.
Parameters:
options.deviceId: Device ID to update (number)options.deviceName: New name for the device (string)
Example:
const devices = await signal.listDevices();
await signal.updateDevice({
deviceId: 2,
deviceName: "Work Laptop",
});Removes a linked device.
sendMessage(recipient: string, message: string, options?: SendMessageOptions): Promise<SendResponse>
Sends a message to a recipient (user or group).
SendMessageOptions:
| Option | Type | Description |
|---|---|---|
attachments |
string[] |
File paths to attach |
mentions |
Mention[] |
Mentions in the message body |
textStyles |
TextStyle[] |
Text formatting (BOLD, ITALIC, SPOILER, STRIKETHROUGH, MONOSPACE) |
quote |
QuoteOptions |
Reply to an existing message |
expiresInSeconds |
number |
Message expiration timer |
isViewOnce |
boolean |
View-once message |
editTimestamp |
number |
Timestamp of the message to edit |
previewUrl |
string |
URL for link preview |
previewTitle |
string |
Title for link preview |
previewDescription |
string |
Description for link preview |
previewImage |
string |
Image path for link preview |
storyTimestamp |
number |
Timestamp of a story to reply to |
storyAuthor |
string |
Author of the story to reply to |
noteToSelf |
boolean |
Send to own account |
endSession |
boolean |
End the session |
noUrgent |
boolean |
Send without push notification (v0.14.0+) |
voiceNote |
boolean |
Mark attachments as voice notes (v0.14.2+) |
Examples:
// Send with text styling and mention
await signal.sendMessage("+1234567890", "Hello @John", {
textStyles: [{ start: 6, length: 5, style: "BOLD" }],
mentions: [{ start: 6, length: 5, number: "+1234567890" }],
});
// Reply to a message
await signal.sendMessage("+1234567890", "Great point!", {
quote: {
timestamp: 1705843200000,
author: "+1234567890",
text: "Original message text",
},
});
// Edit a previous message
await signal.sendMessage("+1234567890", "Corrected text", {
editTimestamp: 1705843200000,
});Receives pending messages with advanced filtering options.
Parameters:
options: Optional receive configurationtimeout: Maximum time to wait for messages in seconds (default: 5)maxMessages: Maximum number of messages to retrieveignoreAttachments: Skip downloading attachments (boolean)ignoreStories: Ignore story messages (boolean)ignoreAvatars: Skip downloading avatars (boolean, v0.14.0+)ignoreStickers: Skip downloading sticker packs (boolean, v0.14.0+)sendReadReceipts: Automatically send read receipts (boolean, default: true)
Returns: Array of received messages
Example:
// Receive with timeout
const messages = await signal.receive({ timeout: 10 });
// Receive without attachments (faster)
const messages = await signal.receive({
timeout: 5,
ignoreAttachments: true,
ignoreStories: true,
});sendReaction(recipient: string, targetAuthor: string, targetTimestamp: number, emoji: string, remove?: boolean, isStory?: boolean): Promise<SendResponse>
Sends a reaction to a specific message.
Sends a typing indicator to a recipient.
Remotely deletes a sent message.
Pins a message in a conversation or group.
PinMessageOptions:
targetAuthor: Author of the message to pin (required)targetTimestamp: Timestamp of the message to pin (required)groupId: Target group (mutually exclusive withrecipients)recipients: Target recipients for a direct pinnoteToSelf: Pin in your own conversationpinDuration: Duration in seconds,-1for forever (default)notifySelf: Send as normal message if self is a recipientstory: Pin a story instead of a normal message
Unpins a message.
UnpinMessageOptions:
targetAuthor: Author of the message to unpin (required)targetTimestamp: Timestamp of the message to unpin (required)groupId: Target grouprecipients: Target recipientsnoteToSelf: Unpin in your own conversationnotifySelf: Send as normal message if self is a recipient
Deletes a message for all group members (admin only).
AdminDeleteOptions:
groupId: Group ID (required)targetAuthor: Author of the message to delete (required)targetTimestamp: Timestamp of the message to delete (required)story: Delete a story instead of a regular messagenotifySelf: Send as normal message if self is a recipient
Creates a poll in a conversation.
PollCreateOptions:
question: The poll question (required)options: Array of poll options, 2-10 items (required)multiSelect: Allow multiple selections (default: true)recipients: Recipients for direct message poll (either this or groupId required)groupId: Group ID for group poll (either this or recipients required)
Example:
// Create a poll in a group
await signal.sendPollCreate({
question: "What's your favorite color?",
options: ["Red", "Blue", "Green", "Yellow"],
multiSelect: false,
groupId: "groupId==",
});
// Create a poll for individual recipients
await signal.sendPollCreate({
question: "Meeting time?",
options: ["9 AM", "12 PM", "3 PM"],
recipients: ["+1234567890", "+1987654321"],
});Votes on an existing poll.
Parameters:
recipient: Phone number or group ID where poll was sentoptions:pollAuthor: Phone number of the poll creator (required)pollTimestamp: Timestamp of the poll message (required)optionIndexes: Array of answer indices to vote for (required)voteCount: Optional vote count
Example:
await signal.sendPollVote("groupId==", {
pollAuthor: "+1234567890",
pollTimestamp: 1705843200000,
optionIndexes: [0, 2], // Vote for first and third options
});Terminates a poll, preventing further votes.
Parameters:
recipient: Phone number or group ID where poll was sentoptions:pollTimestamp: Timestamp of the poll message (required)
Example:
await signal.sendPollTerminate("groupId==", {
pollTimestamp: 1705843200000,
});Sends a MobileCoin payment notification.
PaymentNotificationData:
receipt: Base64 encoded receipt blob (required)note: Optional note for the payment
Sends a message to your own "Note to Self" conversation.
sendMessageWithProgress(recipient: string, message: string, options?: SendMessageOptions & { onProgress?: (progress: UploadProgress) => void }): Promise<SendResponse>
Sends a message with progress tracking for large attachments.
Note: The progress callback currently provides simulated progress for UX purposes, as JSON-RPC does not provide real-time upload progress feedback.
Creates a new Signal group.
Returns: GroupInfo with groupId, name, members, etc.
Updates a group's settings and members.
GroupUpdateOptions:
name: New group namedescription: New group descriptionavatar: Path to avatar imageaddMembers: Array of members to addremoveMembers: Array of members to removepromoteAdmins: Array of members to promote to admindemoteAdmins: Array of members to demote from adminbanMembers: Array of members to banunbanMembers: Array of members to unbanpermissionAddMember: 'EVERY_MEMBER' or 'ONLY_ADMINS'permissionEditDetails: 'EVERY_MEMBER' or 'ONLY_ADMINS'permissionSendMessage: 'EVERY_MEMBER' or 'ONLY_ADMINS'expirationTimer: Message expiration timer in secondsresetInviteLink: Reset the group invite linklinkState: 'enabled', 'enabled-with-approval', or 'disabled'
Example:
await signal.updateGroup("groupId==", {
name: "Updated Group Name",
description: "New description",
addMembers: ["+1234567890"],
promoteAdmins: ["+1234567890"],
});Lists all groups.
Lists all groups with detailed information including permissions, member roles, and invite links.
Returns: Array of detailed group information:
groupId: Group identifiername: Group namedescription: Group descriptionmembers: Array of member objectspendingMembers: Members pending approvalrequestingMembers: Members requesting to joinbannedMembers: Banned member listinviteLink: Group invite linkgroupPermissions: Permission settingsisAdmin: Whether current user is adminisMember: Whether current user is member
Example:
const groups = await signal.listGroupsDetailed();
groups.forEach((group) => {
console.log(`${group.name}: ${group.members.length} members`);
if (group.isAdmin) console.log(" (You are admin)");
});Lists and parses groups with enhanced details.
Leaves a group.
Parameters:
groupId: The group ID to quitoptions.delete: If true, delete local group data after quittingoptions.admins: Array of members to promote as admins before quitting (required if you're the only admin)
Joins a group via an invitation link.
Sends the group's invite link to a recipient.
Resets the group's invite link.
Sets the banned members list for a group.
Lists all contacts.
Options:
detailed: Include more detailed informationblocked: Filter by blocked status (true/false)allRecipients: Include all known recipients, not only contactsname: Find contacts with the given namerecipients: Specify phone numbers to filterinternal: Include internal information
Returns all contacts with enriched profile information (givenName, familyName, username, mobileCoinAddress).
Updates a contact's information.
ContactUpdateOptions:
givenName: First namefamilyName: Last namenickGivenName: Nickname (first name)nickFamilyName: Nickname (last name)note: Contact notecolor: Contact colorexpiration: Message expiration timer
Removes a contact from the contact list.
RemoveContactOptions:
hide: Hide the contact but keep encryption dataforget: Completely remove all contact data
Exports and sends contact data to sync with linked devices.
Blocks one or more contacts or a group.
Unblocks one or more contacts or a group.
Checks registration status on Signal.
Returns: Array of status results with number, isRegistered, uuid, username
Lists known identities and their trust levels.
Parameters:
number: Optional phone number to filter identities
Manually marks an identity as trusted by verifying its safety number.
Parameters:
number: Phone number of the contactverifiedSafetyNumber: The 60-digit safety number to verify
Retrieves the 60-digit safety number for a contact.
Returns: The safety number string or null if not found.
Verifies a safety number and marks the identity as trusted if it matches.
Returns: true if verification succeeded, false otherwise.
Lists all identities that are not currently trusted.
Unregisters the Signal account from the server. This deletes the account on the Signal server but keeps local data.
Deletes all local data associated with the account.
Updates account-wide configuration settings.
AccountConfiguration:
readReceipts: Enable read receiptsunidentifiedDeliveryIndicators: Show unidentified delivery indicatorstypingIndicators: Enable typing indicatorslinkPreviews: Enable link previews
Sets a registration lock PIN for the account.
Removes the registration lock PIN.
updateProfile(givenName: string, about?: string, aboutEmoji?: string, avatar?: string, options?: { familyName?: string; mobileCoinAddress?: string; removeAvatar?: boolean }): Promise<void>
Updates the account profile.
Parameters:
givenName: First name (required)about: About/bio textaboutEmoji: Emoji for the about textavatar: Path to avatar imageoptions.familyName: Last nameoptions.mobileCoinAddress: MobileCoin address for paymentsoptions.removeAvatar: Remove the current avatar
Example:
await signal.updateProfile("John", "Software developer", "💻", "./avatar.jpg", {
familyName: "Doe",
});Updates account settings.
UpdateAccountOptions:
deviceName: New device nameusername: Username to setdeleteUsername: Remove current usernameunrestrictedUnidentifiedSender: Enable unrestricted unidentified senderdiscoverableByNumber: Enable discoverability by phone numbernumberSharing: Enable number sharing
Returns: AccountUpdateResult with success, username, usernameLink
Sets a Signal username.
Deletes the Signal username.
Lists all local account phone numbers.
Lists accounts with name and UUID.
Starts the process of changing your account to a new phone number.
Parameters:
newNumber: The new phone number in E164 format (e.g.,"+33612345678")voice: Use voice verification instead of SMS (default:false)captcha: Optional captcha token if required
Completes the phone number change process.
Sends a MobileCoin payment notification.
PaymentNotificationData:
receipt: Base64 encoded receipt blob (required)note: Optional note for the payment
Lists installed sticker packs.
Adds a sticker pack by ID and key.
Uploads a custom sticker pack.
StickerPackManifest:
path: Path to manifest.json or zip file (required)title: Sticker pack titleauthor: Sticker pack authorcover: Cover sticker informationstickers: Array of sticker definitions
Returns: StickerPackUploadResult with packId, packKey, installUrl
Retrieves a sticker. Returns the path to the saved file.
GetStickerOptions:
packId: Sticker pack ID (hex encoded)stickerId: Sticker index in the pack
Submits a rate limit challenge to lift the limitation.
Returns: RateLimitChallengeResult with success, retryAfter, message
Retrieves an attachment by ID. Returns the path to the saved file.
GetAttachmentOptions:
id: Attachment ID (required)recipient: Recipient who sent the attachmentgroupId: Group ID where attachment was sent
Retrieves a contact's or group's avatar. Returns the path to the saved file.
GetAvatarOptions:
contact: Contact number for contact avatarprofile: Profile number for profile avatargroupId: Group ID for group avatar
Sends a synchronization request to other linked devices.
Responds to a message request from a non-contact.
MessageRequestResponseType: 'ACCEPT' | 'DELETE' | 'BLOCK' | 'BLOCK_AND_DELETE'
Retrieves the version of the underlying signal-cli.
Helper method to check if a phone number is registered on Signal.
The SignalCli class extends EventEmitter and emits the following events:
Emitted when a new message is received.
signal.on("message", (envelope) => {
console.log("From:", envelope.source);
console.log("Message:", envelope.dataMessage?.message);
});Emitted when a reaction is received.
signal.on("reaction", (reaction) => {
console.log("Reaction:", reaction.emoji);
console.log("From:", reaction.sender);
console.log("Target:", reaction.targetTimestamp);
});Emitted when a delivery/read receipt is received.
signal.on("receipt", (receipt) => {
console.log("Receipt type:", receipt.type); // 'read', 'viewed', or 'delivered'
console.log("From:", receipt.sender);
});Emitted when a typing indicator is received.
signal.on("typing", (typing) => {
console.log("Typing from:", typing.sender);
console.log("Action:", typing.action); // 'start' or 'stop'
});Emitted when a story is received.
signal.on("story", (story) => {
console.log("Story from:", story.sender);
});Emitted when a message is pinned or unpinned.
signal.on("pin", (pinEvent) => {
console.log("Pin event from:", pinEvent.sender);
console.log("Pinned timestamps:", pinEvent.pinnedMessageTimestamps);
});Emitted when a call is received or changes state.
signal.on("call", (callEvent) => {
console.log("Call from:", callEvent.sender);
console.log("Call ID:", callEvent.callId);
console.log("State:", callEvent.state);
});Emitted when an error occurs.
signal.on("error", (error) => {
console.error("Error:", error.message);
});Emitted when the connection is closed.
signal.on("close", (code) => {
console.log("Connection closed with code:", code);
});A high-level class for creating interactive Signal bots.
new SignalBot(config: BotConfig, signalCliPath?: string)config:BotConfigobject for the bot.signalCliPath(optional): Path to thesignal-clibinary.
| Option | Type | Required | Description |
|---|---|---|---|
phoneNumber |
string |
Yes | The bot's phone number |
admins |
string[] |
Yes | List of administrator phone numbers |
group |
object |
No | Group configuration |
group.name |
string |
Yes (if group) | Group name |
group.description |
string |
No | Group description |
group.createIfNotExists |
boolean |
No | Auto-create group if it doesn't exist |
group.initialMembers |
string[] |
No | Initial group members |
group.avatar |
string |
No | Path to group avatar image |
settings |
object |
No | Bot settings |
settings.commandPrefix |
string |
No | Command prefix (default: "/") |
settings.autoReact |
boolean |
No | Auto-react to messages |
settings.logMessages |
boolean |
No | Log incoming messages |
settings.welcomeNewMembers |
boolean |
No | Welcome new group members |
settings.cooldownSeconds |
number |
No | Command cooldown per user |
settings.maxMessageLength |
number |
No | Maximum message length |
Adds a custom command to the bot.
BotCommand:
name: Command name (required)description: Command description (required)adminOnly: Restrict to admins only (optional)handler: Async function to handle the command (required)
Handler signature:
handler: (message: ParsedMessage, args: string[], bot: SignalBot) => Promise<string | null | void>Example:
bot.addCommand({
name: "hello",
description: "Say hello",
handler: async (message, args) => {
const name = args.join(" ") || "World";
return `Hello ${name}!`;
},
});Removes a command from the bot.
Retrieves all available commands.
Starts the bot, connects to signal-cli, and sets up event handlers.
Stops the bot and disconnects from signal-cli.
Gracefully shuts down the bot.
Sends a text message.
sendReaction(recipient: string, targetAuthor: string, targetTimestamp: number, emoji: string): Promise<void>
Sends a reaction to a message.
sendMessageWithAttachment(recipient: string, message: string, attachments: string[], cleanup?: string[]): Promise<void>
Sends a message with attachments.
sendMessageWithImage(recipient: string, message: string, imageUrl: string, prefix?: string): Promise<void>
Downloads an image from a URL and sends it as an attachment.
Downloads an image from a URL to a temporary file. Returns the path to the temporary file.
Checks if a phone number is in the bot's admin list.
Retrieves the ID of the group managed by the bot.
Returns the underlying SignalCli instance for advanced operations.
Retrieves bot statistics including messages received and commands executed.
BotStats:
messagesReceived: Number of messages receivedcommandsExecuted: Number of commands executedstartTime: Bot start timestamplastActivity: Last activity timestampactiveUsers: Number of active users
The SignalBot class emits several events:
ready: Emitted when the bot is started and ready.stopped: Emitted when the bot is stopped.message: Emitted upon receiving a new message.command: Emitted when a command is executed.error: Emitted when an error occurs.daemon-closed: Emitted when the Signal daemon closes.
Manages multiple Signal accounts simultaneously with automatic event routing.
new MultiAccountManager(options?: MultiAccountOptions)MultiAccountOptions:
signalCliPath: Path to signal-cli executabledataPath: Data directory for all accountsverbose: Enable verbose loggingautoReconnect: Auto-reconnect on failure
Adds a Signal account to the manager.
Parameters:
account: Phone number for the accountconfig: Optional Signal CLI configuration overrides
Returns: SignalCli instance for the account
Removes an account from the manager and disconnects it.
Gets a specific account instance.
Returns all managed account phone numbers.
Checks if an account is managed.
Connects a specific account.
Disconnects a specific account.
Connects all accounts simultaneously.
Disconnects all accounts.
Sends a message from a specific account.
Retrieves status information for all accounts or a specific one.
Gracefully shuts down the manager and all managed accounts.
The MultiAccountManager extends EventEmitter and forwards all Signal events with account context:
message:(account: string, envelope: any) => voidreceipt:(account: string, receipt: any) => voidtyping:(account: string, typing: any) => voidreaction:(account: string, reaction: any) => voiderror:(account: string, error: any) => voidaccountAdded:(account: string) => voidaccountRemoved:(account: string) => voidaccountConnected:(account: string) => voidaccountDisconnected:(account: string) => void
Example:
// Listen to messages from specific account
manager.on("message", (account, envelope) => {
console.log(`${account} received:`, envelope.dataMessage?.message);
});
// Listen to account connection events
manager.on("accountConnected", (account) => {
console.log("Account connected:", account);
});The SDK uses a comprehensive set of TypeScript interfaces for type safety. These are defined in src/interfaces.ts and include types for messages, contacts, groups, attachments, and more.
interface Mention {
start: number; // Start position in message
length: number; // Length of mention
number: string; // Phone number of mentioned user
}interface TextStyle {
start: number; // Start position in message
length: number; // Length of styled text
style: 'BOLD' | 'ITALIC' | 'STRIKETHROUGH' | 'MONOSPACE' | 'SPOILER';
}interface QuoteOptions {
timestamp: number;
author: string;
text?: string;
attachments?: Attachment[];
mentions?: Mention[];
textStyles?: TextStyle[];
}interface Contact {
number: string;
name: string;
uuid?: string;
blocked: boolean;
givenName?: string;
familyName?: string;
username?: string;
mobileCoinAddress?: string;
// ... more fields
}interface GroupInfo {
groupId: string;
name: string;
description?: string;
members: string[];
pendingMembers?: string[];
bannedMembers?: string[];
admins?: string[];
isAdmin?: boolean;
isMember?: boolean;
inviteLink?: string;
// ... more fields
}For complete interface definitions, see the source code in src/interfaces.ts.