Skip to content

feat(api): add WhatsApp send route endpoint#215

Open
Gill87 wants to merge 6 commits into
benevolentbandwidth:mainfrom
Gill87:feat/whatsapp-send-route
Open

feat(api): add WhatsApp send route endpoint#215
Gill87 wants to merge 6 commits into
benevolentbandwidth:mainfrom
Gill87:feat/whatsapp-send-route

Conversation

@Gill87

@Gill87 Gill87 commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds the C++ backend endpoint for sending optimized route messages through WhatsApp.
  • Keeps WhatsApp credentials server-side and forwards successful Meta Graph API responses back to callers.

Motivation

Changes

  • Adds POST /api/whatsapp/send-route with request validation, credential checks, and Meta Graph API POST handling.
  • Wires the endpoint into API startup and CMake build sources.
  • Adds local HTTP integration tests for invalid payloads, missing configuration, successful upstream forwarding, and upstream failure mapping.

Validation

  • git diff --check
  • bash -n tests/integration/http_server/whatsapp_send_route_forwards_to_upstream_test.sh tests/integration/http_server/whatsapp_send_route_rejects_invalid_request_test.sh tests/integration/http_server/whatsapp_send_route_requires_configuration_test.sh tests/integration/http_server/whatsapp_send_route_returns_502_for_upstream_failure_test.sh
  • cmake --preset dev blocked locally because CMake could not find jsoncppConfig.cmake / jsoncpp-config.cmake.
  • clang-format -i app/api/src/endpoints/whatsapp_endpoint.cpp app/api/include/deliveryoptimizer/api/endpoints/whatsapp_endpoint.hpp blocked locally because clang-format is not installed in this shell.

Risk

  • Low to moderate: the endpoint is additive, but production success depends on Cloud Run providing valid WHATSAPP_ACCESS_TOKEN and WHATSAPP_PHONE_NUMBER_ID secrets.
  • The upstream base URL defaults to Meta Graph API and is overridable only for local/stubbed tests.

Rollout and Recovery

  • Deploy normally after CI passes and manually verify on Cloud Run where WhatsApp secrets are injected.
  • Roll back the deployment if WhatsApp sends fail or remove the frontend call path until credentials/upstream behavior are corrected.

@markboenigk markboenigk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review

Good structure and test coverage — the four integration test scripts cover the happy path, validation errors, missing credentials, and upstream failure cleanly. Three issues need addressing before merge.


🔴 Whitespace env var silently bypasses the 503 guard

app/api/src/endpoints/whatsapp_endpoint.cpp lines 104–106

ResolveEnvOrDefault only checks for a null or zero-length string. A value like " " (a trailing newline from Secret Manager, or a space from a copy-paste into Cloud Run's env-var field) is not .empty(), so the access_token.empty() || phone_number_id.empty() guard evaluates false. The handler proceeds and sends Authorization: Bearer to Meta, which returns error 190. The caller gets a 502 "WhatsApp upstream request failed" with no hint the service is misconfigured — it looks like a transient Meta outage.

Fix: Apply the same std::all_of(…std::isspace…) check already used in ReadNonEmptyStringMember when reading the credentials, or trim the env var values before the empty check.


🔴 Graph API version v18.0 is hardcoded with no override

app/api/src/endpoints/whatsapp_endpoint.cpp line 119

upstream_request->setPath("/v18.0/" + phone_number_id + "/messages");

The base URL gets ResolveNormalizedUrlEnvOrDefault so it can be swapped for tests; the API version cannot be changed without a code edit and redeploy. Meta v18.0 was released September 2023 on a 2-year deprecation cycle — its end-of-life is approximately September 2025. Once Meta enforces the sunset for this app, every send will return OAuthException code 2635 and WhatsApp notifications fail permanently with no runtime fix.

Fix: At minimum, extract a named constant (constexpr char kWhatsAppApiVersion[] = "v18.0"). Ideally add a WHATSAPP_API_VERSION env-var override consistent with kWhatsAppBaseUrlEnv, and bump the default to the current stable version (v21.0+).


🟡 Any caller who can reach the Cloud Run URL can trigger sends

app/api/src/endpoints/whatsapp_endpoint.cpp line 89

There is no application-layer auth on this handler — no Drogon filter, no token check in the lambda. This is consistent with the rest of the endpoints in this server, but the external impact here is qualitatively different: a POST from any caller sends a real WhatsApp message from the business's registered number to an arbitrary phone number, spending Meta API quota. Whether Cloud Run IAM is currently blocking allUsers is not visible from the code.

Worth confirming the Cloud Run service requires authentication (roles/run.invoker not granted to allUsers) before deploying, or adding an HMAC/shared-secret check on this endpoint specifically.


🔵 Nit: phone_number_id is not whitespace-trimmed before URL construction

app/api/src/endpoints/whatsapp_endpoint.cpp line 119

A trailing newline in WHATSAPP_PHONE_NUMBER_ID (common in Secret Manager exports) produces a malformed HTTP request line that Meta silently rejects. A whitespace trim on the env var value (same fix as the first finding above) covers this case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants