A new authenticated client-server API endpoint at `POST /_matrix/client/v1/delayed_events/{delay_id}` allows scheduled events
A set of new unauthenticated client-server API endpoints at `POST /_matrix/client/v1/delayed_events/{delay_id}/[send|cancel|restart]` allows scheduled events
to be managed.
The body of the request is a JSON object containing the following fields:
The final path component of these endpoints specifies the action to take on the delayed event:
- `action` - The action to take on the delayed event.\
Must be one of:
- `send` - Send the delayed event immediately instead of waiting for the delay time to be reached.
- `cancel` - Cancel the delayed event so that it is never sent.
- `restart` - Reset the send time to be `now + original_delay`.
@ -134,15 +134,18 @@ Must be one of:
For example, the following would send the delayed event with delay ID `1234567890` immediately:
```http
POST /_matrix/client/v1/delayed_events/1234567890
POST /_matrix/client/v1/delayed_events/1234567890/send
Content-Type: application/json
{
"action": "send"
}
```
Where the `action` is `send`, the homeserver **should** apply rate limiting to provide mitigation against the
These endpoints are unauthenticated so that control over a particular delayed event may be
[delegated to an external service](#delegating-delayed-events)
by sharing the target delayed event's `delay_id` with the service.
Where the action is `send`, the homeserver **should** apply rate limiting to provide mitigation against the
[High Volume of Messages](https://spec.matrix.org/v1.16/appendices/#threat-high-volume-of-messages) threat.
The server will respond with HTTP 404 and an `M_NOT_FOUND` error if the `delay_id` is not recognized or was already cancelled.
@ -159,6 +162,27 @@ that happened while sending the event (e.g. HTTP 403 and `M_FORBIDDEN` if the us
The primary point of rate limiting is event sending when the delay times out or the event is sent using the `send`
action. However, servers can choose to rate limit the management endpoints themselves as well if necessary.
#### Delegating delayed events
It is useful for external services to also interact with delayed events. If a client disconnects, an external service can
be the best source to send the delayed event/"last will".
To permit this, the `delay_id` that uniquely identifies a delayed event also behaves as a scoped access token
that only allows to interact with the `POST /delayed_events` endpoints on that specific `delay_id`.
With this, an SFU that tracks the current client connection state could be given the power to control the delayed event.
The client would share the `delay_id` and the required details, so that the SFU can call the
`POST /delayed_events/{delay_id}/refresh` endpoint while a user is connected
and can call the `POST /delayed_events/{delay_id}/send` endpoint once the user disconnects.
This way, the SFU can be used as the source of truth for the call membership events without knowing anything about
the Matrix call.
Since the SFU has a much lower chance of running into a network issue,
`POST /delayed_events/{delay_id}/restart` calls may be sent much more infrequently.
Instead of calling that endpoint every couple of seconds, a delayed event's
timeout can be set to be long (e.g. 6 hours), as the SFU can be expected to not forget sending the `POST /delayed_events/{delay_id}/send` requests
when it detects a disconnecting client.
### Getting delayed events
The new authenticated client-server API endpoint `GET /_matrix/client/v1/delayed_events` allows clients to get a list of
@ -391,11 +415,10 @@ the call membership "alive".
For example it could make the request every 5 seconds (or some other period less than the `delay`):
```http
POST /_matrix/client/v1/delayed_events/1234567890
POST /_matrix/client/v1/delayed_events/1234567890/restart
Content-Type: application/json
{
"action": "restart"
}
```
@ -462,28 +485,20 @@ it would make it transparent to clients, when an event was scheduled and when it
## Alternatives
### Delegating delayed events
It is useful for external services to also interact with delayed events. If a client disconnects, an external service can
be the best source to send the delayed event/"last will".
### OAuth 2.0 scope for management endpoints
This is not covered in this MSC but could be realized with scoped access tokens.
A scoped token that only allows to interact with the `delayed_events` endpoint and only with a subset of `delay_id`s
would be used.
Instead of the [delayed event management endpoints](#managing-delayed-events) being unauthenticated
to permit [delegation to an external service](#delegating-delayed-events),
those endpoints could be given an OAuth 2.0 scope and be restricted to sessions that have requested it.
The scope would be within the existing `urn:matrix:client:api:*` scope,
so that access to the entirety the Client-Server API would include access to these endpoints as well.
With this, an SFU that tracks the current client connection state could be given the power to control the delayed event.
The client would share the scoped token and the required details, so that the SFU can call the
`refresh` endpoint while a user is connected
and can call the delayed event `send` request once the user disconnects
(using a `{"action": "restart"}` and a `{"action": "send"}``/delayed_events` request.).
This way, the SFU can be used as the source of truth for the call membership events without knowing anything about
the Matrix call.
Using OAuth 2.0 to restrict access on these endpoints has many benefits over using a path parameter (`delay_id`) as an access token,
such as more fine-grained revocability on access to the endpoints,
and better identification of what entity is requesting these endpoints, which can be used to apply per-entity ratelimits.
Since the SFU has a much lower chance of running into a network issue,
`{"action": "restart"}` calls may be sent much more infrequently.
Instead of calling the `/delayed_events` endpoint every couple of seconds, a delayed event's
timeout can be set to be long (e.g. 6 hours), as the SFU can be expected to not forget sending the `{"action": "send"}` action
when it detects a disconnecting client.
The downsides of this approach are its requirement on the homeserver supporting the OAuth 2.0 login API,
and the additional network/configuration overhead for external services to request access to this scope.
### Batch sending
@ -539,7 +554,7 @@ an indicator to determine if the event is expired, instead of letting the SFU
inform about the call termination or using the call app ping/refresh loop as proposed earlier in this MSC.
The advantage is that this does not require introducing a new ping system
(as is proposed here by using the `delayed_events` restart action).
(as is proposed here by using the `delayed_events/{delay_id}/restart` action).
Though with cryptographic identities, the client needs to create the leave event.
The timeout for syncs are much slower than what would be desirable (30s vs 5s).