1. Abstract
This spec defines a CBOR wire format for World ID authenticators to exchange requests, responses and notifications. The method field MUST use underscore-separated camelCase segments prefixed with worldid. Other WIPs define the methods and their payloads.
It also defines worldid:// deeplinks, which SHOULD follow a namespace, version and action structure. The details of individual deeplinks are defined by the protocols that use them.
2. Motivation
World ID supports authenticators from different providers and on different platforms. A shared message and deeplink format lets them communicate over different transports.
3. Specification
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.
3.1 Message format
3.1.1 Encoding
Messages MUST be encoded using CBOR (RFC 8949). Each transport message MUST contain exactly one CBOR map: a request, response or notification. Receivers MUST reject trailing bytes and validate the whole message before executing the request, including the duplicate-key and resource checks below.
The transport defines message boundaries, routing, authentication and encryption.
Envelope field names are case-sensitive CBOR text strings. Binary payloads MUST use CBOR byte strings. Each method’s defining WIP specifies its parameter and result schemas.
Senders MUST NOT emit maps with duplicate keys. Receivers MUST reject a message in which any key they interpret, including envelope fields and fields of the method’s parameter or result schema, appears more than once in the same map. Receivers MAY accept duplicates of keys they ignore.
Each transport specification MUST set a maximum encoded message size and define what happens when it is exceeded. Implementations MUST limit nesting depth and resource use. Receivers MAY drop messages that exceed these limits or fail transport authentication without replying.
3.1.2 Requests and notifications
Either peer MAY send a request. For each request, the sender is the caller and the receiver is the responder.
A notification is a valid request without an id field. The responder MUST NOT reply to a valid notification, even if execution fails, the method is unknown or its arguments are invalid. A malformed request without an id is not a notification.
A request is a map with these fields:
| Field | Required | Type | Meaning |
|---|---|---|---|
version | Yes | Text string | MUST be "1.0", the envelope version defined by this WIP. |
method | Yes | Text string | Method name following §3.2. |
params | No | Any CBOR value | Arguments conforming to the method’s parameter schema. |
id | No | Text string | ID used to match the response to the request. Omit for notifications. |
Request IDs MUST NOT be null. Callers MUST NOT reuse an ID while waiting for the response to that ID from the same peer in the same session.
For a valid request with an id, the responder MUST return one response with the same ID value.
Omitting params means no arguments were supplied. A present value, including null, MUST conform to the method’s parameter schema. Requests MUST NOT contain fields other than those in the table. Receivers MUST reject unknown envelope fields.
3.1.3 Responses
A response is a map with these fields:
| Field | Required | Type | Meaning |
|---|---|---|---|
version | Yes | Text string | MUST be "1.0". |
id | Yes | Text string or null | The request ID, or null for an uncorrelated error as defined in §3.1.4. |
result | On success | Any CBOR value | The method-defined result, including null when allowed by its schema. |
error | On failure | Map | Failure details as defined below. |
A response MUST contain exactly one of result or error. A success always has a non-null ID. An error always includes its id field, even when null. A null error ID MUST NOT be matched to a pending request. Receivers MUST reject unknown response envelope fields.
The failure details map has these fields:
| Field | Required | Type | Meaning |
|---|---|---|---|
code | Yes | Text string | Stable, case-sensitive failure code. |
message | Yes | Text string | Short human-readable explanation. |
data | No | Any CBOR value | Additional details defined by the method or error code. A present null value is distinct from omission. |
Unknown fields in the error map MUST be ignored. Callers MUST match responses to requests by id, not arrival order. They MUST NOT reply to invalid or unmatched responses, or accept them as successful results. Implementations SHOULD report these as local protocol errors.
3.1.4 Errors
The following error codes are shared by all methods:
| Code | Meaning |
|---|---|
parse_error | The message does not follow the CBOR encoding rules in §3.1.1. |
invalid_request | The request is malformed, or its envelope version is unsupported. |
method_not_found | The requested method is not available. |
invalid_params | The arguments do not match the method’s parameter schema. |
internal_error | The responder could not complete the call because of an internal error. |
Method-specific error codes MUST be defined by the method’s WIP and MUST NOT reuse the codes above. Callers MUST use code, not message, to identify an error.
Whether to reply to a parse error is transport-defined. If a parse error response is sent, it MUST use id: null. For an invalid request, the responder MUST copy its ID into id if it can read a single, unambiguous text string ID; otherwise it MUST use null. Error responses MUST use version: "1.0". Responders MUST NOT send errors in reply to notifications or responses.
3.1.5 Examples
These examples show CBOR diagnostic notation. h'0102ff' represents the three bytes 01 02 ff.
Request with an inline binary argument:
{
"version": "1.0",
"method": "worldid_example_v1_process",
"params": {"payload": h'0102ff'},
"id": "request-1"
}
Successful response with an inline binary result:
{"version": "1.0", "id": "request-1", "result": h'0304'}
Failure response:
{
"version": "1.0",
"id": "request-1",
"error": {"code": "invalid_params", "message": "Unexpected payload length"}
}
Successful response with a nullable result:
{"version": "1.0", "id": "request-1", "result": null}
Uncorrelated parse error:
{"version": "1.0", "id": null, "error": {"code": "parse_error", "message": "bad"}}
Notification (no response, including on failure):
{"version": "1.0", "method": "worldid_example_v1_process", "params": {"payload": h'0102ff'}}
3.2 Methods
The method field MUST consist of camelCase segments joined by underscores _. The first segment MUST be worldid. For example worldid_auth_v1_register.
The method, params, result and error fields MUST be defined in a WIP. This spec does not introduce specific methods.
3.3 Deeplinks
Deeplinks MUST be URIs (RFC 3986) with the scheme worldid. They SHOULD have the form:
worldid://{namespace}/{version}/{action}?{parameters}
namespace is the protocol area, version is v followed by a positive integer, and action is the operation the deeplink starts. For example worldid://auth/v1/register.
Authenticators SHOULD register the worldid scheme with the operating system where the platform allows.
Deeplinks MUST be defined in a WIP. This spec does not introduce specific deeplinks.
4. Backwards Compatibility
This WIP defines a new message format and deeplink format. It does not modify existing protocol behavior, contracts or stored data, and implementations that do not exchange authenticator messages are unaffected. Existing worldid URIs that are not defined by a WIP are not affected.