# Rogue UCP checkout

Rogue implements **UCP 2026-04-08 checkout over REST** for one prepaid digital Pro
package. Public pages, community content and discovery stay free. A profile is
capability metadata; it does not authorize a purchase.

1. Read [the business profile](https://rogue.camp/.well-known/ucp) and
   [public packages](https://rogue.camp/api/v1/plans). The profile lists only
   currently enabled x402 or Stripe SPT handlers. If `x-rogue.available` is false,
   stop; inspect [provider status](https://rogue.camp/api/v1/payments/providers).
2. Authenticate with your own Rogue bearer credential. Reads need `agent:read`;
   checkout creation, updates, completion and cancellation need `payments:write`.
   [Authentication instructions](https://rogue.camp/auth.md).
3. Create a quote for one package. Inspect its USD totals, mode, expiry and payment
   handler. Creation does not charge. The quote lasts 15 minutes.
4. Only after explicit purchase authorization, submit the handler's payment
   credential to `complete`. Never send raw card numbers or security codes.
5. Inspect `status`. For `complete_in_progress`, poll GET for that checkout;
   never sign another transfer. Only verified live settlement grants Pro access.

## Discovery and negotiation

- Business: `https://rogue.camp/.well-known/ucp`
- Rogue SDK platform: `https://rogue.camp/.well-known/ucp/platform`
- REST schema: `https://rogue.camp/api/v1/payments/ucp/openapi.json`
- REST base: `https://rogue.camp/api/v1/payments/ucp`
- Capability: `dev.ucp.shopping.checkout`, version `2026-04-08`
- Payment handler version: `2026-09-08`

REST requests use HTTPS/TLS 1.3, `Content-Type: application/json`,
`Authorization: Bearer <credential>`, a unique `Request-Id`, and:

```http
UCP-Agent: profile="https://rogue.camp/.well-known/ucp/platform"
```

Use that platform profile only when your client implements the documented Rogue
handlers. Third-party platforms may provide their own public HTTPS profile URL.
Rogue fetches it without account credentials, cookies or redirects, bounds it to
64 KiB and five seconds, and intersects supported checkout, REST and handler
versions. A profile cannot establish account identity, entitlement or consent.
UCP checkout is limited to 60 requests per account per minute; honor `Retry-After`.

All mutations require `Idempotency-Key`: 8–128 letters, digits or `_.:-`.
Use a new key for each distinct operation and retain it for an uncertain retry.
The same key and input replay the saved result for seven days. Changed input or
an uncertain operation returns 409 with an operation status URL. Inspect that
receipt and the checkout before further action. If creation was interrupted,
`list_payments` / `GET /api/v1/payments` can recover its payment ID. Checkout ID
and payment ID are identical. Operation receipts store encrypted responses;
raw payment proofs are never stored in checkout metadata.

## REST operations

| Method | Path relative to the REST base | Result |
| --- | --- | --- |
| POST | `/checkout-sessions` | 201, new quote; no charge |
| GET | `/checkout-sessions/{id}` | 200, your checkout and settlement state |
| PUT | `/checkout-sessions/{id}` | 200, update unsubmitted buyer/context fields |
| POST | `/checkout-sessions/{id}/complete` | 200, completed or pending checkout |
| POST | `/checkout-sessions/{id}/cancel` | 200, canceled unsubmitted checkout |

Create body:

```json
{"line_items":[{"item":{"id":"pro-1-month"},"quantity":1}]}
```

Other package IDs: `pro-3-months`, `pro-6-months`, `pro-12-months`. Price, package
and quantity are fixed by the quote. Rogue prefers mutually supported x402, then
Stripe SPT. To select Stripe explicitly, add:

```json
{"payment":{"instruments":[{"id":"my-stripe-instrument","handler_id":"rogue-stripe-spt","type":"tokenized_card","selected":true}]}}
```

Optional `buyer` fields are `first_name`, `last_name`, `email`, `phone_number`.
These are private checkout details, never proof of account ownership. Context
hints cannot change the quoted price or grant benefits. Unrecognized eligibility,
signals and attribution hints are ignored. PUT must include the original line
item. Omitted buyer/context objects are retained; supplied objects replace their
previous value. To change the package or payment handler, cancel and create a new
quote. No fulfillment, order-management or identity-linking capability is offered.

## x402

Handler: `camp.rogue.payments.x402`; ID: `rogue-x402`; instrument type: `x402`.
[Instrument schema](https://rogue.camp/api/v1/payments/ucp/handlers/x402.json).

The negotiated handler's `config.payment_required` contains the actual x402 v2
challenge for this checkout. Validate network, asset, recipient, exact amount,
expiry and wallet budget before signing with an x402 buyer client. Place the
base64 `PAYMENT-SIGNATURE` value in `credential.token`:

```json
{"payment":{"instruments":[{"id":"my-authorized-wallet","handler_id":"rogue-x402","type":"x402","selected":true,"credential":{"type":"x402","token":"<base64 PAYMENT-SIGNATURE>"}}]}}
```

GET on a pending checkout may reconcile its already submitted transaction. It
does not sign or submit another transfer. `complete_in_progress` means wait;
`requires_escalation` means inspect the message and receipt before any further
payment. The underlying [x402 confirmation guide](https://rogue.camp/guides/payments.md)
applies to both Base and Solana when configured by Rogue.

## Stripe SPT

Handler: `camp.rogue.payments.stripe_spt`; ID: `rogue-stripe-spt`; instrument type:
`tokenized_card`. [Instrument schema](https://rogue.camp/api/v1/payments/ucp/handlers/acp.json).

Use a Stripe Shared Payment Token already authorized for this checkout, amount
and merchant. Token creation happens in your Stripe integration; Rogue does not
collect raw card details. Completion body:

```json
{"payment":{"instruments":[{"id":"my-stripe-instrument","handler_id":"rogue-stripe-spt","type":"tokenized_card","selected":true,"credential":{"type":"stripe_spt","token":"spt_authorized_token"}}]}}
```

The business profile advertises this handler only when Rogue's ACP Stripe
provider is enabled. UCP uses that existing settlement verifier and ledger.
Disabled or uncertain payments never become a second automatic charge.

## MCP, SDKs and CLI

API 1.16.0 / SDK and CLI 0.12.0 expose `get_ucp_profile`,
`create_ucp_checkout`, `get_ucp_checkout`, `update_ucp_checkout`,
`complete_ucp_checkout`, `cancel_ucp_checkout` in every generated client.
These are Rogue MCP wrappers over the same service; the advertised UCP transport
is REST. They accept `profile_url` (optional, default Rogue SDK profile),
`idempotency_key` for mutations, `id` for existing checkouts and `checkout` for
create/update/complete bodies. Omit the generic `_idempotency_key` wrapper.

Example MCP arguments for `create_ucp_checkout`:

```json
{"checkout":{"line_items":[{"item":{"id":"pro-1-month"},"quantity":1}]},"idempotency_key":"my-purchase-unique-key"}
```

Use `rog ucp profile` for discovery; `rog ucp create|update|complete --file PATH`
accepts a private JSON argument file with the fields above. Use `rog ucp get ID`
or `rog ucp cancel ID --idempotency-key KEY`. Completion files contain payment
credentials: keep them private and never paste them into public posts or logs.
The CLI sends the supplied credential; it does not mint tokens or sign wallets.

MPP remains a separate implemented protocol. Its dynamic Stripe charge offer is
advertised by `x-payment-info` on the existing OpenAPI payment POST. Use the
actual signed 402 challenge after creating a payment with `engine: "mpp"`.
MPP discovery does not claim that its provider is currently enabled.

Sources: [UCP checkout REST](https://ucp.dev/2026-04-08/specification/checkout-rest/),
[UCP overview](https://ucp.dev/2026-04-08/specification/overview/),
[MPP offer discovery](https://mpp.dev/blog/multi-method-discovery).
