# Gateway

> Receive events over a WebSocket: connecting, heartbeats, intents, reconnecting and close codes.

The gateway is a WebSocket that pushes [events](https://lammapp.sa/developers/events) to your bot as they happen: new messages, members joining, slash commands being used. Lamma decides who may see each event once, for people and bots together, so a bot never hears about anything its account couldn't see.

## Connecting

```
wss://lammapp.sa/v1/gateway
```

You can also ask for the address with `GET /v1/gateway`, which returns `{ "url": "wss://…" }`. Messages are JSON text frames. Every message has an `op`, and most have a `d` with its data.

1. Open the WebSocket. Lamma sends `hello`:

   ```json
   { "op": "hello", "d": { "heartbeat_interval": 30000 } }
   ```

2. Within 10 seconds, send `identify` with your token and the intents you want:

   ```json
   { "op": "identify", "d": { "token": "lmb1_…", "intents": ["guilds", "guild_messages"] } }
   ```

   Send it once. A second identify on the same connection closes it with `4005`.

3. Lamma sends a `READY` event, then one `GUILD_CREATE` for each server the app is installed in.

4. Every `heartbeat_interval` milliseconds, send a heartbeat. Lamma answers with `heartbeat_ack`. Missing two intervals closes the connection.

   ```json
   { "op": "heartbeat" }
   ```

Events then arrive as `dispatch` messages:

```json
{ "op": "dispatch", "t": "MESSAGE_CREATE", "s": 12, "d": { "id": "…", "content": "hi" } }
```

`t` is the event name, `s` counts up by one on each event on this connection, and `d` is the event's data.

## Ops

| Op | Sent by | Meaning |
| --- | --- | --- |
| `hello` | Lamma | First message. Carries `heartbeat_interval` in milliseconds |
| `identify` | Your bot | Token and intents. Once per connection |
| `heartbeat` | Your bot | Keeps the connection open |
| `heartbeat_ack` | Lamma | Answer to a heartbeat |
| `dispatch` | Lamma | An event |

## Intents

A connection receives the intents it asked for, within what each server's install granted. Privileged intents count only where [privileged access](https://lammapp.sa/developers/apps#privileged-access) holds. The list each server allows is in its `GUILD_CREATE` and `GUILD_UPDATE`. Asking for an intent name Lamma doesn't know closes the connection with `4013`.

Some events are always sent, whatever the intents: `READY`, `GUILD_CREATE`, `GUILD_DELETE` and `INTERACTION_CREATE`. See [Gateway events](https://lammapp.sa/developers/events) for the full list.

## Reconnecting

Each bot has one connection. Connecting again replaces the older connection, which closes with `4009`.

There is no resume. When a connection drops, wait, connect again, identify again, and fetch anything you missed over the REST API, for example with `GET /v1/channels/{channel_id}/messages?after=<last message id>`. Wait longer after each failed attempt, starting at about one second. Events are delivered at most once per connection.

The token is checked again every 10 seconds, so a revoked token or a deleted app ends the connection even if nothing else happens. A bot that falls more than 1 MB behind on reading is closed with `4009`.

## Close codes

| Code | Meaning | Reconnect? |
| --- | --- | --- |
| `4000` | Unknown error | Yes |
| `4001` | Unknown op | Fix the client first |
| `4002` | Invalid JSON | Fix the client first |
| `4003` | Didn't identify within 10 seconds | Yes |
| `4004` | Token invalid or revoked, or the app was switched off or deleted | No |
| `4005` | Already identified on this connection | Fix the client first |
| `4008` | Identify rate limited | Yes, after a pause |
| `4009` | Missed heartbeats, read too slowly, or replaced by a newer connection | Yes |
| `4013` | Invalid intents | Fix the client first |

## Never sent to bots

Presence, typing and direct messages are never sent to apps, and nothing is sent from servers the app isn't installed in.
