What Relay does.
Relay is the operating layer around Stellar x402 payments. It is not a wallet and not a new protocol. Payment payloads stay standard x402; Relay adds the parts an autonomous buyer needs before and after the payment.
- Discovery — a Bazaar-compatible catalog of machine-payable resources with capability, schema, network, asset, and price metadata.
- Verification — active probes that check liveness and whether a service returns a valid x402 challenge.
- Routing — deterministic provider selection with explicit rejection reasons.
- Policy — hard spend and quality limits evaluated before any payment is authorised.
- Receipts — a signed record linking intent, route, payment, and response hash.
This deployment runs stellar:testnet. Mainnet operation uses separate relayer credentials, a separate signing account, and its own USDC contract configuration.
From zero to a paid call.
Every step below runs against the live deployment. No API key is required for discovery, routing, or policy evaluation.
1. Check health and supported payment kinds
curl https://api.relayx402.xyz/health/ready
curl https://api.relayx402.xyz/x402/supportedconst res = await fetch("https://api.relayx402.xyz/x402/supported");
const { kinds } = await res.json();
// [{ scheme: "exact", network: "stellar:testnet" }, ...]
console.log(kinds);import httpx
kinds = httpx.get("https://api.relayx402.xyz/x402/supported").json()["kinds"]
print(kinds)2. Search for a service by capability
curl -X POST https://api.relayx402.xyz/v1/search \
-H 'content-type: application/json' \
-d '{"capability":"rwa.asset.inspect","network":"stellar:testnet","asset":"USDC","maxPriceUsd":0.005}'const { resources } = await fetch("https://api.relayx402.xyz/v1/search", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
capability: "rwa.asset.inspect",
network: "stellar:testnet",
asset: "USDC",
maxPriceUsd: 0.005
})
}).then((res) => res.json());import httpx
resources = httpx.post("https://api.relayx402.xyz/v1/search", json={
"capability": "rwa.asset.inspect",
"network": "stellar:testnet",
"asset": "USDC",
"maxPriceUsd": 0.005,
}).json()["resources"]Price filters compare against worst-case spend, so an upto ceiling can never slip past maxPriceUsd.
3. Route by policy
State constraints instead of hard-coding a vendor. Relay returns the selection, ranked fallbacks, and a reason code for every rejection.
curl -X POST https://api.relayx402.xyz/v1/routes \
-H 'content-type: application/json' \
-d '{"capability":"rwa.asset.inspect","constraints":{"networks":["stellar:testnet"],"assets":["USDC"],"maxPricePerRequestUsd":0.005,"minProviderReliability":0.99},"optimizeFor":"balanced"}'const route = await fetch("https://api.relayx402.xyz/v1/routes", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
capability: "rwa.asset.inspect",
constraints: {
networks: ["stellar:testnet"],
assets: ["USDC"],
maxPricePerRequestUsd: 0.005,
minProviderReliability: 0.99
},
optimizeFor: "balanced"
})
}).then((res) => res.json());
if (!route.selected) {
// Nothing qualified. route.rejected explains why, per provider.
console.error(route.rejected);
}import httpx
route = httpx.post("https://api.relayx402.xyz/v1/routes", json={
"capability": "rwa.asset.inspect",
"constraints": {
"networks": ["stellar:testnet"],
"assets": ["USDC"],
"maxPricePerRequestUsd": 0.005,
"minProviderReliability": 0.99,
},
"optimizeFor": "balanced",
}).json()
if not route["selected"]:
print(route["rejected"])4. Trigger a real x402 challenge
curl -i -X POST https://atlas.relayx402.xyz/atlas/v1/rwa/inspect \
-H 'content-type: application/json' \
-d '{"asset":"USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN"}'
# HTTP/1.1 402 Payment Required
# PAYMENT-REQUIRED: <base64-encoded x402 challenge>const res = await fetch("https://atlas.relayx402.xyz/atlas/v1/rwa/inspect", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ asset: "USDC:GA5ZSE..." })
});
// x402 v2 carries the challenge in a base64 PAYMENT-REQUIRED header,
// not WWW-Authenticate.
const challenge = JSON.parse(atob(res.headers.get("payment-required") ?? ""));
console.log(challenge.accepts[0]);
// { scheme: "exact", network: "stellar:testnet", amount: "10000", ... }
// 10000 atomic units at 7 decimals = 0.001 USDCimport base64, json, httpx
res = httpx.post(
"https://atlas.relayx402.xyz/atlas/v1/rwa/inspect",
json={"asset": "USDC:GA5ZSE..."},
)
challenge = json.loads(base64.b64decode(res.headers["payment-required"]))
print(challenge["accepts"][0])Your buyer signs locally — Relay never holds a private key.
Standard x402 endpoints.
Relay settles on-chain itself. These three routes speak stock x402 — no Relay-specific payment fields are added or required — and network fees are sponsored, so a buyer needs only the asset being paid.
Protocol correctness (authorization-entry validation, simulation-event checking, fee ceilings) is delegated to the canonical @x402/stellar implementation. Reimplementing it would add risk without adding value. What Relay adds is the operator layer: idempotency, a durable settlement journal, sponsored-fee budgets, and policy enforcement.
/x402/supported
Supported x402 payment kinds and signers for the configured network.
/x402/verify
Verify a payment payload without settling it.
/x402/settle
Submit a verified payment for settlement.
Because the payload is stock x402, any @x402/stellar client works against these endpoints unmodified.
Multiple backends, with failover
Relay does not implement verify or settle itself, so a single hard-coded facilitator would be a single point of failure. Configure several and Relay picks one that actually advertises the requested network and scheme, falling through on failure.
RELAY_FACILITATORS='[
{"id":"openx402","url":"https://facilitator.stellarx402.xyz"},
{"id":"openzeppelin","url":"https://channels.openzeppelin.com/x402/testnet","apiKey":"..."}
]'curl https://api.relayx402.xyz/x402/facilitators/x402/supported returns the union of every healthy backend's capabilities, de-duplicated by network and scheme. An unreachable backend is marked unhealthy and skipped rather than failing the request.
Policy that a broken agent cannot skip.
Canonical x402 invariants are per-payment and protocol-level: the recipient is bound, and for upto the settled amount cannot exceed the authorized maximum. Nothing in the protocol constrains which provider an agent pays, how much it spends in aggregate, or whether the endpoint has ever been shown to work.
Those are buyer concerns, and they are normally enforced buyer-side — which means an agent that is buggy, compromised, or prompt-injected simply skips them. Relay checks them on the settlement path instead.
POST https://api.relayx402.xyz/x402/settle
{
"paymentRequirements": {
"payTo": "GAYVRGN5...",
"amountUsd": 5,
"relayPolicy": { "maxPricePerRequestUsd": 0.005 }
}
}
403 Forbidden
{
"error": "POLICY_DENIED",
"code": "PRICE_EXCEEDS_LIMIT",
"message": "Worst-case spend $5 exceeds per-request limit $0.005"
}{
"networks": ["stellar:testnet"],
"assets": ["USDC"],
"schemes": ["exact"],
"maxPricePerRequestUsd": 0.005,
"minConfidence": 0.5,
"requireTransactionVerified": false,
"denyProviders": ["prv_untrusted"]
}Limits are measured against worst-case spend. For an upto option that means the authorized ceiling, not the amount the seller currently claims — so a $0.005 cap can never authorize a $5.00 payment.
Refusal codes
PRICE_EXCEEDS_LIMIT— worst-case spend above the per-request cap.WINDOW_LIMIT_EXCEEDED— aggregate spend across providers would exceed the window budget.PAYEE_NOT_VERIFIED— Relay has never observed a valid payment interface at the payee.NO_VERIFICATION_EVIDENCE— no probe evidence exists for this payee at all.CONFIDENCE_LIMIT/VERIFICATION_TOO_OLD— evidence too thin or too stale.NETWORK_NOT_ALLOWED/ASSET_NOT_ALLOWED/SCHEME_NOT_ALLOWED/PROVIDER_DENIED.
Sponsored-fee budgets
Relay pays the Stellar network fee for every settlement it submits, which is a standing invitation to drain the sponsor account. A global ceiling and a per-principal ceiling bound the damage over a rolling window, charged at the fee ceiling rather than the actual fee so the budget can never be under-counted. Exceeding it returns 429 with FEE_BUDGET_EXHAUSTED.
Evidence, not listings.
A scheduler probes every catalogued resource on an interval and records what it sees. Metrics are recomputed from that history — nothing is assumed, carried over, or seeded.
What a probe checks
A healthy payment interface requires a 402 carrying a decodable x402 challenge with at least one acceptable payment option. The advertised price, asset, and network are captured from that challenge, which is what makes price-drift detection possible.
How confidence works
Confidence combines sample size with freshness. Twenty stale probes and one fresh probe are both weak evidence, for different reasons — so a resource Relay has not seen recently decays to zero rather than coasting on old data.
- reliability — 24-hour availability multiplied by payment-interface success rate.
- confidence — 0 until there is current evidence; approaches 1 with sustained recent probes.
- transactionSuccessRate — economic probes only. It stays 0 rather than being back-filled from liveness data.
- priceConsistency — how often the advertised price matches the most recent observation.
Verification levels
Levels are earned from evidence, never declared. A resource starts at DISCOVERED and cannot reach level 4 from a single successful probe — CONTINUOUSLY_VERIFIED requires sustained evidence over time.
curl https://api.relayx402.xyz/v1/resources/svc_atlas_inspect/metrics{
"reliability": 1,
"confidence": 0.05, // one observation so far
"paymentInterfaceSuccessRate": 1,
"observedPriceUsd": 0.001, // read from the live challenge
"p95LatencyMs": 525,
"observationCount": 1,
"lastVerified": "2026-08-11T14:35:12.884Z"
}A resource with no evidence reports confidence: 0, and policies reject it with INSUFFICIENT_DATA. That is a truthful answer, not a placeholder.
/v1/validate
Probe an endpoint now and record the observation.
/v1/resources/:id/metrics
Metrics computed from recorded observations.
/v1/resources/:id/observations
The raw evidence behind the metrics.
Find services machines can buy.
Discovery answers which resources exist and what they expose. Records carry provider, price, network, asset, input and output schema, status, and verification level.
/v1/resources
List every catalog record.
/v1/resources/:id
Fetch one record with its current metrics.
/v1/search
Filter by capability, network, asset, and max price.
/v1/validate
Probe an endpoint and record the observation.
/v1/resources/:id/metrics
Reliability, confidence, latency, and success rates.
/v1/resources/:id/observations
Raw probe history behind the metrics.
Spend limits that are enforced.
An agent states constraints instead of hard-coding a vendor. Relay filters candidates, ranks the survivors, and returns the selection alongside fallbacks and a reason code for every rejection.
{
"capability": "rwa.asset.inspect",
"constraints": {
"networks": ["stellar:testnet"],
"assets": ["USDC"],
"maxPricePerRequestUsd": 0.005,
"minProviderReliability": 0.99,
"minConfidence": 0.75,
"requireTransactionVerified": true
},
"optimizeFor": "balanced"
}
optimizeFor accepts balanced, cheapest, fastest, or reliable. Rejections come back as codes such as PRICE_EXCEEDS_LIMIT, RELIABILITY_LIMIT, or SERVICE_OFFLINE, so a refusal to spend is always explainable.
/v1/routes
Rank eligible providers under a policy.
/v1/policies/evaluate
Dry-run one policy against one resource.
An auditable paper trail.
A commerce receipt binds the request intent, the routing decision, the service that was chosen, the payment metadata, and a hash of the response. It answers “why did this agent spend this money here” after the fact.
Verifiable without trusting Relay
Receipts are signed with an Ed25519 Stellar keypair over the canonical JSON of the receipt body. The signing public key travels with the receipt, so anyone holding one can verify it offline — no shared secret, no call back to Relay.
import { Keypair } from "@stellar/stellar-base";
// Deterministic serialization: keys sorted, undefined dropped.
const canon = (v) =>
v === null || typeof v !== "object"
? JSON.stringify(v ?? null)
: Array.isArray(v)
? "[" + v.map(canon).join(",") + "]"
: "{" + Object.entries(v)
.filter(([, x]) => x !== undefined)
.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
.map(([k, x]) => JSON.stringify(k) + ":" + canon(x))
.join(",") + "}";
const { relaySignature, relaySigner, signatureAlgorithm, ...body } = receipt;
const valid = Keypair.fromPublicKey(relaySigner).verify(
Buffer.from(canon(body), "utf8"),
Buffer.from(relaySignature, "base64")
);# Relay will check it for you too
curl https://api.relayx402.xyz/v1/receipts/rcpt_2d146c5673e517e427204e87/verify
# And the signing key is published
curl https://api.relayx402.xyz/v1/receipts/signerDeployments without a signer key fall back to HMAC. Those receipts are attestations, not proofs — only Relay can check them. /v1/receipts/signer tells you which mode a deployment is in.
/v1/receipts
Create a signed receipt for a completed purchase.
/v1/receipts/:id
Fetch a receipt by id.
/v1/receipts/:id/verify
Check a receipt's signature.
/v1/receipts/signer
The Ed25519 public key receipts are signed with.
The first paid vertical.
Atlas is x402-gated Stellar RWA intelligence — the reference implementation of a service that is discoverable, verifiable, routable, and payable through Relay.
/atlas/v1/rwa/inspect
Asset identity, issuer signals, metadata, and technical state.
/atlas/v1/rwa/changes
Recent observable changes for an asset.
/atlas/v1/rwa/compliance
Observable technical restrictions, without legal conclusions.
/atlas/v1/rwa/eligibility
Technical wallet eligibility signals.
Discovery for agents.
The MCP server mirrors the public HTTP surface so an MCP client can find and qualify a paid service without bespoke integration code.
search_resources
get_resource
validate_endpoint
route_resource
get_resource_health
get_resource_metrics
Claims you can check.
Relay settles real payments. These are the transactions, on a public explorer, produced by the harness in the repository rather than by hand.
Balance deltas confirm both the transfer and fee sponsorship: the seller gained exactly the amount paid, and the buyer lost exactly that amount with no fee deducted. The buyer was the canonical @x402/fetch client with no Relay-specific code, so these are wire-compatibility results too.
upto, pubnet settlement, and a security audit are not demonstrated. Authorization-required, clawback-enabled, and paused assets are untested. The repository's EVIDENCE.md lists every gap explicitly.
Every public endpoint.
Generated from the same OpenAPI 3.1 document the API serves, so this table cannot drift from the implementation.
Health
/health/live
Check liveness
/health/ready
Check readiness
/health/dependencies
Inspect backing services
Facilitator
/x402/supported
List supported payment kinds
/x402/verify
Verify a payment payload
/x402/settle
Settle a verified payment
/x402/facilitators
Inspect facilitator health
Discovery
/v1/resources
List catalogued resources
/v1/resources/{id}
Resolve one resource
/v1/search
Search resources
Verification
/v1/validate
Probe an endpoint
/v1/resources/{id}/metrics
Get resource metrics
/v1/resources/{id}/observations
List raw probe observations
Routing
/v1/routes
Route by policy
/v1/policies/evaluate
Dry-run a policy against one resource
Receipts
/v1/receipts
Create a commerce receipt
/v1/receipts/signer
Get the receipt signing key
/v1/receipts/{id}
Fetch a receipt
/v1/receipts/{id}/verify
Verify a receipt signature
Protocol references.
Use these docs for Relay's hosted infrastructure and product APIs. Use upstream documentation for protocol-level semantics and SDK behaviour.