> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lazyapp.in/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrating from Meta's Cloud API

> Change the base URL and the token.

If you already call Meta's Cloud API, LazyApp accepts Meta-shaped requests and returns Meta-shaped responses. You can move without rewriting your integration, then adopt the native API where it earns its keep.

## The swap

| | Cloud API | LazyApp |
| - | - | - |
| Base URL | `https://graph.facebook.com` | `https://lazyapp.in/meta/whatsapp` |
| Auth | Meta system user token | `Authorization: Bearer sk_live_...` |
| Path | `/v21.0/{phone_number_id}/messages` | unchanged |

```bash Before theme={null}
curl https://graph.facebook.com/v21.0/123456789012345/messages \
  -H "Authorization: Bearer EAAG..." \
  -H "Content-Type: application/json" \
  -d '{
    "messaging_product": "whatsapp",
    "to": "919812345670",
    "type": "text",
    "text": { "body": "Hello" }
  }'
```

```bash After theme={null}
curl https://lazyapp.in/meta/whatsapp/v21.0/123456789012345/messages \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "messaging_product": "whatsapp",
    "to": "919812345670",
    "type": "text",
    "text": { "body": "Hello" }
  }'
```

Same body, same response shape, same error envelope. The version segment is accepted and ignored, so you do not have to chase Graph API versions.

## What the proxy covers

| Endpoint | Method |
| - | - |
| `/meta/whatsapp/{version}/{phone_number_id}/messages` | `POST` |
| `/meta/whatsapp/{version}/{phone_number_id}/media` | `POST` |
| `/meta/whatsapp/{version}/{media}` | `GET`, `DELETE` |
| `/meta/whatsapp/{version}/{phone_number_id}/whatsapp_business_profile` | `GET`, `POST` |
| `/meta/whatsapp/{version}/{phone_number_id}/block_users` | `POST`, `DELETE` |
| `/meta/whatsapp/{version}/{waba_id}/message_templates` | `GET`, `POST` |

The proxy is a translation layer over the same services the native API uses, not a fork — so behaviour cannot drift between the two.

## Webhooks change shape

This is the one part that is not a drop-in. Meta's webhook payload is deeply nested under `entry[].changes[].value`. LazyApp's is flat:

```json Meta theme={null}
{
  "entry": [
    {
      "changes": [
        {
          "value": {
            "statuses": [
              { "id": "wamid...", "status": "delivered", "recipient_id": "919812345670" }
            ]
          }
        }
      ]
    }
  ]
}
```

```json LazyApp theme={null}
{
  "id": "evt_9f8b1c2d",
  "type": "message.delivered",
  "created_at": "2026-08-19T11:42:07+00:00",
  "data": {
    "message": {
      "uuid": "1a2b3c4d",
      "status": "delivered",
      "to": "+919812345670",
      "provider_message_id": "wamid..."
    }
  }
}
```

Signature verification also differs: `X-LazyApp-Signature` over the raw body with your endpoint secret. See [verifying webhooks](https://docs.lazyapp.in/webhooks/verifying.md).

## Suggested order

**1. Point sends at the proxy**

Change the base URL and token in one place. Verify traffic flows with an `sk_test_`
key first.

**2. Move webhooks to LazyApp**

Register an endpoint, verify signatures, and map the flat payload. This is the only
real code change.

**3. Adopt what you could not do before**

Once traffic is flowing, the native API gives you things the Cloud API does not:
scheduling, [events](https://docs.lazyapp.in/sending/events.md) that decouple your code from template names,
[broadcasts](https://docs.lazyapp.in/sending/broadcasts.md) with opt-out and frequency caps enforced server-side,
and [Verify](https://docs.lazyapp.in/sending/verify.md) with fraud controls.

> [!NOTE]
>
> Keep using the proxy indefinitely if it suits you. It is a supported surface, not a
> temporary shim.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.