Meshline
English translationDownload Markdown

The Simplified Chinese text is authoritative.

Method, Transport, and Error Conventions

Client–relay protocol

Endpoints and Authentication

When connecting, clients MUST obtain and verify the current RelayDescriptor by relay_id under Relay discovery, then select an address under Relay endpoint addresses. Previously obtained URLs have no continuing authority. Clients use the selected HTTPS base address for the HTTP API; a WSS address additionally enables the WebSocket API. Before using channel or group hosting, clients MUST confirm that a valid descriptor declares channel.host.v1 or group.host.v1, respectively.

HTTP calls requiring a session MUST carry token in the X-Meshline-Session header. WebSocket calls use the authenticated session bound to that connection. Each session is valid only for the establishing relay origin, account, and session mode; device sessions also bind a device ID. Clients MUST NOT send tokens to another origin, even if both addresses belong to the same relay. Device sessions confirm the calling account and device; account sessions confirm only the account and cannot satisfy methods requiring calling-device identity.

Clients MUST NOT participate directly in the relay DHT or use unverified relay addresses. Target relays and forwarding follow the Calling and routing model.

Method and Request Mapping

Method Paths

HTTP request URLs combine the HTTPS base address listed in RelayDescriptor with the method path. The method path replaces each . in the dot-separated method name with /, preserving case in every segment.

For example, with base address https://relay.example.com/meshline/v1, relay.info maps to GET https://relay.example.com/meshline/v1/relay/info.

WSS connects directly to the complete listed WSS address without a method path; the method name goes in the JSON-RPC request. WebSocket and relay RPC retain dot-separated method names.

Request Parameters and Encoding

JSON Bodies and Parameter Objects

HTTP requests and responses carrying JSON bodies MUST use media type application/json in Content-Type. charset may be omitted but, if present, MUST be utf-8. Recipients MUST accept both application/json and application/json; charset=utf-8, parsing HTTP media type syntax rather than comparing the complete header literally. Media type, parameter names, and utf-8 are case-insensitive; valid parameter quoting and whitespace do not change meaning. An explicit different charset MUST be rejected, without switching encoding or transcoding before acceptance. Bodies always follow the general protocol UTF-8 requirement, including when charset is omitted.

For methods with request parameters, HTTP POST, PUT, PATCH, and DELETE bodies directly carry the complete parameter object, and WebSocket JSON-RPC params carries the same object. HTTP does not use JSON-RPC envelopes. Except for GET, parameters are not passed in query strings. Parameterless HTTP requests have no body; WebSocket requests may omit params or use {}, both treated as parameterless.

If all parameters of the current invocation form are optional, WebSocket may omit params or use an empty object, applying that form's defaults. If present, params MUST be a JSON object. Explicit null, arrays, and other non-object values are Invalid Params, not omission.

GET Query Parameters

HTTP GET parameters use same-named query fields. Relays MUST accept valid percent-encoding, decode names and values once, then restore parameter types from the field table.

  • Decoded integer text MUST use the shortest decimal form under Safe integers and satisfy the field's range. Booleans use lowercase true or false.
  • Omitted optional fields produce no query parameter. Scalar names MUST NOT repeat.
  • GET carries no arrays, objects, or explicit null; queries with signatures or nested authorization material use POST.
  • GET does not change session or authorization requirements or imply public cacheability.

Relays MUST ignore query parameters whose decoded names are not defined by the method, without rejecting solely for their presence. Defined parameters still must pass validation. Unknown parameters MUST NOT replace required fields or alter method selection, sessions, or authorization requirements.

Method Semantics and Interface Consistency

Method Purpose
GET Queries
PUT Establish or set state
PATCH Modify part of state
DELETE Remove a resource or available state
POST Create, perform state transitions, or process queries requiring complex signatures and authorization material

PUT and DELETE idempotency constrains server effects of repeated requests; it does not require identical response status at different times. Clients still follow method-specific duplicate and retry rules after timeouts or lost responses.

HTTP and WebSocket interfaces for the same method MUST apply identical parameter checks, authorization, state changes, duplicate handling, error semantics, and response objects for identical invocation forms and parameters.

Methods without HTTP interfaces are available only through WebSocket.

Pagination

All paginated methods use these common rules. limit is the maximum number of entries requested for this page and, if present, MUST be a positive safe integer. Invalid types or ranges return bad_request. When omitted, the relay chooses page size under local resource policy and response-size limits.

With explicit limit, the relay may reduce the returned count for resource or response-size limits but MUST NOT exceed the requested value. A valid limit above the local cap should yield a smaller page, not parameter rejection solely for that reason.

