# RPC Reference

**Proto package:** `qpc.v1`
**Proto files:** 14 files in `proto/qpc/v1/`
**Total methods:** 44

This page is the complete Protobuf definition reference for all 14 proto files in the v2 RPC protocol. For transport framing, see [Wire Format Overview](overview.md). For method ID assignments, see [Method ID Reference](envelope-schema.md).

Generated Rust types live in `crates/quicprochat-proto/src/` (via prost).

---

## auth.proto (IDs 100-103)

OPAQUE asymmetric PAKE for registration and login. See [Auth Schema](auth-schema.md) for field-level documentation and flow diagrams.

```protobuf
syntax = "proto3";
package qpc.v1;

message OpaqueRegisterStartRequest {
  string username = 1;
  bytes request = 2;
}

message OpaqueRegisterStartResponse {
  bytes response = 1;
}

message OpaqueRegisterFinishRequest {
  string username = 1;
  bytes upload = 2;
  bytes identity_key = 3;
}

message OpaqueRegisterFinishResponse {
  bool success = 1;
}

message OpaqueLoginStartRequest {
  string username = 1;
  bytes request = 2;
}

message OpaqueLoginStartResponse {
  bytes response = 1;
}

message OpaqueLoginFinishRequest {
  string username = 1;
  bytes finalization = 2;
  bytes identity_key = 3;
}

message OpaqueLoginFinishResponse {
  bytes session_token = 1;
}
```

---

## common.proto

Shared types and account deletion.

```protobuf
syntax = "proto3";
package qpc.v1;

// Auth context for federation and internal use.
// In v2, session authentication is carried at the QUIC connection level
// (session token), not per-message.
message Auth {
  bytes access_token = 1;
  bytes device_id = 2;
}

// Account deletion (ID 950).
message DeleteAccountRequest {}

message DeleteAccountResponse {
  bool success = 1;
}
```

`DeleteAccountRequest` is empty; the server derives the user identity from the authenticated QUIC session. On success, all user data is purged: OPAQUE record, identity keys, key packages, hybrid keys, queued deliveries, channel memberships, devices, and recovery bundles.

---

## delivery.proto (IDs 200-205)

Store-and-forward message relay. See [Delivery Schema](delivery-schema.md) for field-level documentation.

```protobuf
syntax = "proto3";
package qpc.v1;

message Envelope {
  uint64 seq = 1;
  bytes data = 2;
}

message EnqueueRequest {
  bytes recipient_key = 1;
  bytes payload = 2;
  bytes channel_id = 3;
  uint32 ttl_secs = 4;
  bytes message_id = 5;
}

message EnqueueResponse {
  uint64 seq = 1;
  bytes delivery_proof = 2;
  bool duplicate = 3;
}

message FetchRequest {
  bytes recipient_key = 1;
  bytes channel_id = 2;
  uint32 limit = 3;
  bytes device_id = 4;
}

message FetchResponse {
  repeated Envelope payloads = 1;
}

message FetchWaitRequest {
  bytes recipient_key = 1;
  bytes channel_id = 2;
  uint64 timeout_ms = 3;
  uint32 limit = 4;
  bytes device_id = 5;
}

message FetchWaitResponse {
  repeated Envelope payloads = 1;
}

message PeekRequest {
  bytes recipient_key = 1;
  bytes channel_id = 2;
  uint32 limit = 3;
  bytes device_id = 4;
}

message PeekResponse {
  repeated Envelope payloads = 1;
}

message AckRequest {
  bytes recipient_key = 1;
  bytes channel_id = 2;
  uint64 seq_up_to = 3;
  bytes device_id = 4;
}

message AckResponse {}

message BatchEnqueueRequest {
  repeated bytes recipient_keys = 1;
  bytes payload = 2;
  bytes channel_id = 3;
  uint32 ttl_secs = 4;
  bytes message_id = 5;
}

message BatchEnqueueResponse {
  repeated uint64 seqs = 1;
}
```

---

## keys.proto (IDs 300-304, 510-520)

MLS KeyPackages, hybrid PQ keys, and key transparency. See [Delivery Schema](delivery-schema.md) for field-level documentation.

