RPP402-002Draft

RPP402-002: Quote

RFCRPP402-002
TitleQuote
StatusDraft
Version1.0.0
RequiresRPP402-001

Overview

A Quote is a Service's binding, time-limited price for one Capability call, in one Settlement Asset. An agent requests a Quote directly from the endpoints.quote URL a Discovery Document (RPP402-001) points to. A Quote is a standalone object -it exists before any Commerce Session and can be requested from several Services to compare, with no obligation to purchase.

Motivation

Pricing is the first decision point in any purchase. MPP and x402 fold pricing into the 402 challenge itself -a client sees a price only in the act of being asked to pay for that exact resource, with no separate step to shop around. RPP402 separates Quote from purchase specifically so an agent can request Quotes from three Services, compare them, and only then start a Commerce Session with the one it picked. This is the first of the two structural differences from prior art named in RPP402-000.

Problem

An agent needs a price it can act on later -not an estimate that might have moved by the time it decides. A Quote must therefore be both binding (the Service commits to it) and expiring (the Service isn't on the hook forever, since underlying costs, and for tokenized-asset pricing, underlying market prices, move).

Terminology

TermDefinition
QuoteA binding, time-limited price for one Capability call.
Quote RequestThe input an agent sends to request one.
expires_atThe instant after which a Quote can no longer be accepted into a Payment Intent (RPP402-004).

Protocol

POST {endpoints.quote} with a QuoteRequest:

FieldTypeRequiredDescription
capabilitystringyesMust match a capabilities[].name from the service's Discovery Document.
paramsobjectnoCapability-specific parameters (e.g. { "ticker": "NVDA" }). Opaque to RPP402 itself.
settlement_assetAssetRefyesWhich supported asset (from Discovery) the agent wants priced in.
agent_walletstringyesThe requesting agent's wallet address -lets a Service return agent-specific pricing tiers if it offers them, and is echoed back into the Quote for later verification.

Response, a Quote object:

FieldTypeDescription
rpp402_versionstring"1.0".
idstringquote_ prefixed, globally unique.
service_idstringEchoes the Service's service.id.
capabilitystringEchoes the request.
priceMoney{ asset: AssetRef, amount: string } -see below.
expires_atstring (RFC 3339)When this Quote stops being acceptable.
created_atstring (RFC 3339)

Money -shared across RPP402-002 through RPP402-006:

json
{ "asset": { "type": "stablecoin", "symbol": "USDG", "chain_id": "robinhood-1", "contract": "0x..." }, "amount": "0.002" }

amount is always a decimal string, never a float -floats cannot represent every valid onchain amount exactly, and a payments protocol that lets its own numbers round is a defect (Design Principle 3, DESIGN-SYSTEM.md §3).

A Quote is not itself a reservation -a Service is not obligated to guarantee capacity, only price, until an agent starts a Commerce Session (RPP402-003) that references it.

JSON Schema

json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://rpp402.com/schemas/v1/quote.json",
  "title": "RPP402 Quote",
  "type": "object",
  "required": ["rpp402_version", "id", "service_id", "capability", "price", "expires_at", "created_at"],
  "properties": {
    "rpp402_version": { "type": "string", "const": "1.0" },
    "id": { "type": "string", "pattern": "^quote_[a-zA-Z0-9]{8,}$" },
    "service_id": { "type": "string", "pattern": "^svc_[a-zA-Z0-9]{8,}$" },
    "capability": { "type": "string", "pattern": "^[a-z0-9-]+\\.[a-z0-9-]+$" },
    "price": {
      "type": "object",
      "required": ["asset", "amount"],
      "properties": {
        "asset": { "$ref": "https://rpp402.com/schemas/v1/asset-ref.json" },
        "amount": { "type": "string", "pattern": "^[0-9]+(\\.[0-9]+)?$" }
      }
    },
    "expires_at": { "type": "string", "format": "date-time" },
    "created_at": { "type": "string", "format": "date-time" }
  }
}

Examples

Request:

json
POST https://market-data.example/rpp/quote
{
  "capability": "market-data.quote",
  "params": { "ticker": "NVDA" },
  "settlement_asset": { "type": "stablecoin", "symbol": "USDG", "chain_id": "robinhood-1", "contract": "0x1111...aaaa" },
  "agent_wallet": "0xaaaa...1234"
}

Response:

json
{
  "rpp402_version": "1.0",
  "id": "quote_8f2e9a1c",
  "service_id": "svc_marketdata01",
  "capability": "market-data.quote",
  "price": {
    "asset": { "type": "stablecoin", "symbol": "USDG", "chain_id": "robinhood-1", "contract": "0x1111...aaaa" },
    "amount": "0.002"
  },
  "expires_at": "2026-07-10T18:32:00Z",
  "created_at": "2026-07-10T18:22:00Z"
}

Security

  • A Quote is not authenticated payment authority -possessing a quote_id does not let anyone spend anything. It only becomes economically meaningful once referenced by a Payment Intent (RPP402-004), which requires the agent's own signature.
  • Services SHOULD rate-limit Quote requests per agent_wallet to prevent quote-spam from being used as a free pricing-oracle scrape at the expense of real capacity planning.
  • expires_at MUST be enforced server-side at Payment Intent authorization time (RPP402-004), not just advisory on the client.

Errors

typestatusMeaning
https://rpp402.com/errors/capability-not-found404capability doesn't match any capability the service offers.
https://rpp402.com/errors/asset-not-supported422settlement_asset isn't in the service's supported_assets.
https://rpp402.com/errors/quote-expired410Referenced later (RPP402-003/004) after expires_at has passed.

Best Practices

  • Request Quotes from every candidate Service concurrently when comparison-shopping; don't serialize.
  • Treat a Quote's expires_at as a hard deadline for starting the Commerce Session leg that references it -build in margin, since network latency plus agent decision time both eat into the window.
  • When priced in a tokenized_security asset, re-read RPP402-004 §Settlement Assets before assuming amount means "token quantity" -it may mean "USD notional," and the two require different downstream handling.

Reference Implementation

Schema: @rpp402/protocol - quote.schema.json. Client: session.quote(service, params) in @rpp402/sdk, which requests the Quote and attaches it to the session in one call.


Previous: RPP402-001 -Discovery · Next: RPP402-003 -Commerce Session