# The 9 event types with their payload

8 **subscribable** types + `webhook.test` (not subscribable). An endpoint with an explicit `events` list receives ONLY those types; empty/omitted = all (new ones arrive on their own). The `data` of each:

| Type | Subscribable | Description |

| --- | --- | --- |

| `message.received` | ✓ | A customer messaged you. data.message = WhatsApp message object (text/image/audio/…); data.contacts[] identifies the sender. |

| `message.echo` | ✓ | 🌟 The Coexistence differentiator: a message the OWNER sent FROM THE PHONE, with its content. origin='device' (does not consume the plan). from = your business number. |

| `message.status` | ✓ | Receipt for a message you sent via /v1. origin (api\|device) tells your send apart from one made by hand on the phone. A 'device' receipt has NO message of yours behind it — that's expected. |

| `connection.created` | ✓ | A new number connected (panel or hosted onboarding). Your externalId travels in the envelope → provision the end-customer in your system. |

| `connection.status_changed` | ✓ | A connection's status changed (e.g. status='disconnected'). Alert or pause sends to that number. |

| `connection.usage_threshold_reached` | ✓ | ONE number's limit (its monthlyMessageLimit) hit 70/90/100%. Emitted ONCE per (number, period, threshold). The commercial one: warn that end-customer or raise the cap. |

| `usage.threshold_reached` | ✓ | The ACCOUNT plan (sum of all numbers) hit a threshold. connection is null, sequence 0. Decide upgrade or cutoff. |

| `history.synced` | ✓ | (Coexistence) summary of the conversation backfill at connect. shared:false = the owner did not share their history. ⚠ Historical messages are NOT forwarded one by one. |

| `subscription.activated` | ✓ | (Billing) the first payment was confirmed and the reseller's client account became active. connection=null. React by enabling their service. |

| `subscription.cancelled` | ✓ | (Billing) subscription cancelled. Works until accessUntil; then sending is blocked (receiving is not). connection=null. |

| `billing.payment_failed` | ✓ | (Billing) a recurring charge failed. Enters warning/grace (nothing is cut yet). Dun your client BEFORE the cutoff. connection=null. |

| `billing.payment_recovered` | ✓ | (Billing) the payment was recovered and the account reactivated on its own. connection=null. |

| `billing.amount_updated` | ✓ | (Billing) the amount of your next renewal changed. You can show your client the amount before it is charged. connection=null. ⚠ Under flat rate the change is the PLAN or the FX rate: `overageArs` and `overageMessages` come back as 0 (only a bespoke plan with an agreed allowance moves them). |

| `webhook.test` | — | The panel 'Test' button event. NOT subscribable: it is ALWAYS delivered to that endpoint (even with an explicit event list) to validate connectivity + signature. connection=null, data.test=true. Never treat it as real traffic. |

**`message.received`** — data

```json
{
  "message": {
    "id": "wamid.HBgL…",
    "from": "5493511234567",
    "type": "text",
    "text": {
      "body": "hola"
    }
  },
  "contacts": [
    {
      "wa_id": "5493511234567",
      "profile": {
        "name": "Ana"
      }
    }
  ]
}
```

**`message.echo`** — data

```json
{
  "origin": "device",
  "message": {
    "id": "wamid.HBgL…",
    "from": "5493516516690",
    "to": "5493511234567",
    "type": "text",
    "timestamp": "1754531482",
    "text": {
      "body": "te confirmo el turno para mañana 10hs"
    }
  }
}
```

**`message.status`** — data

```json
{
  "messageId": "wamid.HBgL…",
  "status": "read",
  "origin": "device",
  "recipient": "5493511234567",
  "timestamp": "2026-08-06T00:31:25.000Z"
}
```

**`connection.created`** — data

```json
{
  "status": "connected"
}
```

**`connection.status_changed`** — data

```json
{
  "status": "disconnected",
  "previousStatus": "connected"
}
```

**`connection.usage_threshold_reached`** — data

```json
{
  "scope": "connection",
  "threshold": 90,
  "used": 900,
  "limit": 1000,
  "period": "2026-08",
  "connection": {
    "id": "conn_4eede070e5a84d1590bdce2ea1d837bc",
    "label": "Farmacia López",
    "externalId": "farmacia-lopez"
  }
}
```

**`usage.threshold_reached`** — data

```json
{
  "scope": "account",
  "threshold": 90,
  "used": 22610,
  "limit": 25000,
  "period": "2026-08"
}
```

**`history.synced`** — data

```json
{
  "conversations": 34,
  "messages": 512,
  "shared": true,
  "phase": 0
}
```

**`subscription.activated`** — data

```json
{
  "planCode": "growth",
  "periodEnd": "2026-09-13T00:00:00.000Z"
}
```

**`subscription.cancelled`** — data

```json
{
  "accessUntil": "2026-09-13T00:00:00.000Z"
}
```

**`billing.payment_failed`** — data

```json
{
  "paymentId": "123456789",
  "amount": 59000,
  "currency": "ARS"
}
```

**`billing.payment_recovered`** — data

```json
{
  "planCode": "growth",
  "paymentId": "123456789"
}
```

**`billing.amount_updated`** — data

```json
{
  "totalArs": 52500,
  "baseArs": 52500,
  "overageArs": 0,
  "overageMessages": 0
}
```

**`webhook.test`** — data

```json
{
  "type": "test",
  "test": true,
  "message": "WAIA Connect test event — your endpoint is reachable and verifying signatures. This is NOT real traffic."
}
```
