Keep credentials on the server
Create a dedicated `send_message` API key for this integration. Save the key and base URL in the server environment, then restart the runtime so the values are loaded.
Do not prefix the key with `NEXT_PUBLIC_`, return it from an API route, include it in browser bundles, or print it in application logs.
HOOKMESSAGE_BASE_URL=https://api.hookmessage.com
HOOKMESSAGE_API_KEY=was_replace_with_your_key
HOOKMESSAGE_SENDER_ID=replace_for_paid_sender_modeCreate one reusable API function
Centralize the HTTP call so timeouts, error handling, and headers are consistent. The example includes a sender only when one is configured, which supports both managed routing and assigned paid senders.
type SendMessageInput = {
receiverNumber: string;
message: string;
reference: string;
};
export async function sendHookMessage(input: SendMessageInput) {
const response = await fetch(
`${process.env.HOOKMESSAGE_BASE_URL}/api/messages/send`,
{
method: "POST",
headers: {
"content-type": "application/json",
"x-api-key": process.env.HOOKMESSAGE_API_KEY!,
"idempotency-key": input.reference,
},
body: JSON.stringify({
...(process.env.HOOKMESSAGE_SENDER_ID
? { sender_id: process.env.HOOKMESSAGE_SENDER_ID }
: {}),
receiver_number: input.receiverNumber,
message: input.message,
source_system: "website",
source_reference: input.reference,
}),
},
);
const result = await response.json();
if (!response.ok) {
throw new Error(result.message ?? `HookMessage failed: ${response.status}`);
}
return result;
}Design for queue semantics
The send endpoint is asynchronous. Persist the returned message ID and initial status in your own database before responding to business workflows that need delivery visibility.
Use the same idempotency key when retrying an uncertain network request. Use a new key for a genuinely new customer event.
- 201 queued: accepted, not delivered.
- 401: check the API key and server environment.
- 403: check key role, workspace state, and sender assignment.
- 422: correct the receiver, sender, routing, or request payload.
- 429: respect the retry interval and reduce request frequency.
Operationalize the integration
Add signed webhooks for status updates, monitor sender health, and create alerts for repeated failures. Store safe identifiers rather than complete message bodies in routine logs.
- Record source reference, message ID, status, and timestamps.
- Verify webhook signatures before parsing or processing events.
- Use a dead-letter or review path for permanent failures.
- Rotate exposed API keys and webhook secrets immediately.