Clients MUST use the method's has_more or next to decide whether to continue, not infer completion from fewer entries than limit or the previous page. Page-size changes do not alter read order, snapshot boundaries, or cursor advancement rules.

HTTP Responses

When a method defines a response object, success returns HTTP 200 with that JSON object directly in the body. Without a response object, success returns HTTP 204.

RelayError

RelayError is the common machine-readable error object for unsuccessful HTTP responses.

Field Type Required Semantics
code string Yes Relay error code
message string Yes Text for logs and diagnostics, not program branching
data object No Machine-readable error details defined by common error rules or the method

HTTP Status Mapping

HTTP status RelayError code
400 Business errors not otherwise mapped here, including bad_request, invalid_signature, device_unknown, clock_skew, stale_state, invalid_state, message_expired, target_not_local, and route_stale
401 unauthorized
403 forbidden
404 not_found, route_not_found
409 state_conflict
413 request_too_large
429 rate_limited
503 internal_error, bad_gateway, temporarily_unavailable

Clients MUST identify business errors by JSON code, not HTTP status alone. When the limiter can determine a wait, it returns data.retry_after and a consistent Retry-After under Rate-limit retry waiting rules.

WebSocket JSON-RPC

Clients connect to a WSS endpoint from RelayDescriptor and exchange JSON-RPC 2.0 objects in WebSocket text messages. Each message MUST contain exactly one complete UTF-8 JSON object, at most 1 MiB. This protocol does not use JSON-RPC batches. Binary messages MUST be rejected with close status 1003; oversized messages close with 1009.

JSON-RPC extension fields follow the general rules; they MUST count toward complete message size and MUST NOT change sessions.

Connection authentication, identity binding, and renewal follow Session validity and connection binding and WebSocket session renewal. For notification connection requirements and catch-up after disconnection, see Client–relay notifications.

Successful responses MUST contain result and no error; failed responses MUST contain error and no result. Clients MUST NOT assume response order and should correlate requests by id.

Requests

{"jsonrpc":"2.0","id":"client-1","method":"message.timeline.sync","params":{"after":41,"limit":50}}
Field Type Required Semantics and constraints
jsonrpc string Yes Fixed as 2.0
id string or integer Yes Opaque client-selected correlation value; string UTF-8 length MUST NOT exceed 128 bytes; integers MUST be safe integers; unique among outstanding requests on the connection
method string Yes Method name
params object Conditional Parameters of the current invocation form; may be omitted or {} when parameterless or all parameters are optional

Clients MUST NOT send request notifications without id. Top-level arrays, non-object values, or jsonrpc, id, or method that fails this table constitute Invalid Request. If id fails type, size, or range requirements, the error response's id is null; the invalid value MUST NOT be echoed. params violating the method definition constitutes Invalid Params.

Successful Responses

For example, a successful auth.challenge response is:

{"jsonrpc":"2.0","id":"client-1","result":{"nonce":"base64url...","created_at":1730000000,"expires_at":1730000300}}
Field Type Required Semantics and constraints
jsonrpc string Yes Fixed as 2.0
id string or integer Yes Echoes the corresponding request id unchanged
result Any JSON value Yes Method-defined response object, or null when none

Error Responses

{"jsonrpc":"2.0","id":"client-1","error":{"code":-32001,"message":"authentication is required"}}
Field Type Required Semantics and constraints
jsonrpc string Yes Fixed as 2.0
id string, integer, or null Yes Echoes a determinable valid request id; otherwise null
error object Yes JSON-RPC error for this call

Error Object

Field Type Required Semantics and constraints
code integer Yes Fixed JSON-RPC code from Relay error codes, or a protocol error below
message string Yes Log and diagnostic text, not program branching
data object No Present only when common rules or the method define a machine-readable error-related object; not for duplicating string error codes or ordinary diagnostic text

Protocol Error Codes

code Name Condition
-32700 Parse Error Text message is not a valid single JSON value; id is null
-32600 Invalid Request JSON value is not a single request object meeting this section; id is null if no valid ID can be obtained
-32601 Method Not Found This relay does not support the method
-32602 Invalid Params params or its parameters violate the method definition
-32603 Internal Error Unclassified internal relay failure

Error Codes

HTTP responses use string code. Client WebSocket and relay RPC use integer JSON-RPC code; this table fixes both encodings for the same failure semantics. Program logic uses the code for its transport and MUST NOT parse message.