```protobuf
syntax = "proto3";
package qpc.v1;

message UploadKeyPackageRequest {
  bytes identity_key = 1;
  bytes package = 2;
}

message UploadKeyPackageResponse {
  bytes fingerprint = 1;
}

message FetchKeyPackageRequest {
  bytes identity_key = 1;
}

message FetchKeyPackageResponse {
  bytes package = 1;
}

message UploadHybridKeyRequest {
  bytes identity_key = 1;
  bytes hybrid_public_key = 2;
}

message UploadHybridKeyResponse {}

message FetchHybridKeyRequest {
  bytes identity_key = 1;
}

message FetchHybridKeyResponse {
  bytes hybrid_public_key = 1;
}

message FetchHybridKeysRequest {
  repeated bytes identity_keys = 1;
}

message FetchHybridKeysResponse {
  repeated bytes keys = 1;
}

// Key revocation (ID 510).
message RevokeKeyRequest {
  bytes identity_key = 1;
  string reason = 2;
}

message RevokeKeyResponse {
  bool success = 1;
  uint64 leaf_index = 2;
}

// Check revocation status (ID 511).
message CheckRevocationRequest {
  bytes identity_key = 1;
}

message CheckRevocationResponse {
  bool revoked = 1;
  string reason = 2;
  uint64 timestamp_ms = 3;
}

// KT audit log retrieval (ID 520).
message AuditKeyTransparencyRequest {
  uint64 start = 1;
  uint64 end = 2;
}

message AuditKeyTransparencyResponse {
  repeated LogEntry entries = 1;
  uint64 tree_size = 2;
  bytes root = 3;
}

message LogEntry {
  uint64 index = 1;
  bytes leaf_hash = 2;
}
```

---

## channel.proto (ID 400)

```protobuf
syntax = "proto3";
package qpc.v1;

// Channel create (1 method).
// Method ID: 400.

message CreateChannelRequest {
  bytes peer_key = 1;
}

message CreateChannelResponse {
  bytes channel_id = 1;
  bool was_new = 2;
}
```

`CreateChannel` deterministically derives a channel ID from the calling user's identity key and `peer_key`, so repeated calls with the same peer return the same `channel_id`. `was_new` is `true` on the first creation.

---

## group.proto (IDs 410-413)

Group management: member removal, metadata, member listing, and key rotation.

```protobuf
syntax = "proto3";
package qpc.v1;

// Group management (4 methods).
// Method IDs: 410-413.

message RemoveMemberRequest {
  bytes group_id = 1;
  bytes member_identity_key = 2;
}

message RemoveMemberResponse {
  bytes commit = 1;
}

message UpdateGroupMetadataRequest {
  bytes group_id = 1;
  string name = 2;
  string description = 3;
  bytes avatar_hash = 4;
}

message UpdateGroupMetadataResponse {
  bool success = 1;
}

message ListGroupMembersRequest {
  bytes group_id = 1;
}

message ListGroupMembersResponse {
  repeated GroupMemberInfo members = 1;
}

message GroupMemberInfo {
  bytes identity_key = 1;
  string username = 2;
  uint64 joined_at = 3;
}

message RotateKeysRequest {
  bytes group_id = 1;
}

message RotateKeysResponse {
  bytes commit = 1;
}

// Server-side group metadata store.
message GroupMetadata {
  bytes group_id = 1;
  string name = 2;
  string description = 3;
  bytes avatar_hash = 4;
  bytes creator_key = 5;
  uint64 created_at = 6;
}
```

`RemoveMember` and `RotateKeys` return a `commit` field containing the MLS `Commit` message bytes that the caller must fan-out to the remaining group members via `BatchEnqueue`. `joined_at` in `GroupMemberInfo` is a Unix timestamp in milliseconds.

---

## moderation.proto (IDs 420-424)

Content moderation: encrypted reports, bans, and audit lists.

```protobuf
syntax = "proto3";
package qpc.v1;

// Moderation service: report, ban, unban, list reports, list banned.
// Method IDs: 420-424.

message ReportMessageRequest {
  bytes encrypted_report = 1;
  bytes conversation_id = 2;
}

message ReportMessageResponse {
  bool accepted = 1;
}

message BanUserRequest {
  bytes identity_key = 1;
  string reason = 2;
  uint64 duration_secs = 3;
}

message BanUserResponse {
  bool success = 1;
}

message UnbanUserRequest {
  bytes identity_key = 1;
}

message UnbanUserResponse {
  bool success = 1;
}

message ListReportsRequest {
  uint32 limit = 1;
  uint32 offset = 2;
}

message ReportEntry {
  uint64 id = 1;
  bytes encrypted_report = 2;
  bytes conversation_id = 3;
  bytes reporter_identity = 4;
  uint64 timestamp = 5;
}

message ListReportsResponse {
  repeated ReportEntry reports = 1;
}

message ListBannedRequest {}

message BannedUserEntry {
  bytes identity_key = 1;
  string reason = 2;
  uint64 banned_at = 3;
  uint64 expires_at = 4;  // 0 = permanent ban.
}

message ListBannedResponse {
  repeated BannedUserEntry users = 1;
}
```

