Transports
Gateway uses JSON-RPC for structured operations, HTTPS webhooks for event delivery, and dedicated HTTP routes for large bytes.
Gateway has one HTTP boundary with three deliberately distinct shapes:
| Traffic | Transport | Why |
|---|---|---|
| Structured request/response operations | JSON-RPC 2.0 at POST /rpc | One typed method registry and one error envelope |
| Consumer event delivery | HTTPS webhook push | One delivery mode with Ed25519 verification (Gateway JWKS, consumer-bound) over the exact raw body |
| Large content | Dedicated HTTP routes | Bytes are not base64-encoded or placed in a JSON envelope |
JSON-RPC
POST /rpc
Content-Type: application/json
Authorization: Bearer <access_token>
X-Traummail-Actor: user
{
"jsonrpc": "2.0",
"id": 1,
"method": "Accounts/list",
"params": {}
}{ "jsonrpc": "2.0", "id": 1, "result": { "accounts": [] } }Method spelling and native Rust request/result schemas are projected into the
generated OpenAPI 3.1 document and
method registry. JSON keys use snake_case.
The request body may be an array of up to 20 requests. Responses are
returned in order with each id echoed; id-less notifications are rejected.
Declaring the actor
Every request (JSON-RPC and the content routes) declares who initiated it in
exactly one X-Traummail-Actor header:
| Value | Use it when |
|---|---|
user | The person using your application initiated the request. |
agent | An AI agent acting for them initiated it: assistant tools, MCP servers, automated tool execution. This includes reads and actions the person approved but the agent carries out. |
There is no default. A missing, unknown or repeated header is refused with
GatewayError.InvalidArgument before the method runs, and one header covers a
whole batch. Declaring the actor honestly is your application's
responsibility: providers route by it. Gmail, for example, requires agent
traffic to use a separate OAuth client, so an agent request reaches Gmail only
over that client. The actor is recorded as Operation.actor. A request
replayed with the same idempotency key by a different actor is a different
request and is refused. The SDKs send the header from the client's required
actor option, so use one client per actor.
Content HTTP
Downloads use the content lane, POST /gateway/content/v1:
a binary request naming an authorized mail-replication stream and message, and
a response of bounded binary frames ending in one result frame. It serves only
authorized DUCS consumers; events carry no content handles. Uploads use POST /gateway/content
(staged content), which returns an
upload_ref; its failures use an HTTP status and the same safe public error
vocabulary as JSON-RPC.
Webhook delivery
Named event consumers configure one HTTPS webhook URL. Gateway signs the exact raw request body and retries delivery according to the consumer lease policy. Each consumer receives every event variant authorized for its owner buffer; event selection is consumer-side dispatch and never part of cursor identity. See Events for headers, signature verification, and replay handling.
Gateway has no public binary-RPC or parallel protobuf API. Tunnel alone retains protobuf framing for its dedicated control/data protocol.