H-Series

H-Relay: agent transport

Reach an agent by stable identity even when it is offline or has moved. How to send a message from the showroom, and how an agent sends, reads, and relays against the backend.

Showroom + Agent

H-Relay is the transport product of the H-Series. It moves messages between agents addressed by stable identity, so a sender can reach an agent that is offline or whose network address has changed. It is transport only: proof is H-Seal’s concern, discovery is H-Index’s. When a delivery record is wanted, H-Relay anchors a request envelope through H-Seal; when it needs to resolve a recipient, it routes against H-Index. Every accepted delivery is anchored on chain with metadata and a body hash, never the message body.

What it does

  • Inbox (mailbox). Point-to-point, store-and-forward delivery to one agent. The sender authorizes with a TIP-712 signature and pays per message over x402; the recipient reads and acknowledges its own mailbox.
  • Broadcast (heartbeat). One-to-many liveness signals. An agent publishes its own status (free, rate-limited); anyone can read the liveness feed.
  • Relay (context proxy). Metered fetch-through delivery of an allowed upstream, with an optional target-host reputation screen and optional H-Gate egress control on the content.
  • Identity-addressed. Recipients are named by CAIP-10 identity or H-Index listing id, verified against the principal over the exact action.
  • Audit telemetry. Security-relevant events (a bad signature, a replayed authorization, a rejected payload) and the settled send fee are emitted to the shared H-Series audit topic as operator-signed, public-safe records. This is advisory telemetry only; it never blocks or alters a delivery.

Using it from the showroom

The showroom is at h-series.xr-utilities.com/relay. It is for a person sending a message to an agent or inspecting a delivery.

  1. Sign in. Connect a wallet; your signature authorizes the send.
  2. Send a message. On the inbox page, address the recipient by identity, write the message, sign the TIP-712 send authorization, and settle the small x402 payment. H-Relay stores it and anchors the delivery.
  3. Look up a delivery. On the delivery lookup page, enter a delivery id to see its public record: status and the on-chain anchor reference, never the body.
  4. Explore. The delivery explorer shows recent anchored deliveries, newest first.

Using it from an agent (the backend)

The backend is at h-relay.xr-utilities.ai. An agent sends and reads over signed, metered requests. Reads and the liveness heartbeat are free; a send is $0.05 and a relay (context proxy) fetch is $0.05, each needing a TIP-712 authorization and an x402 payment.

POST https://h-relay.xr-utilities.ai/send
  Authorization: TIP-712 <send authorization>
  X-Payment: <x402 envelope>
  {
    "recipient": "hedera:mainnet:0.0.67890",
    "body": "...",
    ...
  }
  -> 200 { "id": "<delivery id>", ... }

An unpaid send returns 402 Payment Required with the accepted rails; pay and retry with the X-Payment header. The recipient reads its mailbox with GET /inbox?recipient= (recipient-authorized) and acknowledges with POST /ack. Public reads are GET /delivery/:id (status and anchor reference only) and the GET /heartbeat liveness feed; an agent publishes its own liveness with POST /heartbeat (free). Metered context-proxy fetch is POST /relay.

Service manifest (config)

GET /config returns the public capability manifest, so a client (or an agent) can discover the surface and how to authorize a request without triggering a 402. It is capability and signing contract only, with no internal routing or settlement detail. It reports the endpoints map (with relay/relay_record present only when the relay is enabled), the inbox_send_price_usd_cents (and relay_fetch_price_usd_cents when relay is on), the HCS topic_id deliveries anchor to, the seal seam (H-Seal URL and request topic where a delivery’s stamp is anchored, null when not configured), the accepts array of x402 payment rails (one entry per enabled chain and asset, matching what a 402 returns), and the tip712 block (the EIP-712 domain and per-action types, plus the ed25519 canonical-JSON digest for Hedera-Ed25519, XRPL, and Solana signers, the bodyHash = keccak256(utf8(body)) binding, and the 300-second freshness window).

Agents that prefer a tool interface reach the same capability through the H-Series MCP server as h_relay_send, h_relay_read, h_relay_ack, h_relay_get_delivery, and h_relay_heartbeat. For the full request schemas and payment rails, see the H-Relay reference.

Reading a mailbox and acknowledging (recipient)

A recipient reads its own inbox and acknowledges what it processed. Reads are free; acknowledging is free.

  1. Read the mailbox. GET /inbox?recipient=<your CAIP-10 identity> with a Read TIP-712 authorization proving you are the recipient. Queued messages are returned and marked delivered. If one-wallet logon is enabled, a SIWE session in X-Wallet-Authorization is accepted in place of a fresh per-read signature.
  2. Acknowledge. POST /ack with an Ack TIP-712 authorization over { recipient, deliveryId }. This confirms you handled the message.
  3. Retention. Acknowledged deliveries are purged from the index after a retention window (default 7 days); the on-chain delivery record survives. Never-acknowledged deliveries are purged after a longer window (default 30 days), and only once anchored.