`ReportMessageRequest.encrypted_report` is encrypted asymmetrically to the server's admin key; the server cannot read it without the admin private key. `BanUserRequest.duration_secs = 0` is a permanent ban. `BannedUserEntry.expires_at = 0` denotes a permanent ban.

---

## user.proto (IDs 500-501)

Forward and reverse user resolution.

```protobuf
syntax = "proto3";
package qpc.v1;

// User resolve + identity (2 methods).
// Method IDs: 500-501.

message ResolveUserRequest {
  string username = 1;
}

message ResolveUserResponse {
  bytes identity_key = 1;
  bytes inclusion_proof = 2;
}

message ResolveIdentityRequest {
  bytes identity_key = 1;
}

message ResolveIdentityResponse {
  string username = 1;
}
```

`ResolveUser` returns the user's Ed25519 identity key (32 bytes) along with a key-transparency inclusion proof. `ResolveIdentity` is the reverse lookup: given a key, return the username.

---

## blob.proto (IDs 600-601)

Content-addressed binary object storage with chunked upload and ranged download.

```protobuf
syntax = "proto3";
package qpc.v1;

// Blob upload/download (2 methods).
// Method IDs: 600-601.

message UploadBlobRequest {
  bytes blob_hash = 1;
  bytes chunk = 2;
  uint64 offset = 3;
  uint64 total_size = 4;
  string mime_type = 5;
}

message UploadBlobResponse {
  bytes blob_id = 1;
}

message DownloadBlobRequest {
  bytes blob_id = 1;
  uint64 offset = 2;
  uint32 length = 3;
}

message DownloadBlobResponse {
  bytes chunk = 1;
  uint64 total_size = 2;
  string mime_type = 3;
}
```

`UploadBlob` accepts chunks; callers send multiple requests for large blobs using `offset` + `total_size` for reassembly. `blob_hash` is the SHA-256 of the entire blob (content addressing). `DownloadBlob` supports ranged reads via `offset` + `length`.

---

## device.proto (IDs 700-702, 710)

Multi-device management and push notification token registration.

```protobuf
syntax = "proto3";
package qpc.v1;

// Device register/list/revoke (3 methods).
// Method IDs: 700-702.

message RegisterDeviceRequest {
  bytes device_id = 1;
  string device_name = 2;
}

message RegisterDeviceResponse {
  bool success = 1;
}

message ListDevicesRequest {}

message ListDevicesResponse {
  repeated Device devices = 1;
}

message Device {
  bytes device_id = 1;
  string device_name = 2;
  uint64 registered_at = 3;
}

message RevokeDeviceRequest {
  bytes device_id = 1;
}

message RevokeDeviceResponse {
  bool success = 1;
}

// Push notification token registration (ID 710).
enum PushPlatform {
  PUSH_PLATFORM_UNSPECIFIED = 0;
  PUSH_PLATFORM_APNS = 1;
  PUSH_PLATFORM_FCM = 2;
  PUSH_PLATFORM_WEB_PUSH = 3;
}

message RegisterPushTokenRequest {
  bytes device_id = 1;
  PushPlatform platform = 2;
  string token = 3;
}

message RegisterPushTokenResponse {
  bool success = 1;
}
```

`Device.registered_at` is a Unix timestamp in milliseconds. `Device.device_id` is a client-generated UUID (16 bytes). `RegisterPushToken` associates a platform-specific push token with the device for server-initiated push notifications.

---

## recovery.proto (IDs 750-752)

Encrypted account recovery bundle storage. The server stores an opaque blob indexed by `SHA-256(recovery_token)`. The plaintext recovery token and bundle contents are never visible to the server.

```protobuf
syntax = "proto3";
package qpc.v1;

// Recovery service.
// Method IDs: 750-752.

message StoreRecoveryBundleRequest {
  bytes token_hash = 1;  // SHA-256(recovery_token)
  bytes bundle = 2;      // Encrypted recovery bundle (opaque to server).
  uint64 ttl_secs = 3;   // Default 90 days = 7776000.
}

message StoreRecoveryBundleResponse {
  bool success = 1;
}

message FetchRecoveryBundleRequest {
  bytes token_hash = 1;  // SHA-256(recovery_token)
}

message FetchRecoveryBundleResponse {
  bytes bundle = 1;  // Empty if no bundle found.
}

message DeleteRecoveryBundleRequest {
  bytes token_hash = 1;  // SHA-256(recovery_token)
}

message DeleteRecoveryBundleResponse {
  bool success = 1;
}
```

---

## p2p.proto (IDs 800-802)

iroh P2P node address exchange and server health probe.

