Skip to content

feat(backend): add /api/whatsapp/send-route endpoint to C++ backend #205

Description

@markboenigk

Context

PR #203 ships the full UI flow for sending optimized routes to drivers via WhatsApp (modal, phone validation, Next.js API route). The actual WhatsApp send in that PR is mock-only by design — the real API call is explicitly scoped as a follow-up.

Per our architecture decision and confirmation from Nurtekin (who manages the WhatsApp allowlist): the WhatsApp API call must live in the C++ Cloud Run backend, not the Next.js frontend. The do-app-service service account already has Secret Manager access on benevolent-bandwidth — no additional IAM setup needed.

What needs to be built

Add a new endpoint POST /api/whatsapp/send-route to the C++ backend (app/api/src/endpoints/whatsapp_endpoint.cpp) following the same Drogon patterns as osrm_proxy_endpoint.cpp.

Request body (matches what the Next.js route already sends):
```json
{
"to": "14155551234",
"message": "Your route for today: ..."
}
```

Implementation — credentials come from env vars, Cloud Run injects them from Secret Manager automatically:

```cpp
// Read credentials — same ResolveEnvOrDefault pattern used throughout the codebase
const auto access_token = ResolveEnvOrDefault("WHATSAPP_ACCESS_TOKEN", "");
const auto phone_number_id = ResolveEnvOrDefault("WHATSAPP_PHONE_NUMBER_ID", "");

// POST to WhatsApp API — same drogon::HttpClient pattern as osrm_proxy_endpoint.cpp
auto wa_client = drogon::HttpClient::newHttpClient("https://graph.facebook.com");

// In the handler:
auto upstream = drogon::HttpRequest::newHttpRequest();
upstream->setMethod(drogon::Post);
upstream->setPath("/v18.0/" + phone_number_id + "/messages");
upstream->addHeader("Authorization", "Bearer " + access_token);
upstream->setContentTypeCode(drogon::CT_APPLICATION_JSON);

Json::Value payload;
payload["messaging_product"] = "whatsapp";
payload["to"] = to_number; // from request body, no + prefix
payload["type"] = "text";
payload["text"]["body"] = message; // the formatted route text

upstream->setBody(payload.toStyledString());
```

Return the WhatsApp API response status back to the caller.

After this is merged

whatsappClient.ts in the Next.js app (app/ui/src/lib/whatsapp/whatsappClient.ts) needs to be updated to call this C++ endpoint instead of the current mock. That is a small follow-up change (~5 lines).

Acceptance criteria

  • POST /api/whatsapp/send-route exists on the C++ backend
  • Returns 200 + WhatsApp message ID on success
  • Returns 502 if the WhatsApp API call fails
  • Returns 400 if to or message are missing from the request body
  • Returns 503 if WHATSAPP_ACCESS_TOKEN or WHATSAPP_PHONE_NUMBER_ID env vars are not set
  • Tested manually on Cloud Run (secrets are injected there, not available locally)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions