Frequently Asked Questions
Use the '/send' POST endpoint with a JSON body containing the recipient's number ('to') in E.164 format (e.g., +14155552671) and the message text ('text'). This endpoint leverages the Infobip API to deliver the message, simplifying WhatsApp integration within your Fastify app.
Infobip is a CPaaS (Communication Platform as a Service) that provides the necessary infrastructure and API for sending and receiving WhatsApp messages programmatically. The project uses Infobip's Node.js SDK to interact with their API, abstracting away the complexities of the WhatsApp Business API.
Fastify is a high-performance Node.js web framework known for its speed and developer-friendly features like built-in logging and validation. Its efficiency makes it well-suited for handling real-time messaging traffic and building scalable WhatsApp applications.
Ngrok is useful during local development to create a publicly accessible URL for receiving Infobip webhooks. In production, you'll need a properly deployed server with a public domain or IP and HTTPS.
Yes, besides text messages, Infobip supports various message types like images, documents, templates, and interactive buttons. Refer to the Infobip WhatsApp API documentation for details on structuring the payload for each type and adapting the webhook handler to process them.
Set up a '/infobip-webhook' POST route in your Fastify app. Configure this URL as a webhook in your Infobip account settings, and Infobip will forward incoming WhatsApp messages to this endpoint. Add security measures like secret verification to protect your webhook.
You'll need Node.js v14 or later, an active Infobip account (a free trial is sufficient for testing), your Infobip API Key and Base URL, a registered WhatsApp sender in your Infobip account, and a public URL for receiving webhooks.
Store your Infobip API key as an environment variable in a '.env' file, and add this file to your '.gitignore' to prevent it from being committed to version control. For production, consider using more secure secret management solutions.
A suggested schema includes fields for message ID, direction, sender/recipient numbers, message body, status, timestamps, and Infobip-specific status details (stored as JSON). Use indexing for optimal querying by numbers or status.
Validating the 'to' field ensures that only correctly formatted numbers (E.164 format) are sent to the Infobip API, minimizing errors and unnecessary API calls.
Implement try...catch blocks around API calls to handle network errors or issues returned by Infobip. Log errors with relevant context and return informative error messages to the client with appropriate HTTP status codes.
The webhook secret is used to verify that incoming requests to your '/infobip-webhook' endpoint are actually coming from Infobip. This adds a basic security layer to prevent unauthorized access. While a secret is helpful, prioritize signature verification if Infobip offers it.
Use the 'fastify-rate-limit' plugin to control the rate of incoming requests, protecting your application from abuse. Configure the maximum number of requests allowed within a specified time window. This is especially important for the /send endpoint.
Leverage Fastify's inherent performance, ensure asynchronous operations are non-blocking, optimize database interactions, and keep request/response payloads concise. For high-throughput, conduct load testing to identify potential bottlenecks.
Implement a '/health' endpoint that returns the application's status. Integrate logging and metrics collection using tools like Pino and Prometheus, and set up error tracking with services like Sentry or Bugsnag.
This guide provides a step-by-step walkthrough for building a Node.js application using the Fastify framework to send and receive WhatsApp messages via the Infobip API. We will cover everything from initial project setup to handling webhooks, error management, and basic deployment considerations.
By the end of this tutorial, you will have a functional Fastify application capable of sending WhatsApp text messages and receiving incoming messages through Infobip's webhook service. This solves the common need for businesses to programmatically interact with customers on WhatsApp for notifications, support, or engagement, leveraging the speed of Fastify and the robust infrastructure of Infobip.
Project Overview and Goals
Goal: Create a Node.js application using Fastify to send outbound WhatsApp messages and process inbound messages via Infobip.
Problem Solved: Enables programmatic WhatsApp communication without directly managing the complexities of the WhatsApp Business API infrastructure. Provides a foundation for building chatbots, notification systems, or integrating WhatsApp into existing business workflows.
Technologies:
.env
file for secure configuration management.Architecture:
Prerequisites:
ngrok
are useful for local development, but for production, you'll need a deployed server with a public IP or domain name.Outcome: A running Fastify server with two primary endpoints:
POST /send
: Accepts a request to send a WhatsApp message.POST /infobip-webhook
: Listens for incoming WhatsApp messages forwarded by Infobip.1. Setting up the project
Let's initialize our Node.js project and install the necessary dependencies.
Create Project Directory: Open your terminal and create a new directory for your project, then navigate into it:
Initialize Node.js Project: Run
npm init
and follow the prompts. You can accept the defaults for most options.This creates a
package.json
file.Install Dependencies: We need Fastify for the web server, the Infobip Node.js SDK to interact with their API, and
dotenv
to manage our API credentials securely.Create Project Structure: Set up a basic directory structure for clarity:
src/server.js
: Will contain our main application code..env
: Stores sensitive information like API keys (will be ignored by Git)..gitignore
: Specifies files and directories that Git should ignore.Configure
.gitignore
: Addnode_modules
and.env
to your.gitignore
file to prevent committing dependencies and secrets:Set up Environment Variables: Open the
.env
file and add your Infobip credentials and the phone number associated with your Infobip WhatsApp sender. You'll also define the port for your server.Purpose:
INFOBIP_API_KEY
: Your secret API key for authenticating requests with Infobip.INFOBIP_BASE_URL
: The specific API endpoint domain provided by Infobip for your account (the full URL).INFOBIP_WHATSAPP_SENDER
: The registered phone number (including country code) used to send messages via Infobip.PORT
: The local port your Fastify server will listen on.WEBHOOK_SECRET
: A secret string you define, used to verify incoming webhooks (basic security).How to Obtain Infobip Values:
Developers
section orAPI Keys
(exact location might vary slightly).INFOBIP_API_KEY
).INFOBIP_BASE_URL
) is usually displayed prominently on the API Keys page or homepage after login. Copy the complete Base URL provided (e.g.,xyz123.api.infobip.com
).INFOBIP_WHATSAPP_SENDER
) is the number you registered with Infobip for sending WhatsApp messages. Find this under theChannels and Numbers
->WhatsApp
section.Important: Replace the placeholder values with your actual credentials. Never commit your
.env
file to version control.2. Implementing core functionality: Sending Messages
Now, let's write the code to initialize Fastify and the Infobip client, and create an endpoint to send messages.
Load Environment Variables and Initialize Clients: Open
src/server.js
. We'll start by loadingdotenv
, importing dependencies, and setting up Fastify and the Infobip client.dotenv.config()
first? It ensures environment variables are loaded before any other code tries to access them.Fastify({ logger: true })
? Enables detailed logging of requests, responses, and errors, crucial for development and debugging.AuthType.ApiKey
? Explicitly tells the SDK which authentication method to use, matching the Infobip standard.try...catch
aroundnew Infobip()
? Handles potential errors during client initialization (e.g., invalid base URL format).host: '0.0.0.0'
? Makes the server accessible from outside its container or local machine (important for Docker or receiving webhooks).Create the Send Message Route: Add the following route definition inside
src/server.js
before thestart()
function call.async (request, reply)
? The route handler needs to beasync
because sending the message (infobipClient.channels.whatsapp.send
) is an asynchronous operation (it returns a Promise).messagePayload
structure? This follows the structure required by the Infobip SDK'ssend
method for text messages, as documented here.try...catch
? Essential for handling potential network errors or API errors returned by Infobip during the send operation.errorMessage
,errorCode
) helps diagnose problems quickly. We try to extract the error message from Infobip's response structure if available.3. Building the API Layer
The
/send
route created above forms the basic API layer for sending messages.Authentication/Authorization: For this simple example, there's no built-in user authentication. In a production scenario, you would add authentication middleware (e.g., using JWT with
fastify-jwt
or API keys) to protect this endpoint.Request Validation: We implemented basic validation for
to
andtext
. For more complex scenarios, Fastify's schema validation is highly recommended for robustness:API Endpoint Documentation:
POST /send
Testing with
curl
: Replace placeholders with your actual running server address, recipient number (must be your own number if using a free trial Infobip account), and desired message.4. Integrating with Infobip (Receiving Messages - Webhooks)
To receive incoming WhatsApp messages, Infobip needs a publicly accessible URL (a webhook) to send the message data to.
Create the Webhook Route: Add this route definition to
src/server.js
, before thestart()
function.incomingData.results
Array? Infobip often sends webhook events in batches within theresults
array.reply.code(200).send()
Quickly? Webhook providers expect a fast acknowledgment (typically within a few seconds). Perform complex processing asynchronously (e.g., using message queues or background jobs) if needed, but respond to the webhook request promptly.Configure Webhook in Infobip:
ngrok
to expose your local server to the internet.ngrok
will provide a public HTTPS URL (e.g.,https://<unique-id>.ngrok.io
). Use this URL. For production, you must use your deployed server's actual public domain/IP address and ensure it's configured for HTTPS.Channels and Numbers
->WhatsApp
.Forward messages to URL
or similar).https://<your-public-url>/infobip-webhook
X-Webhook-Secret
with valuea_very_secret_string_you_should_change
). Otherwise, you might need to append it as a query parameter:https://<your-public-url>/infobip-webhook?secret=a_very_secret_string_you_should_change
. Again, prioritize signature verification if available over this method.Test Receiving: Send a WhatsApp message from your personal phone to your registered Infobip WhatsApp sender number. Check your Fastify application's console logs. You should see the
Received request on /infobip-webhook
message, followed by the payload details and theProcessed incoming message
log.5. Error Handling, Logging, and Retry Mechanisms
try...catch
blocks for asynchronous operations (like API calls)./send
endpoint) or respond appropriately to the webhook provider (200 OK for successful receipt, 4xx/5xx for errors).setErrorHandler
for more complex applications.logger: true
) is excellent and performant.info
for general operations,warn
for potential issues,error
for failures) based on environment (more verbose in dev, less in prod).async-retry
can help. Use exponential backoff (wait longer between each retry) to avoid overwhelming the API.6. Database Schema and Data Layer (Conceptual)
While this guide uses an in-memory array (
receivedMessages
), a production application requires a persistent database.Why? To store message history, track conversation states, manage user data, and prevent data loss on server restarts.
Choice: PostgreSQL, MongoDB, MySQL, Redis (depending on needs).
Example Schema (Conceptual - PostgreSQL):
Data Layer: Use an ORM (like Prisma, Sequelize, TypeORM) or a query builder (like Knex.js) to interact with the database, handle migrations, and abstract SQL queries. Replace the
receivedMessages.push()
logic with database insertion calls within the webhook handler. Similarly, log sent messages to the database after a successful API call in the/send
route.7. Security Features
dotenv
) and.gitignore
to keep keys out of source control. Use tools like HashiCorp Vault or cloud provider secret managers for production environments./send
) from abuse. Usefastify-rate-limit
:npm audit
, avoiding insecure code patterns). Use security linters.8. Handling Special Cases
messagePayload
in the/send
route and the parsing logic in the/infobip-webhook
according to the Infobip WhatsApp API documentation.429 Too Many Requests
errors gracefully.9. Performance Optimizations
k6
,autocannon
, orwrk
to simulate load and identify bottlenecks in your/send
endpoint or webhook processing.10. Monitoring, Observability, and Analytics
fastify-metrics
to expose application metrics (request counts, latency, error rates) in Prometheus format. Visualize these metrics using Grafana or similar tools.