RPP402-001Draft

RPP402-001: Discovery

RFCRPP402-001
TitleDiscovery
StatusDraft
Version1.0.0
RequiresRPP402-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

TermDefinition
Discovery DocumentThe JSON object at /.well-known/rpp.json, defined below.
CapabilityA named, priceable unit of work, in namespace.action form (e.g. market-data.quote, compute.inference).
RegistryAn 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:

FieldTypeRequiredDescription
rpp402_versionstringyesProtocol wire version, e.g. "1.0".
service.idstringyesGlobally unique service identifier, svc_ prefixed.
service.namestringyesHuman-readable name.
service.descriptionstringyesOne-sentence description of what the service sells.
wallet.addressstringyesThe service's Robinhood Chain wallet address (0x-prefixed), receiving settlement.
wallet.chain_idstringyesChain identifier, e.g. "robinhood-1".
capabilitiesarray<Capability>yesSee below. At least one required.
supported_assetsarray<AssetRef>yesAssets this service will accept in a Payment Intent (RPP402-004).
endpoints.quotestring (URL)yesWhere to POST a Quote request (RPP402-002).
endpoints.sessionstring (URL)yesWhere to POST/GET Commerce Sessions (RPP402-003).
endpoints.receiptsstring (URL)yesWhere to GET a Receipt by id (RPP402-006).

Capability object:

FieldTypeDescription
namestringnamespace.action form, e.g. market-data.quote.
descriptionstringHuman-readable.
pricing_summarystringFree-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):

json
{ "type": "stablecoin", "symbol": "USDG", "chain_id": "robinhood-1", "contract": "0x1111...aaaa" }
json
{ "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:

json
{
  "$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

json
{
  "$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

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.address is 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

typestatusMeaning
https://rpp402.com/errors/discovery-not-found404No document at /.well-known/rpp.json.
https://rpp402.com/errors/discovery-invalid502Document fetched but fails schema validation.
https://rpp402.com/errors/discovery-version-mismatch409rpp402_version is a major version the client doesn't support.

Best Practices

  • Cache a Discovery Document for no longer than its Cache-Control header 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[].name stable 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