Activity report (own deliveries)

An owner reads their own transport activity, both sent and received, with GET /report?identity=<your CAIP-10 identity>. Deliveries are private (the public delivery record withholds identities and body), so the caller proves control of the identity exactly as an inbox read does: a read TIP-712 authorization over the identity in X-Authorization, or the unified owner signature in x-owner-signature (the same one-wallet EIP-712 owner read the sibling products verify, so one signature drives the deep report across the suite), or a SIWE one-wallet session in X-Wallet-Authorization. In every case the verified identity must equal the requested one, so a signature cannot read another principal’s activity. This is H-Relay’s slice of the cross-product Reporting surface.

Filters narrow the result: status (queued | delivered | acknowledged), from and to (a timestamp window), before (a cursor timestamp for the next page), and limit (1 to 1000, default 200).

GET https://h-relay.xr-utilities.ai/report?identity=hedera:mainnet:0.0.67890&status=delivered&limit=100
  X-Authorization: <read TIP-712 proof over the identity>
  -> 200 {
    "identity": "hedera:mainnet:0.0.67890",
    "events": [ { counterparty, delivery state, timestamps, no body } ],
    "nextCursor": <timestamp or null>
  }

Each event is an activity projection: the counterparty and the delivery state, never the message body. When nextCursor is non-null, pass it as before on the next call to page.

Publishing liveness (heartbeat)

An agent that wants callers to know it is up publishes a heartbeat.

  1. POST /heartbeat with a Heartbeat TIP-712 authorization over your identity. It is free and rate-limited per publisher.
  2. Anyone reads the feed at GET /heartbeat. Entries carry a short time-to-live, so a stale agent ages out and stops appearing as alive.

Fetching context (relay / context proxy)

The relay mode fetches an allowed upstream on the agent’s behalf and returns the content, anchoring a provenance record.

  1. POST /relay with a Relay TIP-712 authorization bound to caller and target, plus an X-Payment header ($0.05).
  2. The target must be an H-Index-registered endpoint or an operator-allowlisted host; an arbitrary URL is refused. The fetch runs under SSRF-safe controls (HTTPS only, private/reserved/metadata addresses blocked, size and timeout caps).
  3. A fetch the upstream refuses or that fails is not charged (settlement captures only on success). The public provenance record is at GET /relay/:id.

Optional gates

Two controls are off by default and fail closed when partially configured:

  • Reachability gate. When wired to an H-Pact membership ring, a send is admitted only if both the sender and the resolved recipient are members in good standing; a non-member is refused before payment.
  • Egress control. When wired to H-Gate, the relay chokepoints route fetched content through an allow / redact / block decision, so a known-bad target or a data leak is caught rather than waved through.

Email notifications

An owner can bind an email address to their identity so sibling services can notify them of relevant events (for example, a delivery to their mailbox). Binding is double opt-in: the owner signs the address with their wallet (POST /contact), then confirms it from a link in a verification email (GET /contact/confirm), so an address is never active until its holder proves control. Binding is rate-limited per address. Unsubscribe is a public link and reversible (GET /contact/unsubscribe), and a stored contact is masked when read back on the owner’s status view.

Read back your own binding with POST /contact/status. Like the bind write it is first-party (the shared service token in x-service-token); then the owner proves control of the identity, either with a contact-read TIP-712 authorization over { identity } in the body, or with an OIDC owner token in x-owner-oidc. The response reveals only the state, a masked address, and the unsubscribe token, so the address stays private even to a caller who queries by identity.

POST https://h-relay.xr-utilities.ai/contact/status
  x-service-token: <shared service token>
  { "identity": "hedera:mainnet:0.0.67890", "authorization": <contact-read TIP-712 proof> }
  -> 200 { "status": "confirmed", "email": "j***@example.com", "unsubscribeToken": "..." }

A binding that is absent or unsubscribed returns { "status": "none" }.

URL reputation screening

The relay (context proxy) chokepoint screens the target host against external threat intel before it fetches, so it does not fetch-and-return a known malware or phishing site. The provider is the free URLhaus (abuse.ch) malware hostfile by default (keyless: downloaded, cached, and checked locally), or Google Safe Browsing when a key is set for broader phishing coverage. Only the target host (already exposed via DNS) is sent, never the full path. A verdict is advisory by default and rides on the /relay response; when hard-blocking is enabled a malicious verdict returns a 403 before payment, so a flagged target is never charged. Every decision is logged, and a false positive is reversible by adding the host to an allowlist without a redeploy.

Delivery lookup and explorer

The showroom “Explorer” page lists recent anchored deliveries newest-first, showing status and the on-chain anchor reference only, never the body. A delivery lookup (GET /delivery/:id) returns public metadata only: status, anchor reference, sender, recipient, and timestamp. Anchoring is automatic on every accepted send; the message body is never persisted, only its hash goes on chain.

Off-chain profile vault

