npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

btechworks-sdk

v2.1.2

Published

Official BTechWorks WhatsApp CRM SDK - Send messages, photos, videos, documents, templates, broadcasts, and wallet management via API

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-sdk

Quick 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

  1. Login to your BTechWorks dashboard
  2. Go to Settings > API Key
  3. Click "Create API Key"
  4. 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 /links API, Razorpay /payment_links/create API, Paytm /payment/link/create API
  • NEW: Backend POST /api/payments/create-link and POST /api/payments/verify-payment endpoints
  • 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/track or just track)
  • 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