String code JSON-RPC code Category Meaning and caller behavior
bad_request -32602 Permanent Invalid structure, format, or value in method parameters or business objects
method_not_found -32601 Permanent Method unsupported by this relay
internal_error -32603 Temporary Unclassified server failure
unauthorized -32001 Permanent Session absent, expired, or revoked; HTTP session token missing or malformed; or challenge missing, expired, or consumed
forbidden -32003 Permanent A valid session's account, device, or mode lacks method permissions, or a valid business identity lacks the required permission
invalid_signature -32004 Permanent Invalid cryptographic account, device, request, or business-object signature; MUST NOT be used for a validly signed device certificate whose device is not currently valid
device_unknown -32005 Conditional Required certificate missing or device lacks current valid authorization; authentication and reads do not distinguish nonexistent, removed, not-yet-effective, expired, or revoked devices
clock_skew -32006 Conditional Request/message creation or update time fails the receiving relay's applicable clock tolerance or freshness check
not_found -32010 Conditional Requested route, profile, or object does not exist; retry depends on the method
state_conflict -32011 Permanent Referenced revision, precondition, or concurrency condition changed; required revision/counter advancement is exhausted; or identifier reuse violates method-specific duplicate rules. For message idempotency, the same logical key has different request content
stale_state -32012 Conditional Submitted state is older than stored state
invalid_state -32013 Conditional A same-revision route conflict in a dependent account has not been superseded, or target profile, devices, and route are inconsistent and no verifiable response can be produced
message_expired -32014 Permanent Message exceeds this relay's delivery age limit, a known result-retention period ended with no available result, or reliable delivery could not be confirmed by its fixed deadline
request_too_large -32015 Permanent Request parsed successfully but the complete parameter object or method-limited business object exceeds its size cap; oversized raw frames produce no business response
target_not_local -32020 Routing This relay cannot confirm it is the target's current home relay and has no known valid current route pointing elsewhere
route_stale -32021 Routing This relay knows a valid current route pointing elsewhere
route_not_found -32022 Routing Source could not resolve a route
bad_gateway -32023 Temporary Remote response fails validation and MUST NOT be passed to the client
rate_limited -32030 Temporary Rate or resource quota restriction
temporarily_unavailable -32031 Temporary Peer, network, or service temporarily unavailable

JSON-RPC -32700 and -32600 describe only unparseable client WebSocket messages or relay RPC frames, or JSON that is not a valid request. They do not correspond to HTTP business errors.

Automatic retries of temporary errors use local backoff and MUST NOT loop immediately. Message delivery additionally follows Delivery deadlines and retries, and rate_limited follows Rate-limit retry waiting rules.

Resource and Security Controls

Relays may impose quotas or rate limits by connection, Peer, relay_id, account, source address, and operation type. Thresholds are deployment policy and do not enter signed objects or protocol-version decisions.

Client API requests and already decoded relay RPC requests exceeding rate or resource quotas MUST return rate_limited. Once framing and decoding are complete, parameters exceeding a method's size limit return request_too_large under Relay streams and frames. If a connection-level limit is reached before decoding completes, the relay may directly reject or reset the stream. Initiators MUST treat such termination as a temporary failure under Temporary-error retry conventions.

Rate-Limit Retry Waiting Rules

Hint Generation and Encoding

rate_limited may provide a relative wait in error data.retry_after. HTTP RelayError.data, client WebSocket error.data, and relay RPC error.data use the same structure:

Field Type Required Semantics and constraints
retry_after integer No Minimum seconds from receipt of this response before retrying the limited request; MUST be a nonnegative safe integer, not a Unix timestamp

The limiter MUST provide it when it can determine a wait, and may omit it otherwise. This hint applies only to rate_limited and changes no other error semantics. HTTP 429 carrying it MUST also return a numerically identical Retry-After using delay-seconds under RFC 9110 Section 10.2.3; this protocol does not use HTTP-date for rate-limit hints. If no wait can be supplied, omit both field and header.

For example, this HTTP error is returned with Retry-After: 30:

{"code":"rate_limited","message":"request rate exceeded","data":{"retry_after":30}}

The corresponding WebSocket error is:

{"jsonrpc":"2.0","id":"client-1","error":{"code":-32030,"message":"request rate exceeded","data":{"retry_after":30}}}

Hint Reception and Forwarding

Automatic retries MUST satisfy both this wait and local backoff; recipients may wait longer. Without a hint, use local backoff. 0 means only that there is no additional wait, not permission to bypass backoff and loop immediately. A hint guarantees neither success after waiting nor extension of delivery deadlines or other business validity periods.

When forwarding a verified rate_limited error to a client, a relay MUST preserve this field and apply the error mapping for that client's transport. Recipients measure waiting from receipt of the corresponding response. Invalid hint values MUST NOT be treated as 0 or omission; reject them under existing invalid-response rules. Kademlia messages and stream terminations without an error response carry no such hint.