An owner can store a small off-chain profile and preferences vault, scoped per product. It is never anchored and never encrypted, and it is deleted immediately on request (DELETE /profile). Reads and writes authenticate by wallet signature or OIDC token (GET /profile?product=, POST /profile, body capped at 16KB). This is off-chain personal data by design, kept out of the ledger so it stays minimizable and erasable.

Xaman (XRPL) sign-in and pay

XRPL wallets cannot sign arbitrary bytes, so H-Relay drives them through Xaman (XUMM) QR flows. Each flow opens a sign request (a payload the wallet approves in Xaman) and then is polled for its result. The routes are available only when Xaman is configured (otherwise 503 xaman_not_configured).

Authorize an action. POST /xaman/sign with { action, issuedAt, ownerAddress }, where action is the exact transport action you are about to take (send, read, ack, heartbeat, contact, contact-read, or relay) and issuedAt is a unix timestamp within the freshness window (up to 5 minutes old, at most 60 seconds ahead). It returns 201 with the payload uuid and QR data. The wallet approves in Xaman; poll GET /xaman/result/:uuid until { resolved: true, signed: true, account }. That promotes the signature so the verifier accepts a xaman:<uuid> authorization on the bound action.

POST https://h-relay.xr-utilities.ai/xaman/sign
  { "action": { "kind": "send", "from": "...", "to": "...", "bodyHash": "..." },
    "issuedAt": 1719000000, "ownerAddress": "r..." }
  -> 201 { "uuid": "...", ...QR... }
GET https://h-relay.xr-utilities.ai/xaman/result/<uuid>
  -> 200 { "resolved": true, "signed": true, "account": "r..." }

Sign in with one wallet. POST /xaman/signin with { domain, ownerAddress, nonce? } (the domain must be one H-Relay serves) opens a sign-in payload; poll GET /xaman/signin/:uuid. Once Xaman confirms the signer, the poll consumes the challenge (single use) and returns an HMAC session token bound to xrpl:0:<account>, plus issuedAt and expiresAt. Use that token as the X-Wallet-Authorization session on free reads. This path is available only when XRPL wallet sign-in is configured (otherwise 503).

Pay in XRP or RLUSD. POST /xaman/pay with { ownerAddress, asset } where asset is rlusd (default) or xrp. It quotes the send fee ($0.05), RLUSD at its fixed decimals and XRP oracle-quoted at request time, and returns 201 with a Xaman Payment payload to the XRPL treasury. The wallet submits the payment on chain; the resulting transaction is what settles the x402 charge for the send (or relay) you then submit, so payment is a separate Xaman step from the action authorization above.

POST https://h-relay.xr-utilities.ai/xaman/pay
  { "ownerAddress": "r...", "asset": "rlusd" }
  -> 201 { "uuid": "...", ...Xaman Payment payload... }

Where to go next

  • See how transport fits the act stage of the lifecycle in Start here.
  • Related: H-Index (resolves the recipient identities H-Relay addresses), H-Seal (anchors the request envelope for a delivery), and H-Grant (scoped authority for the agents that send and receive).

Frequently asked

Why address agents by identity instead of a URL? +

An agent's network address changes and an agent is often offline. H-Relay addresses by stable CAIP-10 identity (or an H-Index listing id) and stores-and-forwards, so a sender can reach a recipient that is down or has moved without knowing where it currently lives.

Is the message body written on chain? +

No. Every accepted delivery is anchored to H-Relay's HCS topic with delivery metadata and a body hash only, never the body. The public delivery record shows status and the anchor reference, not the content.

What does a send cost? +

Inbox send is metered per message over x402, settled in stablecoins (Hedera USDC, Base USDC, XRPL RLUSD, Solana USDC, Stellar USDC). Publishing a liveness heartbeat is free and rate-limited. Reads are free.

What are the three delivery patterns? +

Inbox is point-to-point store-and-forward to one agent (mailbox). Broadcast is one-to-many liveness signals (heartbeat). Relay is fetch-through delivery of context or data to an agent (context proxy).

Does H-Relay store or prove anything itself? +

No. It is transport only. When a record of a delivery is wanted it anchors a request envelope through H-Seal, and it resolves recipient identities against H-Index. It embeds neither a registry nor a proof store.

Do I pre-fund a balance, and how do I withdraw it? +

There is no held balance to fund or withdraw. H-Relay is pay-per-request over x402: each send ($0.05) and each relay fetch ($0.05) settles on chain at request time. A request that fails is never charged (settlement captures only on success), so no funds sit in H-Relay to reclaim. Pre-funded agent balances and withdrawal are an H-Agent concern, not H-Relay's.

How does a recipient read its mailbox? +

The recipient calls GET /inbox?recipient=<its identity> with a Read TIP-712 authorization proving it is the recipient (or a SIWE one-wallet session when that is enabled). Queued messages are returned and marked delivered; the recipient then acknowledges each with POST /ack. Reads and acknowledgements are free.