carousell/rctp

Draft 0.5 proposal: open to every UCP agent

Status: accepted by the editor as the implementation baseline on 10 November 2026 (see Editor's decisions). Lazy consensus under GOVERNANCE runs until 17 November 2026. The normative text is rctp-draft-0.5.md, which wins where the two differ. Review in #91, #92 and #94 · Proposed 10 November 2026 · Changes Draft 0.4 sections 4.1, 5.3, 6.1, 6.2, 8.4, 14 and 17, the term-set registry, and conformance vectors S1, V11 and V28, if adopted

Section numbers in brackets, such as [4.1], refer to Draft 0.4. Key words follow BCP 14 and apply to the proposed text only.

The story

Draft 0.4 told RCTP's story as a protocol mechanism: agents propose, the marketplace decides, signatures prove. That is how a call is handled, not why anyone would use RCTP. Draft 0.5 tells it as what each party gets:

Delegated by consent A person hands their agent the whole trade, with their consent: what it may do, under which limits and until when. They can revoke it at any time.
Transparent profiles Every seller and every unique item has a profile both sides can check: the seller's track record in bands (Party Credential, [11.1]), and the item's passport and history (Item Passport, [11.3]).
Guardrails, enforced The marketplace's gateway, and every party in the ecosystem, enforces the seller's limits on every call and keeps a signed record of what happened.

Each change below serves this story: authentication anyone can adopt (delegation), terms a seller can state in plain language (consent), and policy the marketplace owns (guardrails).

Key highlight

RCTP authenticates agents as UCP does. RCTP drops its stricter "every call must be signed" rule. Calls authenticate the way UCP allows: signatures are recommended, and OAuth, API keys or mTLS are accepted where the marketplace chooses. Plugins on hosts such as Grok, Cursor and similar can use OAuth. Every call and deal event records how it was authenticated. Buyer verbs need nothing beyond UCP plus AP2 or another payment protocol. The seller's private floor, the grant, revocation and the deal record are unchanged.

The principle behind it: the profile defines verbs, scopes and invariants, and records facts; marketplaces and platforms set policy. Three changes follow:

  1. Authenticate as UCP does, and record how (section 2). This removes a rule that is stricter than UCP's.
  2. Tier policy belongs to the marketplace (section 3). The tier table becomes reference defaults.
  3. Listing Terms in plain language (section 4). A seller tells their agent two prices, and the marketplace guarantees the lower one.

1. Why change

Draft 0.4 is stricter than the protocol it profiles, in two places.

  • Authentication. [4.1] makes every agent request carry an HTTP Message Signature, and [5.3] binds every grant token to the signing key. UCP v2026-08-25 says platforms SHOULD sign requests and that "alternative authentication mechanisms (API keys, OAuth, mTLS) may be used instead" (Message Signatures: When Signatures Apply). Whatever the mechanism, the business MUST confirm that the authenticated principal may act for the profile in UCP-Agent (Overview: Identity Binding). Agents on plugin hosts sign the seller in with OAuth and receive a grant, but cannot sign each request. Under Draft 0.4 they are refused, and conformance vector S1 requires that refusal.
  • Policy. [8.4] fixes a default and an allowed set of tiers for every verb. offer.accept defaults to ask (OI-2), and listing.create may only be ask. A marketplace whose sellers already let their agent list and accept automatically cannot offer the same experience without failing the profile.

Neither strictness protects what RCTP exists to protect. The floor is enforced on every call whatever the authentication, and the seller's grant is checked live and is revocable either way. The strictness does, however, stop marketplaces and agents from adopting the profile.

2. Authenticate as UCP does, and record how

Proposed text.

  1. [4.1.1] An agent request to an enforcement point MUST authenticate by a mechanism UCP allows: HTTP Message Signatures (RECOMMENDED), OAuth 2.0, API keys or mTLS. The marketplace chooses which mechanisms it accepts. The request carries UCP-Agent, and the enforcement point applies UCP's identity binding.
  2. [5.3.1] When the request is signed, the grant's access token MUST be sender-constrained with cnf.jkt, and the signature MUST cover authorization. When it is not signed, the token is the request's OAuth credential.
  3. [5.3.2] The enforcement point checks on every call that the grant is active and unexpired and that the verb's scope is granted. It checks cnf.jkt against the signing key only when the token is bound.
  4. Record. The decision and every deal event carry authenticated_by (http_signature, oauth, api_key or mtls) and the caller's UCP-Agent profile. Until a draft defines these fields, implementations use x-rctp-authenticated-by.
  5. INV-7 becomes "a revoked or expired grant fails the next call", dropping "signed".
  6. [14] The threat "agents bypass the enforcement point" is mitigated by "every agent path goes through the enforcement point; which authentication mechanisms it accepts is the marketplace's choice, and each call records its mechanism", replacing "marketplaces block unsigned automation".

Buyer verbs need nothing RCTP-specific. offer.create is an ordinary UCP platform call and authenticates as above. Checkout and payment authority come from UCP and AP2, or another payment protocol, which carry their own proof: an AP2 mandate is signed for the buyer, not with the agent's request key. RCTP does not duplicate that proof.

No separate category for hosted agents. A hosted MCP server that signs for its clients (#89) is a UCP platform signing with its own key and profile. The record already shows that.

What it costs. Without a signature, the record proves "OAuth client X, acting for profile Y", not the content of each request, and a leaked token works without a key. What each mechanism may do is the marketplace's policy (section 3); the profile states the fact.

3. Tier policy belongs to the marketplace

Proposed text.

  1. [8.4] The Default and Allowed columns become reference defaults, like the reference offer budget [8.5]. A marketplace declares its own default_tier and allowed_tiers for each scope in the config.scopes of its dev.ucp.common.identity_linking entry, as [5.2] already has it publish them. It MAY vary them by authentication mechanism. The seller chooses within what the marketplace allows, at consent and later.
  2. OI-2 ("offer.accept defaults to ask") becomes the reference default, not a requirement.
  3. listing.create MAY be auto where the marketplace allows it. What remains fixed is mechanical: only the seller enters private terms, on a Trusted Surface (INV-5). A listing created automatically has no terms until the seller adds them, and [6.5] already covers that state: no agent negotiation until terms exist.
  4. listing.set_terms has no tier. It always opens the seller's hosted page, in the same way that offer.create has no tier.

4. Listing Terms in plain language

What the seller should experience: "List it at 500, don't go below 400." The seller says that to their agent once, confirms it once, and gets one guarantee: the marketplace never sells below 400, whatever anyone says to the agent. Everything between 400 and 500 is the agent's to negotiate.

Draft 0.4 taxes that sentence three times:

  • The seller types the price twice. [6.1.6] forbids the agent from pre-filling the terms form, so the price the seller told their agent must be typed again on the hosted page.
  • The seller is asked for marketplace defaults. Every term set requires available_until, fulfillment_options, payment_terms, release_condition and deliver_within_days. They are public, and the marketplace already has a value for each category.
  • "Counter" means two things. The optional private counter term, a fixed price returned with below_floor, sits next to the offer.counter verb, so sellers and implementers read it as a second price they must set.

Proposed text.

  1. Two prices are the minimum. The minimum Listing Terms are the public list price, already on the listing, and a private floor, which interfaces call the "lowest price". Every other term is optional.
  2. The agent carries what the seller said. Replace [6.1.6]: a seller agent MAY propose terms values, the floor included, in listing.create and listing.set_terms. The marketplace shows them pre-filled and editable on its confirmation (hosted page or app), and stores only what the seller confirms. This is the expected flow. A marketplace MAY still ask for the floor directly instead; that is its policy.
  3. Public terms default from the marketplace. required in a term set means "has a value", not "the seller types it". The marketplace fills each public term from its category defaults, and the seller changes them only if they want to.
  4. The counter term leaves the starter term sets. goods.small/1 and vehicles/1 drop it. A below_floor refusal carries nothing private; it MAY point to the public list price. A later term set can bring a fixed counter back if marketplaces ask for it.
  5. Agent counter-offers are the marketplace's option. A marketplace that does not support seller counter-offers leaves dev.rctp.deal:offer_counter out of its config.scopes, and agents read that from discovery. Floor defence alone is a complete profile: below the floor is refused; at or above it, the offer goes to the seller or their agent to accept or decline.

Invariants, restated (the guarantee is unchanged; the wording now matches what a marketplace can promise):

  • INV-1 becomes "the marketplace never discloses private terms to any agent". A seller may tell their own agent; that is the seller's choice. An agent that knows the floor can still be talked into revealing it, and a marketplace that wants to rule that out uses item 2's option. Either way, no sale happens below the floor.
  • INV-5 becomes "only the seller confirms grants and terms, on a Trusted Surface; an agent may propose them".

5. What stays fixed

These are facts about a safe trade. They are not a security posture, so this proposal does not touch them.

  • INV-1 (restated in section 4): the marketplace never discloses private terms to any agent. A low offer is refused below_floor.
  • INV-2: an ask that expires is a decline.
  • INV-5 (restated in section 4): only the seller confirms grants and terms, on a Trusted Surface.
  • INV-6: an accepted offer becomes a single-use, business-signed checkout.
  • INV-8 and INV-9: no custom cryptography, and no personal data in RCTP objects.
  • Every price check against the floor, live grant checks and revocation, the decision on every call, and the hash-chained deal record.
  • Webhooks stay signed, as UCP requires.

6. Conformance

  • S1 becomes: an unauthenticated request is refused. A marketplace that accepts only signatures still answers signature_invalid.
  • New vectors: an OAuth-authenticated call is admitted and recorded with authenticated_by: oauth; a revoked grant fails the next call under each mechanism; listing.set_terms always returns ask.
  • Profile-dependent vectors: vectors that assert a [8.4] default read the marketplace's published tiers instead of the table. V11 and V28, which exercise offer.counter, run only where the marketplace offers that scope.
  • Terms vectors: a proposed floor appears pre-filled and only the confirmed value is stored; a below_floor refusal carries no private value.

7. Implementing now: build on Draft 0.5

New implementations start on Draft 0.5, not on Draft 0.4, so that a first phase carries no workarounds for rules that are about to change. The plan, tracked in milestones Draft 0.5 text, v0.3.0-draft.5 reference and Research preview:

  • Tuesday 10 November 2026: the repository syncs to Draft 0.5 (normative text and the v0.3 binding).
  • By Friday 13 November 2026: the reference implementation and simulator on Draft 0.5 (release v0.3.0-draft.5), the base sandbox and tests, and the rctp.dev research preview site.

Lazy consensus still runs to 17 November. Anything it changes is applied to Draft 0.5 before v0.3.0-draft.5 is tagged.

A first marketplace phase can be this small and still be complete:

  • agents authenticate by OAuth or signatures, and each call records which (section 2);
  • the marketplace's own tiers, including auto where it chooses (section 3);
  • two prices per listing, pre-filled from what the seller told their agent and confirmed once (section 4);
  • floor defence only: no offer.counter and no counter term (section 4, items 4 and 5);
  • public terms from category defaults.

Until rctp-draft-0.5.md fixes the field names (open question 3), use the names in this proposal. They change at most once, when the normative text lands.

8. Open questions

  1. INV-3. Do deal.sign_contract and account.update stay fixed forbid? Recommendation: yes. Signing contracts and changing account details are outside a trade, so the rule concerns scope, not posture. The editors decide.
  2. Plugin profiles. UCP needs a UCP-Agent profile for every caller. Does a plugin without its own profile use one published by its developer, or one the marketplace hosts for each registered OAuth client?
  3. Field names: authenticated_by, on the decision and on the deal event.

Editor's decisions

Recorded on 10 November 2026 by the editor. They stand unless an objection is raised during lazy consensus.

  1. The story is delegated by consent, transparent profiles, guardrails enforced (see The story). It replaces agents propose, the marketplace decides, signatures prove on the site and in the docs. Reason: RCTP's value is full delegation that people can trust. It does not lie in how a call is handled.
  2. Draft 0.5 is the implementation baseline. The first marketplace implementation builds on it directly. Reason: a clean first phase, without interim workarounds for rules that this proposal removes.
  3. The seller's agent may know the floor (was open question 4). Pre-fill is the expected flow (section 4, item 2). Reason: everything about the item reaches the marketplace through the seller's agent anyway, so hiding the floor from that one agent buys little and costs the seller a second entry. The value RCTP adds is that the marketplace never discloses the floor to any other agent and never sells below it, backed by the seller and item profiles and the marketplace's data. Simple is worth more than that marginal secrecy.
  • #78: Draft 0.5 proposal for credentials presented by cloud agents through Delegate SD-JWT. It is independent of this proposal, and both target Draft 0.5.
  • #80: the MCP route and the research preview.

Source: spec/proposals/draft-0.5-open-to-every-ucp-agent.md