---
audience: developer
summary: Server-to-server protocol + admin surface.
title: Federation API
path: reference/api/federation
status: published
---

# Federation API

14 endpoints. Split into the **S2S protocol** (consumed by peers,
not by your end-user clients) and the **admin** surface.

## Server-to-server (signed)

These endpoints are called by *other* ScaiWave servers, not your
own client. Every request is signed with the calling server's
Ed25519 key; ScaiWave verifies before processing.

| Method | Path | Purpose |
|---|---|---|
| `GET` | `/.well-known/scaiwave/server` | Server descriptor: public key, supported versions, endpoints. |
| `GET` | `/_scaiwave/federation/v1/profile/{local_id}` | Profile of a local participant (for foreign-side member rendering). |
| `GET` | `/_scaiwave/federation/v1/rooms/{room_id}/members` | Member list of a federated room. |
| `GET` | `/_scaiwave/federation/v1/rooms/{room_id}/backfill` | Historical events in the room (for catch-up). |
| `POST` | `/_scaiwave/federation/v1/send` | Receive a signed event from a peer. |

The `/send` endpoint validates:

- HTTP signature header.
- Event's own signature against the claiming server's key.
- The claiming server is on this tenant's `allowed_peers` list (or
  policy is `open`).
- The recipient room exists and accepts federation.

Failure modes return 4xx with a stable error code so peers can log
and retry intelligently.

## Self-DM (federated)

| Method | Path | Purpose |
|---|---|---|
| `POST` | `/v1/me/federated-dms` | Start a federated 1:1 with a foreign participant. |

```json
{ "fqid": "@alice:peer.example.com" }
```

## Admin

Requires `power_level=admin` on tenant.

| Method | Path | Purpose |
|---|---|---|
| `GET` | `/v1/admin/federation/identity` | Your server's key + server_name. |
| `GET` | `/v1/admin/federation/peers` | Active peer list with last_seen / error metrics. |
| `GET` | `/v1/admin/federation/policy` | Read current policy. |
| `PUT` | `/v1/admin/federation/policy` | Update policy. |
| `POST` | `/v1/admin/federation/foreign/{participant_id}/refresh` | Refresh a foreign participant's profile (re-fetches from peer). |
| `PUT` | `/v1/admin/rooms/{room_id}/federate` | Enable / disable federation for a room. |
| `POST` | `/v1/admin/rooms/{room_id}/federation/invite` | Send an invite to a foreign participant. |
| `POST` | `/v1/admin/rooms/{room_id}/federation/backfill` | Pull missed history from a peer. |

### Policy fields

```json
{
  "default_mode": "open|invite_only|closed",
  "allowed_peers": ["peer1.example.com", "peer2.example.com"],
  "max_foreign_participants_per_room": 50,
  "max_backfill_events_per_request": 1000,
  "min_signature_protocol": "v1"
}
```

### Identity rotation

The federation key rotates yearly (configurable). Rotation creates
a new key, publishes it on `/.well-known`, and starts signing new
events with it. The old key remains valid for an overlap window
(default 30 days) so peers that haven't refreshed yet can still
verify events.

CLI:

```bash
scaiwave admin federation key rotate
```

See [Concepts: Federation](/docs/scaiwave/concepts/federation) for
the conceptual model and
[Enable federation with a peer](/docs/scaiwave/tutorials/developer/enable-federation-with-a-peer)
for the setup recipe.
