---
sidebar_position: 4
sidebar_label: Sending from your server
---

# Sending from Flask

Your server sends events to rooms and to users, after its own work is saved. Everyone in the room gets them, sealed on the way, and a room that keeps history keeps them.

## To a room

```python
realtime.to("order:1042").emit("updated", {"status": "shipped"})
realtime.to(["order:1042", "staff"]).emit("updated", {"status": "shipped"})
```

- **The answer** is the kept event ids, by room, for the rooms that keep history.
- **A refusal** raises `RealtimeError`, whose `code` says why: `too_large`, `too_many`, `reserved` (event names kept for the room itself), `bad_room` ([errors](../apps/errors.md)).
- **Up to 1 MB** an event, to up to 1,000 rooms at once.
- **It is one HTTPS request,** done in the view. For many, or ones a request should not wait on, send them from a task queue (RQ, Celery).

## Not back to the tab that made it

A page that made the change already shows it. Send its tab with the request, and leave it out:

```js
// The page
await fetch( `/orders/${ id }/status`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', 'X-Realtime-Tab': rt.tab },
    body: JSON.stringify( { status: 'shipped' } ),
} );
```

```python
# The view
@app.post("/orders/<int:pk>/status")
def order_status(pk):
    order = set_status(pk, request.get_json()["status"])
    realtime.to(f"order:{pk}").except_tab(request.headers.get("X-Realtime-Tab")).emit("updated", {"status": order.status})
    return {"ok": True}
```

## To a user

Every tab and device a user has open, wherever they are in your app:

```python
realtime.to_user(42).emit("notice", {"text": "Your order shipped"})
realtime.to_user([42, 43]).to("staff").emit("notice", {"text": "A new order"})
```

```js
rt.on( 'notice', ( data ) => toast( data.text ) );   // on the page, for its signed-in user
```

It is sealed with the key of the user, so only their pages read it. A user with nothing open gets nothing: send an email for what must reach them.

## Many at once

```python
realtime.batch([
    {"rooms": "order:1042", "event": "updated", "data": {"status": "shipped"}},
    {"users": 42, "event": "notice", "data": {"text": "Your order shipped"}},
])
```

Up to 100 events a call.

## Asking about a room

```python
realtime.in_room("shop").count()
realtime.in_room("shop").members()                     # of a presence room, their info opened
realtime.in_room("chat:34:42").history(limit=50)
realtime.in_room("chat:34:42").forget(event_id)        # one kept event, forget() for all
realtime.in_room("chat:34:42").kick(43)                # out now, and refused until their token ends
```

`kick()` also moves a sealed room key on, so what is sent after it is not theirs to read, when your server keeps the key generations ([encryption](encryption.md#when-someone-loses-access)).

## Webhooks

Your server can hear what happens in rooms. Set the address on your app page in your WordPlus Cloud account, `https://shop.example.com/api/realtime/webhook`, which your route answers with `realtime.webhook()` ([getting started](getting-started.md#3-your-server)):

```python
# The rule of a room says which events of the pages come here too
realtime.room("chat:{a}:{b}", is_one_of, history=50, emit=["message", "typing"], webhook=["message"])

realtime.on("message", lambda e: save_message(e["event_id"], e["room"], e["from"], e["data"]["text"], e["at"]))   # a repeat has the same id
realtime.on("user.offline", lambda e: mark_away(e["user"]))
```

- **What comes:** the page events a rule names in `webhook`, by their name. `room.occupied` and `room.vacated`. `member.joined` and `member.left`. `user.online` and `user.offline`. `"*"` gets them all.
- **Checked and opened:** each request is signed, and checked before your handler sees it. Sealed data comes opened.
- **At least once:** each event has its id, so a repeat can be dropped. A request that fails is tried again for 24 hours.

More, with Node and PHP side by side: [sending in depth](../apps/sending.md).
