Frequently Asked Questions
Integrate Sinch WhatsApp with NestJS by setting up a new NestJS project, installing necessary dependencies like @nestjs/config
, axios
, and class-validator
, configuring environment variables for Sinch credentials, and structuring the project into modules for Sinch API interaction, webhook handling, and optional database integration.
The Sinch Conversation API is a unified platform provided by Sinch that allows developers to manage conversations across various channels, including WhatsApp. It simplifies the process of sending and receiving messages, managing contacts, and handling other communication aspects.
NestJS provides a robust and scalable framework for building server-side applications. Its modular architecture, dependency injection, and TypeScript support make it well-suited for complex integrations like WhatsApp messaging through the Sinch API.
MongoDB is optional but recommended if you need to persist message history or other data related to your WhatsApp interactions. Use it when you require data storage and retrieval capabilities beyond the immediate request-response cycle.
Create a Sinch service in your NestJS project to handle API calls. Use axios
to send HTTP requests to the Sinch API endpoint for sending WhatsApp messages. Ensure you have the recipient's phone number and the message text content.
The webhook secret is a crucial security measure to verify the authenticity of incoming webhook requests from Sinch. It ensures that the requests originated from Sinch and haven't been tampered with.
Secure your webhook endpoint by verifying the signature of incoming requests using the shared webhook secret. Implement a guard or middleware that calculates the signature from the request body and compares it with the signature provided in the x-sinch-signature
header.
You'll need Node.js, npm or yarn, the NestJS CLI, a Sinch account with Conversation API access, a registered and approved WhatsApp Business Sender, a publicly accessible HTTPS URL for webhooks, and a basic understanding of NestJS concepts.
Your Sinch API token and Service Plan ID are found in your Sinch Customer Dashboard under APIs > API Credentials. Ensure these are kept secure and not exposed in your codebase.
Sinch sends webhook notifications to your specified endpoint for incoming WhatsApp messages. Create a webhook controller in your NestJS app to receive these notifications and process the message data accordingly. Verify the signature of the webhook requests for security.
The body-parser
middleware, specifically bodyParser.raw()
, is crucial for accessing the raw request body of incoming webhooks. This raw body is required for webhook signature verification to ensure the message integrity and security.
Your application interacts with your NestJS backend, which communicates with the Sinch platform using the Conversation API. Sinch then sends the messages to WhatsApp users, and incoming messages flow back through webhooks to your NestJS backend.
Docker is optional but recommended for containerizing your NestJS application and Sinch integration for consistent deployment across different environments.
Create DTOs for sending messages (recipient's number, message content) and receiving webhook payloads. These DTOs enhance code clarity and provide validation for incoming data. For webhooks, DTOs should handle various event types via validation and nested properties.
The Sinch webhook signature is verified using a SHA256 HMAC with your webhook secret and a concatenation of the timestamp and raw request body. This is compared to the received signature in the x-sinch-signature header to ensure message integrity.
Integrate Sinch WhatsApp API with Node.js & NestJS
Build a NestJS backend service that sends WhatsApp messages via the Sinch Conversation API and receives incoming messages through webhooks. This step-by-step guide walks you through the complete integration process.
Leverage NestJS's robust framework to build scalable applications that communicate with customers on the world's most popular messaging platform.
Technologies Used:
System Architecture:
(Note: This ASCII diagram illustrates the flow. For final documentation_ consider generating a visual diagram using tools like MermaidJS or other diagramming software.)
Prerequisites:
npm install -g @nestjs/cli
).1. Project Setup and Configuration
Initialize your NestJS project and set up the basic structure and environment configuration.
1.1. Create NestJS Project:
Open your terminal and run:
Choose your preferred package manager (npm or yarn).
1.2. Install Dependencies:
Install modules for HTTP requests_ configuration management_ data validation_ and handling raw request bodies for webhooks. Optionally_ add Mongoose for database interaction.
@nestjs/config
: Manages environment variables.axios
: A promise-based HTTP client for making requests to the Sinch API. (Alternatively_ use NestJS's built-inHttpModule
).class-validator
&class-transformer
: For validating incoming webhook payloads and API request bodies.body-parser
&@types/body-parser
: Required for accessing the raw request body_ necessary for webhook signature verification.@nestjs/mongoose
&mongoose
: For MongoDB integration (if storing messages).1.3. Environment Variables:
Store sensitive credentials outside your codebase using a
.env
file – a security best practice.Create a
.env
file in the project root:How to Obtain Sinch Credentials:
SINCH_WHATSAPP_SENDER_ID
. This must be the exact, approved number in E.164 format (including+
and country code, e.g., +12345678900).SINCH_WEBHOOK_SECRET
(use a password manager or online generator). Provide this exact same secret to Sinch when configuring the webhook later. Treat this like a password.Note on E.164 Format: All phone numbers used with Sinch Conversation API must be in E.164 format:
+[country code][number]
with no spaces, dashes, or parentheses. For example, a US number: +14155551234. This international standard ensures proper routing across global telecommunications networks.1.4. Configure Environment Module:
Load the
.env
file into the application using@nestjs/config
.Modify
src/app.module.ts
:1.5. Project Structure:
Organize your code into modules for better separation of concerns.
Create these folders (
sinch
,webhook
,config
, etc.) within thesrc
directory.2. Implementing Core Functionality: Sending Messages
Create a service to interact with the Sinch Conversation API for sending WhatsApp messages.
2.1. Create Sinch Module and Service:
Generate the module and service using the NestJS CLI:
2.2. Define Sinch Configuration (Optional but Recommended):
Create a typed configuration file for Sinch settings.
Inject this configuration into your
SinchService
.2.3. Implement
SinchService
:This service contains the logic to call the Sinch API.
2.4. Update
SinchModule
:Register the service and the configuration.
2.5. Import
SinchModule
intoAppModule
:3. Building the API Layer (Example: Sending a Message)
Expose an endpoint to trigger sending a message.
3.1. Create DTOs for Sending Messages and Responses:
Define the expected request body structure and validation rules. Also, define a basic DTO for the Sinch API response.
3.2. Create a Controller (e.g., add to
AppController
or create a dedicatedMessageController
):Explanation:
SinchService
is injected.POST /send-whatsapp
is defined.@UsePipes(new ValidationPipe(...))
validates the request body againstSendMessageDto
.forbidNonWhitelisted: true
rejects requests with extra fields.sinchService.sendWhatsAppTextMessage
.202 Accepted
with themessageId
on success.AxiosError
to provide more context from Sinch API failures, and throws appropriateHttpException
instances which NestJS handles.3.3. Testing the Endpoint:
Run your NestJS application:
Use
curl
or Postman. Usingcurl
(note the use of single quotes around the JSON data for shell safety):Expected Response (Success – Status Code 202):
Expected Response (Validation Error – Status Code 400):
Expected Response (Sinch API Error – Status Code e.g., 400, 401, 503):
The response will reflect the
HttpException
thrown in the controller, e.g.:4. Integrating Third-Party Services: Handling Incoming Webhooks
Sinch notifies your application about incoming messages or status updates via webhooks. Create an endpoint to receive and process these notifications securely.
4.1. Configure Webhook in Sinch Dashboard:
https://your-public-domain.com/webhook/sinch
or your ngrok URL likehttps://<your-id>.ngrok.io/webhook/sinch
). This URL MUST use HTTPS..env
file (SINCH_WEBHOOK_SECRET
). This is used for signature verification. Ensure there are no typos or extra spaces.MESSAGE_INBOUND
,MESSAGE_DELIVERY
). Start withMESSAGE_INBOUND
.Screenshot Example (Conceptual – Actual UI may vary):
4.2. Create Webhook Module_ Controller_ and Service:
4.3. Enable Raw Body Parsing (Via Middleware):
Webhook signature verification requires the raw_ unparsed request body. Apply
body-parser
's raw body middleware specifically to the webhook route. This is configured in theWebhookModule
(see section 4.4).Modify
src/main.ts
to ensure global pipes or other global body parsers don't interfere_ although selective middleware is preferred:4.4. Create Webhook Verification Guard & Configure Middleware:
This guard checks the
x-sinch-signature
header.Middleware Configuration (Important!): Apply the raw body parser middleware in
WebhookModule
.Modify
src/webhook/webhook.module.ts
:Import
WebhookModule
intoAppModule
:4.5. Define DTO for Incoming Webhooks:
Map the structure of Sinch's webhook payloads. This DTO handles multiple event types using the
trigger
field. Note: The original provided DTO was incomplete; this version provides a more structured example forMESSAGE_INBOUND
.Frequently Asked Questions
How do I authenticate with the Sinch Conversation API in NestJS?
Authenticate using Bearer token authentication. Store your
SINCH_API_TOKEN
in your.env
file and include it in theAuthorization
header asBearer YOUR_TOKEN
for all API requests. The Sinch API Token is available in your Sinch Dashboard under APIs > API Credentials. Use@nestjs/config
to inject the token securely into your services and create an axios instance with the Authorization header configured globally.What phone number format does Sinch require for WhatsApp messaging?
Sinch requires E.164 format for all phone numbers:
+[country code][number]
with no spaces, dashes, or parentheses. For example, a US number would be+14155551234
, not(415) 555-1234
or415-555-1234
. This international standard ensures proper routing across global telecommunications networks. Use the@IsPhoneNumber()
validator fromclass-validator
in your DTOs to enforce this format.How do I verify webhook signatures from Sinch?
Sinch uses HMAC-SHA256 signature verification with Base64 encoding. Extract the
x-sinch-signature
header (format:t=<timestamp>,<base64_signature>
) andx-sinch-timestamp
header. Construct the signed payload as<timestamp>.<raw_request_body_utf8>
, compute HMAC-SHA256 using your webhook secret, encode as Base64, and compare usingcrypto.timingSafeEqual()
to prevent timing attacks. Applybody-parser.raw()
middleware specifically to webhook routes to preserve the raw body. See official documentation at https://developers.sinch.com/docs/conversation/keyconcepts/#callback-signature-verification.How do I set up NestJS modules for Sinch integration?
Create separate modules for concerns: a
SinchModule
for API interaction (services for sending messages), aWebhookModule
for receiving callbacks (controller with guards for signature verification), and optionally aDatabaseModule
for persisting message history. Use@nestjs/config
withConfigModule.forFeature()
to inject typed configuration into each module. ExportSinchService
fromSinchModule
so other modules can inject it, particularly theWebhookGuard
for signature verification.What is the WhatsApp message length limit through Sinch?
WhatsApp Business API allows up to 4,096 characters per text message through Sinch Conversation API. Use
@MaxLength(4096)
validator in yourSendMessageDto
to enforce this limit. Messages exceeding this length will be rejected by the API. For longer content, consider breaking it into multiple messages or using media attachments. Template messages may have different character limits depending on the template configuration.How do I handle errors from the Sinch API in NestJS?
Wrap Sinch API calls in try-catch blocks and check for
AxiosError
instances to extract detailed error information. Accesserror.response.status
for HTTP status codes anderror.response.data
for Sinch-specific error details. Throw appropriateHttpException
instances with meaningful messages (e.g.,BadRequestException
,UnauthorizedException
,BadGatewayException
). Log detailed errors internally using NestJS Logger but return generic messages to clients to avoid exposing sensitive information.Can I test Sinch webhooks locally during development?
Yes, use ngrok to create a secure tunnel to your local development server. Install ngrok (
npm install -g ngrok
), runngrok http 3000
(or your port), and use the generated HTTPS URL (e.g.,https://abc123.ngrok.io/webhook/sinch
) in your Sinch Dashboard webhook configuration. Ensure you configure the same webhook secret in both your.env
file and Sinch Dashboard. ngrok provides a web interface athttp://localhost:4040
to inspect webhook payloads, which is invaluable for debugging.What environment variables are required for production deployment?
For production, configure these required environment variables:
SINCH_SERVICE_PLAN_ID
,SINCH_API_TOKEN
,SINCH_PROJECT_ID
,SINCH_WHATSAPP_SENDER_ID
(E.164 format), andSINCH_WEBHOOK_SECRET
. Never commit.env
files to version control. Use your hosting provider's environment variable configuration (e.g., AWS Systems Manager, Heroku Config Vars, Vercel Environment Variables). Ensure theapiUrl
in your Sinch config matches your account's region (us or eu). Verify all credentials are correctly loaded on startup using validation in your service constructor.