Frequently Asked Questions
Use the sendWhatsAppTextMessage function in the provided sinch.ts service file. This function utilizes the Sinch Conversation API to send text messages via WhatsApp. It requires the recipient's phone number in E.164 format and the message content as input. The function handles the interaction with the Sinch SDK and returns the Sinch message ID upon successful delivery.
The Sinch Conversation API is a unified messaging API that allows developers to integrate various messaging channels, including WhatsApp, into their applications. It simplifies the process of sending and receiving messages, managing contacts, and handling other communication tasks, providing a more streamlined experience than directly integrating with each messaging platform's API.
Fastify is a high-performance, low-overhead web framework for Node.js. Its speed and efficiency make it well-suited for handling real-time communication, like receiving webhook notifications from Sinch. It offers a robust routing system for managing incoming messages and a flexible plugin system for extensibility.
ngrok is primarily used during development to create a publicly accessible URL for your local Fastify server. This allows Sinch to send webhook notifications to your application even while it's running locally. Consider alternatives or paid tiers for production for more stable URLs.
Yes, the Sinch Conversation API supports various message types, including text messages, images, and interactive templates. The provided example focuses on text messages, but you can extend the sinch.ts service file to include functions for sending other message types using the appropriate Sinch SDK methods.
In your Sinch app dashboard, go to "Conversation API" -> "Webhook Settings". Enter your public URL (e.g., ngrok URL) followed by /webhooks/inbound for incoming messages and /webhooks/status for delivery reports. Select the relevant event types (MESSAGE_INBOUND, MESSAGE_DELIVERY) for each endpoint.
The waid: prefix is a specific identifier used by the Sinch Conversation API to denote WhatsApp contacts. It's followed by the recipient's phone number in E.164 format (e.g., waid:12223334444). It ensures that the message is routed correctly through the Sinch system to the intended WhatsApp user.
Webhook security is paramount. Use the verifySinchSignature function in the example code. This function compares the signature provided by Sinch in the x-sinch-signature header with your calculated signature using the raw request body, timestamp, and your Sinch "Application Secret." This prevents unauthorized requests.
The x-sinch-signature header contains a cryptographic signature generated by Sinch for each webhook request. This signature, along with the x-sinch-timestamp header, allows your application to verify the authenticity of the webhook and ensure it originated from Sinch, preventing malicious actors from sending fake requests.
The provided code includes a global error handler in server.ts to catch unhandled exceptions within routes. Specific error handling within the webhook route and the sendWhatsAppTextMessage function provides contextual error logging and responses. Always respond with a 200 OK to Sinch webhooks even if internal processing fails to prevent retries.
The Sinch webhook signature verification process typically uses the raw, unparsed request body as part of the signed data. Accessing this raw body is crucial for verifying the integrity of the request. The provided Fastify server setup includes instructions and examples to ensure request.rawBody is populated correctly for use in signature verification. This can be accomplished using middleware or adjusting content parser settings
SINCH_PROJECT_ID, SINCH_KEY_ID, SINCH_KEY_SECRET, SINCH_APP_ID, SINCH_APPLICATION_SECRET (for webhooks), and WHATSAPP_SENDER_ID (your provisioned number). These are loaded from the .env file in the provided example, keeping credentials secure.
The article recommends a modular structure. Create a dedicated service file (sinch.ts) to encapsulate interactions with the Sinch SDK. Define separate route handlers in Fastify (routes/webhooks.ts) to manage incoming webhooks and outgoing message requests. Use environment variables (.env) for configuration.
Send WhatsApp Messages with Sinch API in Node.js using Fastify
Build a production-ready WhatsApp messaging system using Sinch Conversation API with Fastify and Node.js. This comprehensive guide demonstrates how to integrate Sinch WhatsApp API with Fastify's high-performance framework to create a scalable messaging backend that handles two-way communication, webhook verification, and OAuth2 authentication.
By completing this tutorial, you'll deploy a fully functional Fastify application that sends and receives WhatsApp messages through Sinch's unified Conversation API, with production-grade security, error handling, and best practices for customer notifications, support, and marketing automation.
Project Overview and Goals
@sinch/sdk-coreNode.js SDK (official Sinch SDK supporting OAuth2 authentication). The SDK supports all current Sinch APIs including Conversation API. (npm: @sinch/sdk-core | GitHub: sinch-sdk-node, accessed October 2025).envfile.ngroktiers have limitations like session expiry and changing URLs; use paid tiers or alternatives likecloudflaredfor stable development URLs.ngrokglobally or make it available vianpx.System Architecture
1. Setting up Your Fastify WhatsApp Project
Initialize your Node.js project with Fastify and configure the Sinch SDK for WhatsApp integration.
Create Project Directory: Open your terminal and create a new directory for the project.
Initialize npm: Run
npm init -yto create yourpackage.jsonfile.Install Dependencies: Install Fastify, the Sinch SDK, and
dotenv.Install Development Dependencies (Optional but Recommended): Install TypeScript tooling for a better development experience.
Create Project Structure: Organize your files with this structure.
Configure
.gitignore: Create a.gitignorefile in the root directory to prevent committing sensitive information.Set up Environment Variables (
.env): Create a.envfile in the root directory. Populate this with credentials from the Sinch dashboard later..envkeeps sensitive credentials separate from code and makes configuration environment-specific. Never commit your.envfile to version control.(Optional) Configure
tsconfig.json(if using TypeScript): Create atsconfig.jsonfile in the root directory.(Optional) Add Run Scripts to
package.json:Choose the appropriate
devscript based on whether you're using JavaScript or TypeScript.2. Implementing Sinch WhatsApp Messaging Service
Create a dedicated service file to handle Sinch Conversation API interactions and WhatsApp message sending.
@sinch/sdk-corepackage uses OAuth2 authentication for the Conversation API, requiringprojectId,keyId, andkeySecret. This is the recommended authentication method for production applications. (Sinch SDK Core Documentation, accessed October 2025)waid:prefix: The Sinch Conversation API requires channel-specific prefixes for contact identifiers. For WhatsApp, usewaid:followed by the E.164 number. Consult the latest Sinch API documentation if you encounter issues.3. Building the Fastify API and WhatsApp Webhook Handler
Set up the Fastify server with webhook endpoints to receive incoming WhatsApp messages from Sinch.
Important: Sinch API payload structures (like
request.bodyformat in webhooks) can change. Always refer to the official Sinch Conversation API documentation for current details. Adjust the code examples based on your specific API version.Fastify Server Setup
Raw Body Access Implementation:
The code above uses Fastify's
addContentTypeParserwithparseAs: 'buffer'to capture the raw request body before JSON parsing. This approach is recommended for webhook signature verification in Fastify v5. The raw body is stored inrequest.rawBodyfor use in signature verification. (Fastify Content Type Parser Documentation, accessed October 2025)Alternative Approaches:
fastify-raw-bodyplugin for simpler setupWebhook Route Implementation
This route handles incoming POST requests from Sinch when a user sends a message to your WhatsApp number.
Webhook Security Implementation:
The signature verification implementation follows Sinch's webhook security specifications. Sinch signs webhook requests using HMAC-SHA256 with the following components:
rawBody + timestamp(concatenation)x-sinch-webhook-signature(Base64-encoded signature) andx-sinch-webhook-timestamp(ISO 8601 timestamp)The verification includes timestamp validation (5-minute window) to prevent replay attacks. (Sinch Conversation API Callbacks Documentation, accessed October 2025)
request.bodydepends on the Sinch event. Always consult the latest Sinch Conversation API documentation. Use TypeScript interfaces (likeSinchWebhookPayload) for type safety.200 OKquickly. Process asynchronously if needed./inboundvs/status: Logic forMESSAGE_DELIVERYevents is in the/statusendpoint./inboundfocuses onMESSAGE_INBOUND.4. Configuring Sinch WhatsApp API Credentials
Obtain Sinch Credentials:
.envfile. These credentials are used for OAuth2 authentication with the Conversation API.App ID.Application Secret. This is used for signature validation. Copy both into your.envfile.447537400000) without the+in your.envfile (WHATSAPP_SENDER_ID).Configure Webhooks in Sinch Dashboard:
ngrok.ngrokwill display a forwarding URL likehttps://<random-string>.ngrok-free.app. Copy this HTTPS URL. Free tier URLs change frequently..env: Paste the ngrok URL into theNGROK_URLvariable in your.envfile (optional, but helpful for reference).https://<random-string>.ngrok-free.app/webhooks/inboundhttps://<random-string>.ngrok-free.app/webhooks/statusMESSAGE_INBOUNDis selected for the Target URL. EnsureMESSAGE_DELIVERY(and potentially others likeMESSAGE_SUBMIT_FAILED,MESSAGE_REJECTED) are selected for the Delivery Report URL.SINCH_APPLICATION_SECRET. Make sure it matches what's in your.envfile.Review Environment Variables: Double-check your
.envfile ensures all values obtained from Sinch are correctly copied.5. Production-Ready Error Handling and Logging
Error Handling:
server.tsusingserver.setErrorHandler.try...catchblocks in specific functions (e.g.,sendWhatsAppTextMessage) for graceful handling of expected errors.403 Forbidden) or other request errors.Logging:
pinologger (logger: true) is excellent for production use. Pino is one of the fastest JSON loggers for Node.js.fastify.log.info(),fastify.log.warn(),fastify.log.error()contextually.Retry Mechanisms (for Outgoing Messages):
async-retry.sinch.ts):6. Testing Your Sinch WhatsApp Integration
Start Your Fastify Server:
Start ngrok (if not already running):
Configure Sinch Webhooks: Ensure your ngrok URL is correctly set in the Sinch dashboard webhook settings.
Send a Test Message:
/webhooks/inboundCheck Delivery Status:
/webhooks/statusendpoint logs for delivery reports from Sinch.Test Error Scenarios:
7. Deploying Your Fastify WhatsApp Application to Production
HTTPS Required: In production, your webhook endpoints must use HTTPS. Use a proper SSL/TLS certificate (Let's Encrypt, AWS Certificate Manager, etc.). Sinch will not send webhooks to insecure HTTP endpoints in production.
Environment Variables: Use environment-specific
.envfiles or a secrets manager (AWS Secrets Manager, HashiCorp Vault, Google Secret Manager) to manage credentials securely.Database Integration: Store message history, conversation state, and 24-hour window tracking in a database (PostgreSQL, MongoDB, MySQL). The 24-hour customer service window is critical for WhatsApp compliance – you can only send free-form messages within 24 hours of the last user message; outside this window, you must use approved template messages.
Rate Limiting: Implement rate limiting on your API endpoints using
@fastify/rate-limitto prevent abuse and comply with WhatsApp Business Platform messaging limits.Message Queue: For high-volume applications, use a message queue (Redis, RabbitMQ, AWS SQS) to handle webhook processing asynchronously and prevent blocking.
Monitoring and Alerting: Set up monitoring (Datadog, New Relic, Sentry) to track error rates, webhook failures, message delivery rates, and API latency.
Load Balancing: Deploy multiple Fastify instances behind a load balancer (Nginx, AWS ALB, Google Cloud Load Balancer) for high availability.
Webhook Retries: Sinch will retry failed webhook deliveries. Ensure your endpoint is idempotent – processing the same webhook multiple times should not cause duplicate actions. Use message IDs to track processed webhooks.
Template Messages: For conversations outside the 24-hour window, you must use pre-approved WhatsApp template messages. Register templates in your Sinch dashboard and use the Sinch SDK's template message sending methods.
Conclusion: Your Sinch WhatsApp API Integration is Ready
You've successfully built a production-ready WhatsApp messaging integration using Node.js, Fastify, and the Sinch Conversation API. Your Fastify application handles secure webhook signature verification using HMAC-SHA256, sends WhatsApp messages using OAuth2-authenticated API calls, processes incoming messages with proper error handling, and implements best practices for logging and retry logic.
The Sinch Conversation API provides a unified, modern interface for WhatsApp Business Platform communication with OAuth2 authentication and robust webhook security. Your Fastify application leverages high-performance request handling (47,001 req/sec) with minimal overhead, making it suitable for production-scale WhatsApp messaging.
As you scale your integration, consider implementing database storage for conversation history and 24-hour window tracking, message queueing with Redis or RabbitMQ for high-volume scenarios, rate limiting with
@fastify/rate-limit, monitoring with Sentry or Datadog, and proper HTTPS deployment with load balancing for high availability. Your WhatsApp integration is ready to power customer communications, notifications, and engagement at scale.Additional Resources