# Events

Events are named payloads delivered to subscribed clients. Vask supports Pusher-compatible server events, batch events, client events, server-to-user events, and system events.

Use `https://api.vask.dev` for HTTP API requests and `wss://wss.vask.dev` for WebSocket clients.

## Server events

Your backend triggers events with the HTTP API or a Pusher-compatible server SDK. The public endpoint shape is:

```text
POST https://api.vask.dev/apps/{app_key}/events
```

Example JSON body:

```json
{
    "name": "order.updated",
    "channel": "private-orders.123",
    "data": "{\"status\":\"paid\"}"
}
```

For multi-channel fanout, use `channels` instead of `channel`.

```json
{
    "name": "announcement.created",
    "channels": ["public-feed", "private-team.42"],
    "data": "{\"title\":\"Deploy complete\"}"
}
```

## Batch events

Use `batch_events` to send multiple channel events in one request.

```text
POST https://api.vask.dev/apps/{app_key}/batch_events
```

```json
{
    "batch": [
        {
            "name": "metric.updated",
            "channel": "private-dashboard.1",
            "data": "{\"value\":42}"
        },
        {
            "name": "metric.updated",
            "channel": "private-dashboard.2",
            "data": "{\"value\":99}"
        }
    ]
}
```

## Excluding the sender

Pass `socket_id` to avoid echoing an event back to the socket that initiated the action.

```json
{
    "name": "cursor.moved",
    "channel": "presence-document.42",
    "data": "{\"x\":120,\"y\":80}",
    "socket_id": "1234.5678"
}
```

## Client events

Client events must start with `client-`. They are accepted only on private and presence channels, and only when client events are enabled for the app.

```js
const channel = pusher.subscribe('private-room.42');

channel.trigger('client-typing', {
    is_typing: true,
});
```

Client events are not supported on public channels or encrypted channels.

## Server-to-user events

When a client signs in with [user authentication](/docs/user-authentication), your backend can send an event to that `user_id` without requiring a channel subscription.

```text
POST https://api.vask.dev/apps/{app_key}/users/{user_id}/events
```

```json
{
    "name": "notification.created",
    "data": "{\"body\":\"Your export is ready\"}"
}
```

## System events

Vask emits Pusher-compatible system events:

| Event                                    | Direction      | Purpose                                  |
| ---------------------------------------- | -------------- | ---------------------------------------- |
| `pusher:connection_established`          | Vask to client | Initial socket id and heartbeat timeout. |
| `pusher:pong`                            | Vask to client | Response to `pusher:ping`.               |
| `pusher:signin_success`                  | Vask to client | User sign-in completed.                  |
| `pusher:error`                           | Vask to client | Command or auth failure.                 |
| `pusher_internal:subscription_succeeded` | Vask to client | Channel subscription accepted.           |
| `pusher_internal:member_added`           | Vask to client | Presence member joined.                  |
| `pusher_internal:member_removed`         | Vask to client | Presence member left.                    |
| `pusher_internal:subscription_count`     | Vask to client | Subscription count changed.              |

Most SDKs expose these through callbacks instead of requiring direct frame handling.

## Info responses

The `events` and `batch_events` endpoints can return channel counts when `info` is requested.

```json
{
    "name": "order.updated",
    "channel": "private-orders.123",
    "data": "{}",
    "info": "subscription_count"
}
```

Counts are snapshots taken independently from delivery.

## Related docs

- [HTTP API reference](/docs/http-api)
- [Subscription count](/docs/subscription-count)
- [User connections](/docs/user-connections)
