RPP402-001: Discovery
| RFC | RPP402-001 |
| Title | Discovery |
| Status | Draft |
| Version | 1.0.0 |
| Requires | RPP402-000 |
Overview
Discovery is how an agent finds a Service and learns what it sells, how it's priced, in what assets it settles, and which endpoints implement the rest of the protocol. A Service publishes one JSON document at a well-known location; there is no registration step, no API key, and no approval process to be discoverable.
Motivation
An agent comparing three data providers needs a machine-readable answer to "what does this service sell and where do I ask for a price" before it can request a single Quote. Without a standard discovery document, every service invents its own capability-listing format (if it has one at all), and comparison-shopping -the entire point of a multi-provider Commerce Session -becomes bespoke integration work per service.
Problem
Concretely: given only a domain name (market-data.example), how does an agent determine, with no human involvement, (1) whether this is an RPP402 service at all, (2) what capabilities it exposes, (3) what assets it accepts, and (4) where to send a Quote request? RPP402-001 answers all four with one HTTP request.
Terminology
| Term | Definition |
|---|---|
| Discovery Document | The JSON object at /.well-known/rpp.json, defined below. |
| Capability | A named, priceable unit of work, in namespace.action form (e.g. market-data.quote, compute.inference). |
| Registry | An optional aggregator/index of many services' Discovery Documents, surfaced as the Registry Explorer; direct well-known lookup never requires one. |
Protocol
A Service publishes a Discovery Document at:
https://{service-domain}/.well-known/rpp.json
per the .well-known URI convention (RFC 8615). An agent resolves a Service by fetching this URL with GET and Accept: application/json. No authentication is required to read it -Discovery is intentionally public.
Fields:
| Field | Type | Required | Description |
|---|---|---|---|
rpp402_version | string | yes | Protocol wire version, e.g. "1.0". |
service.id | string | yes | Globally unique service identifier, svc_ prefixed. |
service.name | string | yes | Human-readable name. |
service.description | string | yes | One-sentence description of what the service sells. |
wallet.address | string | yes | The service's Robinhood Chain wallet address (0x-prefixed), receiving settlement. |
wallet.chain_id | string | yes | Chain identifier, e.g. "robinhood-1". |
capabilities | array<Capability> | yes | See below. At least one required. |
supported_assets | array<AssetRef> | yes | Assets this service will accept in a Payment Intent (RPP402-004). |
endpoints.quote | string (URL) | yes | Where to POST a Quote request (RPP402-002). |
endpoints.session | string (URL) | yes | Where to POST/GET Commerce Sessions (RPP402-003). |
endpoints.receipts | string (URL) | yes | Where to GET a Receipt by id (RPP402-006). |
Capability object:
| Field | Type | Description |
|---|---|---|
name | string | namespace.action form, e.g. market-data.quote. |
description | string | Human-readable. |
pricing_summary | string | Free-text indicative pricing, e.g. "from $0.002/call" -non-binding; the binding number always comes from RPP402-002. |
AssetRef object -shared across every RFC that references an asset (Quote, Payment Intent, Settlement, Receipt):
{ "type": "stablecoin", "symbol": "USDG", "chain_id": "robinhood-1", "contract": "0x1111...aaaa" }{ "type": "tokenized_security", "symbol": "NVDA.rh", "chain_id": "robinhood-1", "contract": "0x2222...bbbb", "issuer": "Robinhood Assets (Jersey) Limited" }type is one of "stablecoin" or "tokenized_security" in v1. See RPP402-004 §Settlement Assets for how each is used in a Payment Intent.
AssetRef's own schema, $ref'd by every other RFC rather than redefined per document:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://rpp402.com/schemas/v1/asset-ref.json",
"title": "RPP402 Asset Reference",
"type": "object",
"required": ["type", "symbol", "chain_id", "contract"],
"properties": {
"type": { "type": "string", "enum": ["stablecoin", "tokenized_security"] },
"symbol": { "type": "string" },
"chain_id": { "type": "string" },
"contract": { "type": "string", "pattern": "^0x[a-fA-F0-9]{40}$" },
"issuer": { "type": "string" }
},
"if": { "properties": { "type": { "const": "tokenized_security" } } },
"then": { "required": ["issuer"] }
}JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://rpp402.com/schemas/v1/discovery.json",
"title": "RPP402 Discovery Document",
"type": "object",
"required": ["rpp402_version", "service", "wallet", "capabilities", "supported_assets", "endpoints"],
"properties": {
"rpp402_version": { "type": "string", "const": "1.0" },
"service": {
"type": "object",
"required": ["id", "name", "description"],
"properties": {
"id": { "type": "string", "pattern": "^svc_[a-zA-Z0-9]{8,}$" },
"name": { "type": "string", "minLength": 1 },
"description": { "type": "string", "minLength": 1 }
}
},
"wallet": {
"type": "object",
"required": ["address", "chain_id"],
"properties": {
"address": { "type": "string", "pattern": "^0x[a-fA-F0-9]{40}$" },
"chain_id": { "type": "string" }
}
},
"capabilities": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"required": ["name", "description"],
"properties": {
"name": { "type": "string", "pattern": "^[a-z0-9-]+\\.[a-z0-9-]+$" },
"description": { "type": "string" },
"pricing_summary": { "type": "string" }
}
}
},
"supported_assets": {
"type": "array",
"minItems": 1,
"items": { "$ref": "https://rpp402.com/schemas/v1/asset-ref.json" }
},
"endpoints": {
"type": "object",
"required": ["quote", "session", "receipts"],
"properties": {
"quote": { "type": "string", "format": "uri" },
"session": { "type": "string", "format": "uri" },
"receipts": { "type": "string", "format": "uri" }
}
}
}
}Examples
GET https://market-data.example/.well-known/rpp.json
{
"rpp402_version": "1.0",
"service": {
"id": "svc_marketdata01",
"name": "Market Data Co",
"description": "Real-time and historical equity market data."
},
"wallet": {
"address": "0x111111111111111111111111111111111111aaaa",
"chain_id": "robinhood-1"
},
"capabilities": [
{
"name": "market-data.quote",
"description": "Real-time last-trade price for a ticker.",
"pricing_summary": "from $0.002/call"
}
],
"supported_assets": [
{ "type": "stablecoin", "symbol": "USDG", "chain_id": "robinhood-1", "contract": "0x1111...aaaa" }
],
"endpoints": {
"quote": "https://market-data.example/rpp/quote",
"session": "https://market-data.example/rpp/sessions",
"receipts": "https://market-data.example/rpp/receipts"
}
}Security
- Discovery Documents are served over HTTPS only; an agent MUST reject a document fetched over plaintext HTTP.
wallet.addressis advisory at discovery time -it is re-validated against the address that actually signs the Settlement (RPP402-005). A Discovery Document is not itself an authorization to pay; it only tells an agent where to ask.- Because Discovery is unauthenticated and public, services MUST NOT put anything in it they wouldn't publish on a public webpage.
Errors
type | status | Meaning |
|---|---|---|
https://rpp402.com/errors/discovery-not-found | 404 | No document at /.well-known/rpp.json. |
https://rpp402.com/errors/discovery-invalid | 502 | Document fetched but fails schema validation. |
https://rpp402.com/errors/discovery-version-mismatch | 409 | rpp402_version is a major version the client doesn't support. |
Best Practices
- Cache a Discovery Document for no longer than its
Cache-Controlheader allows, and never longer than 24h by default -pricing summaries and endpoints do change. - An agent building a multi-provider Commerce Session should resolve all candidate services' Discovery Documents concurrently, not serially.
- Services should keep
capabilities[].namestable across versions; if a capability is removed, deprecate it in the document rather than deleting it silently.
Reference Implementation
Schema: @rpp402/protocol - discovery.schema.json. Client resolution: rpp.discover(domain) in @rpp402/sdk. Explorer UI: the Registry Explorer.
Previous: RPP402-000 -Introduction · Next: RPP402-002 -Quote
