btechworks-sdk
v2.1.2
Published
Official BTechWorks WhatsApp CRM SDK - Send messages, photos, videos, documents, templates, broadcasts, and wallet management via API
Downloads
810
Maintainers
Readme
BTechWorks SDK
Official BTechWorks WhatsApp CRM SDK for Node.js. Send messages, photos, videos, documents, templates, interactive buttons, lists, and broadcasts via the BTechWorks API. Create payment links using your own payment provider.
Installation
npm install btechworks-sdkQuick Start
import { BTechWorksClient } from 'btechworks-sdk';
const client = new BTechWorksClient({
apiKey: 'wk_your_api_key_here',
secretKey: 'ws_your_secret_key_here',
});
// Send a message
const result = await client.sendMessage({
phone: '+1234567890',
message: 'Hello from BTechWorks SDK!',
});
console.log(result);
// { success: true, message: 'Message sent successfully' }Configuration
const client = new BTechWorksClient({
apiKey: 'wk_...', // Required: Your API key
secretKey: 'ws_...', // Required: Your secret key
baseUrl: 'https://api.btechworks.io', // Optional: Custom API URL
timeout: 30000, // Optional: Request timeout in ms (default: 30000)
});API Methods
Messaging
// Send text message
await client.sendMessage({ phone: '+1234567890', message: 'Hello!' });
// Send photo
await client.sendPhoto({
phone: '+1234567890',
imageUrl: 'https://example.com/photo.jpg',
caption: 'Check this out!'
});
// Send video
await client.sendVideo({
phone: '+1234567890',
videoUrl: 'https://example.com/video.mp4',
caption: 'Watch this!'
});
// Send document
await client.sendDocument({
phone: '+1234567890',
documentUrl: 'https://example.com/file.pdf',
filename: 'invoice.pdf',
caption: 'Your invoice'
});
// Send CTA URL button
await client.sendCtcUrl({
phone: '+1234567890',
bodyText: 'Need help? Chat with us!',
displayText: 'Chat Now',
url: 'https://wa.me/919999999999?text=Hi',
footerText: 'We reply within 5 minutes',
});Interactive Buttons
Send reply buttons (max 3) that users can tap to respond:
// Simple string buttons (auto-generates IDs)
await client.sendInteractiveButtons({
phone: '+1234567890',
bodyText: 'Would you like to proceed with your order?',
buttons: ['Yes', 'No', 'Maybe'],
footerText: 'Tap a button to respond',
});
// Custom ID buttons
await client.sendInteractiveButtons({
phone: '+1234567890',
bodyText: 'Select your preferred delivery time:',
buttons: [
{ id: 'morning', title: '9 AM - 12 PM' },
{ id: 'afternoon', title: '12 PM - 4 PM' },
{ id: 'evening', title: '4 PM - 8 PM' },
],
footerText: 'Delivery charges may apply',
});
// Reply to a specific message
await client.sendInteractiveButtons({
phone: '+1234567890',
bodyText: 'Was your issue resolved?',
buttons: ['Yes, thanks!', 'No, need more help'],
contextMessageId: 'wamid.xxx', // Reply to this message
});Interactive List
Send a scrollable list with sections and items:
await client.sendInteractiveList({
phone: '+1234567890',
bodyText: 'Choose a service from our menu:',
buttonText: 'View Services',
sections: [
{
title: 'Development',
items: [
{ id: 'web', title: 'Web Development', description: 'Full stack web applications' },
{ id: 'mobile', title: 'Mobile App', description: 'iOS and Android apps' },
{ id: 'api', title: 'API Development', description: 'REST & GraphQL APIs' },
],
},
{
title: 'Design',
items: [
{ id: 'ui', title: 'UI/UX Design', description: 'Modern interface design' },
{ id: 'logo', title: 'Logo Design', description: 'Brand identity creation' },
],
},
],
});
// Simple list without descriptions
await client.sendInteractiveList({
phone: '+1234567890',
bodyText: 'Select your city:',
sections: [
{
title: 'Cities',
items: ['Mumbai', 'Delhi', 'Bangalore', 'Chennai'],
},
],
});List Interactive Messages
Query previously sent interactive messages:
// List all interactive messages
const messages = await client.listInteractiveMessages();
// {
// success: true,
// messages: [
// {
// _id: '...',
// phone: '+1234567890',
// contact_name: 'John',
// interactive_type: 'button',
// body_text: 'Would you like to proceed?',
// buttons: [{ id: 'yes', title: 'Yes' }, { id: 'no', title: 'No' }],
// status: 'sent',
// created_at: '2026-06-20T...'
// }
// ],
// total: 25,
// limit: 50,
// offset: 0
// }
// Filter by phone
await client.listInteractiveMessages({ phone: '+1234567890' });
// Filter by type
await client.listInteractiveMessages({ type: 'button' }); // or 'list'
// Pagination
await client.listInteractiveMessages({ limit: 10, offset: 0 });Flow Forms
Send WhatsApp Flow forms to collect structured data from users:
await client.sendFlowForm({
phone: '+1234567890',
flowId: '123456789',
bodyText: 'Please fill out this form:',
footerText: 'Your info is secure',
flowCta: 'Open Form',
flowAction: 'navigate',
flowActionPayload: { screen: 'FORM_SCREEN', data: {} },
});Templates
Smart Send (Recommended)
The easiest way to send templates - just pass variables and the backend handles everything automatically:
// Send any template with just variables
await client.sendSmart({
phone: '+1234567890',
template: 'order_confirmed',
variables: ['John', 'ORD-12345'],
});The backend automatically:
- Fetches template structure from DB
- Maps variables to body parameters
- Handles header variables (text/image/video/document)
- Handles copy_code buttons (OTP)
- Handles URL buttons with variable suffix (auto-extracts from full URL)
- Handles quick_reply buttons
- Checks 24h service window (sends as free text if open)
URL Buttons - Dynamic URLs
For URL buttons, pass full URL or just suffix - backend handles both:
// Option 1: Pass full URL (backend extracts suffix)
await client.sendSmart({
phone: '+1234567890',
template: 'payment_confirmation',
variables: { '1': 'GULAB', '2': '123456', '3': 'https://noornayaab.com/track' },
});
// Meta URL: https://noornayaab.com/track ✅
// Option 2: Pass just suffix
await client.sendSmart({
phone: '+1234567890',
template: 'payment_confirmation',
variables: { '1': 'GULAB', '2': '123456', '3': 'track' },
});
// Meta URL: https://noornayaab.com/track ✅Template URL should be: {{1}} (just variable, no base URL)
Send Template (Full Control)
// Array format
await client.sendTemplate({
phone: '+1234567890',
templateName: 'order_confirmed',
templateLanguage: 'en_US',
templateParams: ['John', 'ORD-12345'],
});
// Named object format
await client.sendTemplate({
phone: '+1234567890',
templateName: 'order_confirmed',
templateParams: { '1': 'John', '2': 'ORD-12345' },
});Check Template
See what variables a template needs before sending:
const check = await client.checkTemplate({ templateName: 'order_confirmed' });
// {
// success: true,
// exists: true,
// template: { name: 'order_confirmed', language: 'en_US', status: 'approved', ... },
// variables: [
// { name: 'var_1', example: 'John', required: true, index: 1 },
// { name: 'var_2', example: 'ORD-123', required: true, index: 2 }
// ],
// total_variables: 2,
// message: 'Template has 2 variable(s).'
// }List Templates
Get all templates for your account:
const templates = await client.listTemplates();
// {
// success: true,
// templates: [
// {
// name: 'order_confirmed',
// language: 'en_US',
// status: 'approved',
// category: 'utility',
// source: 'meta',
// header: { type: 'text', text: 'Order confirmed!' },
// body: 'Hi {{1}}, your order {{2}} is confirmed.',
// footer: 'Thank you',
// variables: [...],
// buttons: [{ type: 'url', text: 'View order' }]
// }
// ],
// total: 15
// }Template Types Supported
| Template Type | Example | Variables |
|---------------|---------|-----------|
| OTP/Auth | *{{1}}* is your verification code | templateParams: ['123456'] |
| Order | Hi {{1}}, order {{2}} confirmed | templateParams: ['John', 'ORD-123'] |
| Marketing | Hi {{1}}, get {{2}}% off | templateParams: ['User', '50'] |
| Header + Body | Header: Order #{{1}} + Body text | templateParams: ['ORD-123', 'John'] |
Button Types Auto-Handled
| Button Type | How It Works |
|-------------|-------------|
| copy_code (OTP) | Auto-injects first variable as OTP code |
| url with {{N}} | Auto-injects variable N as URL suffix |
| quick_reply | Auto-adds button component |
| phone_number | No params needed, auto-included |
| catalog | No params needed, auto-included |
Broadcast
// Send to specific phone numbers
const result = await client.broadcast({
name: 'Summer Sale',
templateName: 'summer_offer',
templateLanguage: 'en_US',
recipients: ['+1234567890', '+0987654321'],
templateVariables: ['User', '50% OFF'],
});
// { success: true, sent: 20, failed: 5, skipped: 2 }
// Send to contacts filtered by tags
await client.broadcast({
name: 'Premium Users',
templateName: 'vip_offer',
templateVariables: ['VIP User'],
audienceFilter: { tags: ['premium', 'vip'] },
});
// Broadcast from Excel/CSV file
const file = new File([readFileSync('contacts.xlsx')], 'contacts.xlsx', {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
});
await client.broadcastFromSheet({
name: 'Bulk Broadcast',
templateName: 'offer',
templateVariables: ['User'],
file,
});Payment Links (Your Own Provider)
Create payment links using your configured payment provider (Cashfree, Razorpay, or Paytm):
// Create a payment link
const link = await client.createPaymentLink({
amount: 999,
currency: 'INR',
customerName: 'John Doe',
customerEmail: '[email protected]',
customerPhone: '+919999999999',
description: 'Order #12345',
});
// {
// success: true,
// link_url: 'https://payments.cashfree.com/...',
// link_id: 'SDKLINK_1719000000_abc123',
// order_id: 'SDKLINK_1719000000_abc123',
// amount: 999,
// provider: 'cashfree',
// provider_name: 'My Cashfree Account'
// }
// Create with custom provider (if you have multiple)
const link = await client.createPaymentLink({
amount: 1500,
providerId: 'provider_id_here', // Use specific provider
description: 'Premium Plan Subscription',
returnUrl: 'https://yoursite.com/payment/success',
expiryMinutes: 30, // Link expires in 30 minutes
});
// Verify payment after customer pays
const verify = await client.verifyPayment({
orderId: 'SDKLINK_1719000000_abc123',
});
// {
// success: true,
// orderId: 'SDKLINK_1719000000_abc123',
// status: 'PAID',
// amount: 999,
// provider_name: 'My Cashfree Account',
// provider_type: 'cashfree'
// }
// For Razorpay, pass additional verification params
const verify = await client.verifyPayment({
orderId: 'order_Razorpay123',
razorpayOrderId: 'order_Razorpay123',
razorpayPaymentId: 'pay_xxx',
razorpaySignature: 'xxx',
});Wallet
// Check balance
const balance = await client.getBalance();
// { success: true, balance: 100, template_rate: 1, is_active: true }
// Estimate cost before sending
const estimate = await client.estimateCost(50);
// { success: true, balance: 100, can_send: 100, estimated_templates: 50, estimated_cost: 50 }
// Generate payment link
const link = await client.rechargeViaLink({
amount: 500,
email: '[email protected]',
phone: '+919999999999'
});
// { success: true, link_url: 'https://cashfree.com/pay/...', order_amount: 500 }
// Verify payment after redirect
const verify = await client.verifyOrder('wallet_1234567890_abc123');
// { success: true, status: 'PAID', balance: 500 }
// Get transaction history
const txns = await client.getTransactions(10, 0);
// { success: true, transactions: [...] }Analytics
const analytics = await client.getAnalytics();
// {
// success: true,
// analytics: {
// contacts: 1250,
// conversations: 890,
// messages: { today: 45, this_week: 312, this_month: 1250 },
// templates: 15,
// recent_broadcasts: [...]
// }
// }Response Format
All methods return a response object. No exceptions are thrown.
// Success
{ success: true, message: 'Message sent successfully' }
// Error
{ success: false, message: 'Invalid phone number format' }
// Template sent as text (24h window open - free!)
{ success: true, sent_as: 'text', message: 'Service window open - sent as free text message' }
// Template sent as template (paid)
{ success: true, sent_as: 'template', message: 'Template sent successfully' }
// Broadcast result
{ success: true, sent: 20, failed: 5, skipped: 2, refunded: 7 }24-Hour Service Window
When you send a template via sendTemplate() or sendSmart():
- Window OPEN (customer messaged within 24h): Template is sent as free text message - no balance deducted!
- Window CLOSED: Template is sent as paid template - balance deducted
This is automatic - you don't need to check the window yourself.
Error Handling
All methods return response objects with success: false on error. No try-catch needed:
const result = await client.sendMessage({ phone: 'invalid', message: 'Hello!' });
if (result.success) {
console.log('Sent!');
} else {
console.log('Failed:', result.message);
}Getting API Keys
- Login to your BTechWorks dashboard
- Go to Settings > API Key
- Click "Create API Key"
- Copy both the API Key and Secret Key (secret is shown only once)
TypeScript
Full TypeScript support with exported types:
import type {
BTechWorksConfig,
SendMessageOptions,
SendPhotoOptions,
SendVideoOptions,
SendDocumentOptions,
SendCtcUrlOptions,
SendInteractiveButtonsOptions,
SendInteractiveListOptions,
SendFlowFormOptions,
SendTemplateOptions,
SmartSendOptions,
BroadcastOptions,
CheckTemplateOptions,
CheckTemplateResponse,
ListTemplatesResponse,
TemplateListItem,
TemplateVariable,
InteractiveMessage,
ListInteractiveMessagesOptions,
ListInteractiveMessagesResponse,
CreatePaymentLinkOptions,
CreatePaymentLinkResponse,
VerifyPaymentOptions,
VerifyPaymentResponse,
ApiResponse,
SendTemplateResponse,
BroadcastResponse,
BroadcastSheetResponse,
WalletBalanceResponse,
EstimateCostResponse,
TransactionsResponse,
RechargeResponse,
RechargeViaLinkResponse,
VerifyOrderResponse,
AnalyticsResponse,
} from 'btechworks-sdk';All API Methods Reference
| Method | Parameters | Returns | Description |
|--------|-----------|---------|-------------|
| sendMessage | { phone, message } | ApiResponse | Send text message |
| sendPhoto | { phone, imageUrl, caption? } | ApiResponse | Send image |
| sendVideo | { phone, videoUrl, caption? } | ApiResponse | Send video |
| sendDocument | { phone, documentUrl, filename?, caption? } | ApiResponse | Send document |
| sendCtcUrl | { phone, bodyText, displayText, url, footerText? } | ApiResponse | Send CTA URL button |
| sendInteractiveButtons | { phone, bodyText, buttons, footerText?, contextMessageId? } | ApiResponse | Send reply buttons (max 3) |
| sendInteractiveList | { phone, bodyText, buttonText?, sections } | ApiResponse | Send interactive list |
| sendFlowForm | { phone, flowId, bodyText?, footerText?, flowCta?, flowAction?, flowActionPayload? } | ApiResponse | Send WhatsApp Flow form |
| listInteractiveMessages | { phone?, type?, limit?, offset? } | ListInteractiveMessagesResponse | List sent interactive messages |
| sendTemplate | { phone, templateName, templateLanguage?, templateParams? } | SendTemplateResponse | Send template (full control) |
| sendSmart | { phone, template, variables?, language? } | SendTemplateResponse | Send template (easy mode) |
| checkTemplate | { templateName, templateLanguage? } | CheckTemplateResponse | Check template variables |
| listTemplates | - | ListTemplatesResponse | List all templates |
| broadcast | { name, templateName, recipients?, audienceFilter?, ... } | BroadcastResponse | Broadcast to recipients |
| broadcastFromSheet | { name, templateName, file, ... } | BroadcastSheetResponse | Broadcast from Excel/CSV |
| createPaymentLink | { amount, currency?, customerName?, ... } | CreatePaymentLinkResponse | Create payment link (your provider) |
| verifyPayment | { orderId, providerId?, ... } | VerifyPaymentResponse | Verify payment (your provider) |
| getBalance | - | WalletBalanceResponse | Get wallet balance |
| estimateCost | count | EstimateCostResponse | Estimate sending cost |
| recharge | { amount, email?, phone? } | RechargeResponse | Create Cashfree order |
| rechargeViaLink | { amount, email?, phone? } | RechargeViaLinkResponse | Generate wallet payment link |
| verifyOrder | orderId | VerifyOrderResponse | Verify wallet payment |
| getTransactions | limit?, offset? | TransactionsResponse | Get transaction history |
| getAnalytics | - | AnalyticsResponse | Get account analytics |
Changelog
2.1.0
- NEW:
sendInteractiveButtons()- Send interactive reply buttons (max 3) via WhatsApp - NEW:
sendInteractiveList()- Send interactive list messages with sections and items - NEW:
listInteractiveMessages()- List and filter previously sent interactive messages - NEW:
createPaymentLink()- Create payment links using your own payment provider (Cashfree, Razorpay, Paytm) - NEW:
verifyPayment()- Verify payments via your own payment provider - NEW: Backend payment link support for Cashfree
/linksAPI, Razorpay/payment_links/createAPI, Paytm/payment/link/createAPI - NEW: Backend
POST /api/payments/create-linkandPOST /api/payments/verify-paymentendpoints - NEW: Full TypeScript types for all new methods
2.0.0
- BREAKING: Removed Instagram methods (
getInstagramPosts,getInstagramPostDetail,getInstagramReels) - NEW:
sendSmart()- one-liner template sending with automatic variable mapping - NEW:
listTemplates()- list all templates for your account - NEW: Backend auto-builds complete Meta API payload from template structure
- NEW: Automatic header variable support (text/image/video/document)
- NEW: Automatic copy_code button support (OTP templates)
- NEW: Automatic URL button suffix injection
- NEW: URL button auto-extracts suffix from full URL (pass
https://site.com/trackor justtrack) - NEW: Automatic quick_reply button support
- NEW: 24h service window detection - sends as free text when possible
- IMPROVED: Template params support both array
['val1', 'val2']and object{'1': 'val1'}formats - IMPROVED: Broadcast now uses smart template payload building
1.1.1
- Initial release with messaging, templates, broadcasts, wallet, analytics
License
MIT
