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 robust Node.js application using Fastify to send and receive WhatsApp messages via the Sinch Conversation API. This guide covers initial project setup, core messaging functionality, security, error handling, deployment, and verification.
By completing this tutorial, you'll deploy a functional application handling two-way WhatsApp communication with production-ready best practices. Use this integration to programmatically interact with customers on WhatsApp for notifications, support, marketing, and more.
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 January 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 the Project
Initialize your Node.js project with Fastify.
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. We will populate this with credentials obtained from the Sinch dashboard later..env? It keeps sensitive credentials separate from code and makes configuration environment-specific. Remember to 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 Core Functionality (Sinch Service)
Create a dedicated service file to handle Sinch SDK interactions.
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 API Layer (Fastify Server and Webhook Route)
Set up the Fastify server and webhook endpoint to receive incoming messages.
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
Webhook Route Implementation
This route will handle incoming POST requests from Sinch when a user sends a message to your WhatsApp number.
verifySinchSignaturefunction is critical. It prevents attackers from sending fake requests to your endpoint. It uses theApplication Secretfrom your Sinch App settings. Crucially, it now relies on accessing the raw request body (request.rawBody), which needs to be configured inserver.tsas noted in the comments there. Verify Sinch's exact signing method (raw body vs. stringified JSON) if issues arise.request.bodydepends on the Sinch event. Always consult the latest Sinch Conversation API documentation. Using TypeScript interfaces (likeSinchWebhookPayload) is recommended for type safety.200 OKquickly. Process asynchronously if needed./inboundvs/status: Logic forMESSAGE_DELIVERYevents is now only in the/statusendpoint to avoid redundancy./inboundfocuses onMESSAGE_INBOUND.4. Integrating with Sinch (Configuration and Setup)
Obtain Sinch Credentials:
.envfile.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. Remember that 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.Review Environment Variables: Double-check your
.envfile ensures all values obtained from Sinch are correctly copied.5. Implementing Error Handling, Logging, and Retries
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.fastify.log.info(),fastify.log.warn(),fastify.log.error()contextually.Retry Mechanisms (for Outgoing Messages):
async-retry.sinch.ts):