```protobuf
syntax = "proto3";
package qpc.v1;

// P2P endpoint publish/resolve + health (3 methods).
// Method IDs: 800-802.

message PublishEndpointRequest {
  bytes identity_key = 1;
  bytes node_addr = 2;
}

message PublishEndpointResponse {}

message ResolveEndpointRequest {
  bytes identity_key = 1;
}

message ResolveEndpointResponse {
  bytes node_addr = 1;
}

message HealthRequest {}

message HealthResponse {
  string status = 1;
  string node_id = 2;
  string version = 3;
  uint64 uptime_secs = 4;
  string storage_backend = 5;
}
```

`node_addr` is an iroh `NodeAddr` serialised to bytes. `HealthResponse.storage_backend` is one of `"sql"`, `"file"`, or `"postgres"`. `HealthRequest` requires no authentication and is suitable for infrastructure health checks.

---

## federation.proto (IDs 900-905)

Cross-server relay and proxy operations. All federation methods include a `FederationAuth` struct carrying the origin server's domain for inter-server authentication.

```protobuf
syntax = "proto3";
package qpc.v1;

// Federation relay + proxy (6 methods).
// Method IDs: 900-905.

message FederationAuth {
  string origin = 1;
}

message RelayEnqueueRequest {
  bytes recipient_key = 1;
  bytes payload = 2;
  bytes channel_id = 3;
  FederationAuth auth = 4;
}

message RelayEnqueueResponse {
  uint64 seq = 1;
}

message RelayBatchEnqueueRequest {
  repeated bytes recipient_keys = 1;
  bytes payload = 2;
  bytes channel_id = 3;
  FederationAuth auth = 4;
}

message RelayBatchEnqueueResponse {
  repeated uint64 seqs = 1;
}

message ProxyFetchKeyPackageRequest {
  bytes identity_key = 1;
  FederationAuth auth = 2;
}

message ProxyFetchKeyPackageResponse {
  bytes package = 1;
}

message ProxyFetchHybridKeyRequest {
  bytes identity_key = 1;
  FederationAuth auth = 2;
}

message ProxyFetchHybridKeyResponse {
  bytes hybrid_public_key = 1;
}

message ProxyResolveUserRequest {
  string username = 1;
  FederationAuth auth = 2;
}

message ProxyResolveUserResponse {
  bytes identity_key = 1;
}

message FederationHealthRequest {}

message FederationHealthResponse {
  string status = 1;
  string server_domain = 2;
}
```

Federation relay methods (`RelayEnqueue`, `RelayBatchEnqueue`) are analogous to the client-facing delivery methods but originate from a peer server rather than a client. Proxy methods allow one server to fetch resources (key packages, hybrid keys, user identities) on behalf of a user whose home server is remote.

---

## push.proto (Event IDs 1000-1003)

Server-push event types sent on QUIC uni-streams using the push frame format.

```protobuf
syntax = "proto3";
package qpc.v1;

// Server-push event types (sent on QUIC uni-streams).
// Event type IDs: 1000+.

message PushEvent {
  oneof event {
    NewMessage new_message = 1;
    TypingIndicator typing = 2;
    PresenceUpdate presence = 3;
    GroupMembershipChange membership = 4;
  }
}

message NewMessage {
  bytes channel_id = 1;
  bytes sender_key = 2;
  uint64 seq = 3;
  bytes payload = 4;
  uint64 timestamp_ms = 5;
}

message TypingIndicator {
  bytes channel_id = 1;
  bytes sender_key = 2;
  bool is_typing = 3;
}

message PresenceUpdate {
  bytes identity_key = 1;
  bool online = 2;
  uint64 last_seen_ms = 3;
}

message GroupMembershipChange {
  bytes channel_id = 1;
  bytes actor_key = 2;
  bytes target_key = 3;
  MembershipAction action = 4;
}

enum MembershipAction {
  MEMBERSHIP_ACTION_UNSPECIFIED = 0;
  MEMBERSHIP_ACTION_ADDED = 1;
  MEMBERSHIP_ACTION_REMOVED = 2;
  MEMBERSHIP_ACTION_LEFT = 3;
}
```

Push events are sent by the server without a client request. The `event_type` field in the push frame header (see [Wire Format Overview](overview.md)) determines which `oneof` variant is present. Clients must handle all event types and ignore unknown types gracefully.

---

## Further reading

- [Wire Format Overview](overview.md) -- frame format and transport parameters
- [Method ID Reference](envelope-schema.md) -- complete method ID table
- [Auth Schema](auth-schema.md) -- OPAQUE flow documentation
- [Delivery Schema](delivery-schema.md) -- delivery and key management documentation
- [Authentication Service Internals](../internals/authentication-service.md) -- server-side OPAQUE flow
- [Storage Backend](../internals/storage-backend.md) -- how data is persisted
