Skip to main content
Available now on sandbox. Stellar testnet (stellar:testnet) settlement is live for every Sly tenant. Stellar mainnet (stellar:pubnet) ships with production access — contact us once you’ve worked through the production access checklist.

Why Stellar

Sly is rail-neutral by design — the four primitives (Identity, Governance, Policy, Receipts) work on any chain. Stellar is a production rail and changes the economics of agent micro-payments. Three properties matter:
  • Fees are sponsored. The x402.org facilitator sets areFeesSponsored=true for Stellar — your agent’s Stellar account doesn’t need XLM for transaction fees, only enough USDC to cover the payment itself. This is what makes sub-cent settles economically viable.
  • Native USDC since 2021 with deep liquidity, no bridging risk.
  • The fiat edge. 475K+ MoneyGram cash-out locations, Yellowcard across 20+ African markets, Flutterwave — the routes Sly’s emerging-markets remittance story rides on.
For typical 0.100.10–10 commerce settlements in EVM-heavy stacks, Base is the better fit. For sub-cent agent calls and emerging-markets fiat edges, Stellar is. See Settlement rails for the full side-by-side and the selectRail() decision function that picks for you.

The three-layer identity stack

The Stellar rail is where Sly built out its agentic-identity thesis end-to-end. Three layers of evidence the dashboard surfaces and the receipt carries — each provable independently of the others.
Sly’s full identity model is a four-facet framework that applies across rails. This page covers the three chain-side layers as they’re implemented on Stellar. For the unified view — including KYA tier (the Sly-side facet) and how all four facets bind together in the receipt envelope — see Agentic identity.

Control

SEP-10 key-control. The agent’s Stellar keypair signs a Sly-issued challenge. Receipt stamps agent_chain_proof: "sep10".

Custody

Custody provider. The receipt names whoever signed: env_key, oz_soroban, etc. Honest disclosure today, structurally ready for tomorrow.

Discoverability

On-chain anchor. Receipt hash + schema published to Soroban via AttestProtocol. Discoverable from chain alone.
Each layer has its own section below. All three live in the same receipt envelope, signed by the same HMAC.

The flow

Agent ─── 1. GET /api ──────────────► Seller x402 API
      ◄── 2. 402 + PAYMENT-REQUIRED ──
              { accepts: [{
                scheme: "exact",
                network: "stellar:testnet",
                amount: "100000",
                asset: "CBIELTK6Y…",   ← Soroban USDC SAC
                payTo: "GAUJGJ…"
              }]}

Agent ─── 3. POST /v1/x402/stellar/pay ────────► Sly
              { agent_id, url, intent }                │

                              ┌────────────────────────┘
                              ▼ L1–L5 governance

                              │  L1  KYA tier check
                              │  L2  Kill-switch + status
                              │  L3  Per-call cap
                              │  L4  Sign Stellar Soroban auth
                              │      with the agent's Ed25519 key
                              │  L5  Mint witness receipt


              ┌── 4. PAYMENT-SIGNATURE ──┐
              │   (signed PaymentPayload) │
              ▼                          │
Seller verifies + settles via x402.org facilitator


        Soroban USDC SAC transfer on Stellar testnet


Agent  ◄── 5. 200 OK + protected JSON
            + witness receipt persisted to Sly's ledger
Steps 1, 2, and the on-chain settle are vanilla x402 — same shape as Base. The Sly-side governance (L1–L5) and the witness receipt are where the differentiation lives.

Quickstart

1

Use the same Sly API key

Your existing tenant API key works on both rails. No new key needed.
2

Call /v1/x402/stellar/pay

curl -X POST https://sandbox.getsly.ai/v1/x402/stellar/pay \
  -H "Authorization: Bearer pk_test_…" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "<your T2+ agent UUID>",
    "url": "https://seller.example.com/my-service",
    "max_amount": 0.05,
    "intent": { "reason": "demo call", "model": "claude" }
  }'
Or, with a multi-rail allow-list configured, use the unified /v1/x402/pay endpoint and let selectRail() pick Stellar by scoring (fee_sponsored + cheaper_fee + faster_finality).
3

Receive a signed witness receipt

Success returns HTTP 200 with the full envelope, including the three identity fields:
{
  "ok": true,
  "receipt": {
    "receipt_id":      "rcpt_c477197e-…",
    "chain":           "stellar:testnet",
    "from_address":    "GBJWOSLO…",
    "to_address":      "GAUJGJ…",
    "amount":          "0.0100000",
    "asset":           "USDC",
    "agent_id":        "3f85288f-…",
    "agent_name":      "my-buyer-agent",
    "agent_kya_tier":  2,
    "agent_chain_proof":      "sep10",      // key-control proven
    "agent_custody_provider": "env_key",    // honest disclosure of who signed
    "rail_selection": {                     // selectRail() audit trail
      "chosen": "stellar:testnet",
      "reasons": ["picked:fee_sponsored", "picked:cheaper_fee", "picked:faster_finality"]
    },
    "policy_decision": { "decision": "approve",  },
    "signature_mode":     "witness-hmac",
    "canonical_encoding": "json-sort-keys-v1",
    "signature":          "1c022de607719e5ed2aefdc1f60101dd…"
  },
  "receipt_hash": "0x…",
  "http_status":  200,
  "response_body": {  the seller's protected JSON }
}
Every highlighted field is in the canonical encoding. Every highlighted field is in the HMAC. Tampering with any one of them invalidates the signature.
4

(Optional) Verify the receipt offline

Receipts are HMAC-signed by Sly over a stable canonical encoding (json-sort-keys-v1). Anyone with your tenant’s witness key can re-derive the signature without any network call:
node verify-offline.mjs receipt.json
# → ✓ SIGNATURE VALID — receipt is verifiable offline.
This is the proof. The on-chain Soroban tx is the settlement; the receipt is the governance attestation that turns the on-chain movement into “agent X at KYA tier 2, with SEP-10-proven key control, custodied by env_key, paid Y under Sly governance, for resource Z, on rail picked for these three reasons.”

Layer 1 — Control (SEP-10 key-control proof)

Phase A baseline: every receipt named the agent. Strong, but assertive — the receipt named the G-address; it didn’t prove the agent controlled it. SEP-10 key-control binding closes that gap. The agent runs through SEP-10 Web Authentication against Sly:
# 1. Sly issues a SEP-10 challenge transaction (anti-replay home_domain).
curl -X POST https://api.getsly.ai/v1/agents/:id/stellar/challenge \
  -H "Authorization: Bearer pk_test_…" \
  -d '{"client_account": "GBJWOSLO…"}'
# → { "challenge_xdr": "AAAAAg…", "network_passphrase": "Test SDF Network ; September 2015" }

# 2. Agent signs the XDR with its Stellar keypair, off-screen.
#    The keypair never leaves the agent.

# 3. Agent submits the signed XDR to bind.
curl -X POST https://api.getsly.ai/v1/agents/:id/stellar/bind \
  -H "Authorization: Bearer pk_test_…" \
  -d '{"signed_challenge_xdr": "AAAAAg…"}'
# → { "verified": true, "method": "sep10", "binding_id": "709d81f5-…" }
Once bound, every subsequent receipt for this agent stamps agent_chain_proof: "sep10". Until then, agent_chain_proof: "asserted" — and the dashboard’s Chain Bindings panel shows an amber asserted badge with a tooltip explaining what’s NOT cryptographically backed. Where to see it:
  • Receipt field: agent_chain_proof
  • Dashboard: /dashboard/agents/<id>KYA tab → Chain Bindings panel → ✓ SEP-10 PROVEN badge
  • DB: kya_chain_bindings table (proof_method = 'sep10')
The verifier uses @stellar/stellar-sdk’s WebAuth.verifyChallengeTxSigners(). Standards-compliant: matches what Stellar wallets and anchors already trust.

Layer 2 — Custody (provider disclosure)

The second honesty axis. The receipt stamps agent_custody_provider with one of three values today:
ValueWhat it meansStatus
env_keyPrivate key in env (sandbox default)✅ Live
oz_sorobanOpenZeppelin Soroban smart account🚧 In development — receipt-side abstraction live, on-chain custody contract still being deployed
crossmintCrossmint-managed wallets📋 Future
The receipt stamps whichever provider actually signed the call. This is the structural change that lets future smart-account custody drop in oz_soroban without breaking any receipt verifier — the canonical encoding handles new values by design. Why this matters. The most common identity mistake in agentic-payment systems is conflating “the agent’s address is X” with “the agent controls X’s keys.” Layer 1 proves the agent signed once at bind time; Layer 2 discloses whether the keys still live where the binding promised, or whether they’ve moved to a smart account, custodian, etc. Both layers in the same envelope, both in the HMAC.

Layer 3 — Discoverability (AttestProtocol on Soroban)

Phase A receipts are discoverable through Sly’s API and the tenant’s database. Layer 3 makes the receipt’s existence visible from chain alone — without trusting Sly. The /v1/x402/stellar/receipts/:id/anchor route publishes the receipt hash to Soroban via AttestProtocol under Sly’s schema:
curl -X POST https://api.getsly.ai/v1/x402/stellar/receipts/:id/anchor \
  -H "Authorization: Bearer pk_test_…" \
  -d '{"backend": "attest-stellar"}'
Honest status as of June 2026: the route is wired, the schema is designed, the SDK is integrated. The upstream @attestprotocol/stellar-sdk returns Storage::MissingValue on first attestation against the testnet contract — an open upstream contract-initialization question we’re tracking with the AttestProtocol team. The response makes this explicit:
{
  "receipt_id": "rcpt_…",
  "backend": "attest-stellar",
  "network": "stellar:testnet",
  "schema_uid":       "witness-stellar-v1",
  "canonical_receipt": "json-sort-keys-v1",
  "receipt_hash":      "0x9b1c…f3a7",
  "attestation_xdr":   "AAAAAgAAAAB…",     // signed, ready

  "status":         "pending_init",
  "upstream_error": "Storage::MissingValue",
  "blocker":        "AttestProtocol contract not initialized on testnet",
  "tracking":       "upstream contract init · in progress"
}
Sly’s response to a partially-blocked dependency is to show what it computed, what it signed, and exactly what’s pending. No fake green checks. Once the contract-init question resolves upstream (or we self-host), the same route returns the live attestation_uid + tx_hash + explorer URL without any code change at the route surface. In the meantime, the EAS anchor path on Base Sepolia is in production today — see Settlement on Base.

Agentic identity in the receipt (cheat sheet)

Six identity-bearing fields, in canonical-encoding order:
FieldSourceWhy it matters
agent_idSlyUUID — opaque identifier
agent_nameSlyHuman-readable, audit-log-friendly
agent_kya_tierSlyKYA tier at sign time. Frozen in the receipt even if the agent’s tier later changes.
agent_chain_proofLayer 1sep10 (proven) vs asserted (claimed only)
agent_custody_providerLayer 2Discloses who actually signed
rail_selectionselectRail()Why this rail won — auditable, replayable
All six are part of the canonical encoding the HMAC signs over. Tampering with any one of them invalidates the signature. This is the differentiation against raw x402: anyone can prove a payment happened on chain, but only Sly’s witness receipt cryptographically binds “this G-address, this amount, this resource” to “this agent, key-control-proven, env_key-custodied, picked-for-these-reasons, approved by this governance decision.”

Deny artifacts also carry identity

Denied payments don’t just return an error — they return a signed artifact in the same shape. T0 agents below the minimum tier never touch the network; Sly emits a signed deny:
{
  "ok": false,
  "decision": {
    "decision": "deny",
    "reasons": ["kya_tier_below_minimum"],
    "checks": [{
      "check": "kya_tier",
      "detail": "agent.kya_tier=0 < required 2"
    }]
  },
  "signed_artifact": {
    "receipt_id":     "rcpt_deny_…",
    "agent_id":       "…",
    "agent_name":     "stellar-demo-t0",
    "agent_kya_tier": 0,
    "agent_chain_proof": "asserted",
    "agent_custody_provider": "env_key",
    "rail_selection": { "chosen": "stellar:testnet", "reasons": ["intent_target"] },
    "signature_mode": "witness-hmac",
    "signature":      "e9d23f1b…"
  }
}
The deny IS the proof. The agent never sent a single byte to Stellar. The signed artifact says exactly who tried, what they tried to do, why Sly said no, and on which rail.

API surface

EndpointPurpose
POST /v1/x402/stellar/payGoverned payment — L1–L5 + Stellar settle + receipt mint
GET /v1/x402/stellar/infoNetwork, facilitator URL, demo agent address (sandbox sanity)
GET /v1/x402/stellar/receipts/:receipt_idFetch the full signed envelope by rcpt_* id
GET /v1/x402/stellar/denies?limit=25Recent governance denials from the audit log
POST /v1/x402/stellar/receipts/:id/anchorAnchor a witness receipt hash — backend = attest-stellar (Soroban) or eas-base (Base Sepolia)
POST /v1/agents/:id/stellar/challengeIssue a SEP-10 chain-binding challenge
POST /v1/agents/:id/stellar/bindBind a Stellar address with a signed challenge XDR
GET /v1/agents/:id/chain-bindingsList active chain bindings for the agent (cross-rail)
All endpoints are tenant-scoped via your existing API key.

Dashboard

Stellar settlements render in /dashboard/transfers with:
  • A 🌟 stellar testnet rail badge (or 🌟 stellar for mainnet)
  • The Rail column on the transfers list
  • An “All Rails” filter (All / Base / Base Sepolia / Stellar / Internal)
Click into a Stellar transfer to see:
  • Sly-Governed x402 Settlement block at the top
  • Agentic Identity callout — agent name (linked to the agent’s detail page) with the KYA tier badge at sign time
  • Counterparties — G/C address chips with click-through to stellar.expert
  • Witness Receipt panel — full envelope with Download JSON and Copy verify command buttons
The agent detail page (/dashboard/agents/<id>) reads as an identity record:
  • Allowed Rails chips at the top of the header card (intersected tenant.allowed_rails ∩ agent.allowed_rails)
  • Chain Bindings panel (under the KYA tab) — every chain this agent has proven key-control on, with the proof method badge. SEP-10 bindings carry a green ✓ SEP-10 PROVEN badge; asserted bindings carry an amber asserted badge with the tooltip explaining what’s cryptographically backed and what isn’t. G-address links through to stellar.expert.

See it in action — the narrated demo

Three layers of agentic identity on Stellar

~2:10 narrated walkthrough of every Stellar layer Sly has shipped. Six beats — the new receipt with the three identity fields, the dashboard’s Chain Bindings panel with the live SEP-10 binding, the selectRail() decision tree, and the honest framing of the AttestProtocol contract-init blocker. The demo-day asset for Epic 102 (CV Labs / Meridian Lisbon).
The earlier ~1:25 Stellar Phase A walkthrough covers the four-beat baseline arc: T0 deny → T2 settle → dashboard render → offline verification.

Five layers of evidence

Verifying a Stellar settle, weakest to strongest:
  1. Sly UI/dashboard/transfers/<id> (UX surface, not proof)
  2. Sly DB — your tenant’s transfers row + protocol_metadata.witness_receipt
  3. Offline receipt verifynode verify-offline.mjs receipt.json (HMAC re-derives — identity + amount + decision + custody + rail-selection are tamper-proof)
  4. Horizoncurl https://horizon-testnet.stellar.org/accounts/<G> (USDC actually moved between G-addresses)
  5. stellar.expert — direct on-chain visual confirmation of the Soroban invoke_host_function call
Layers 3 + 4 + 5 together form an airtight chain of custody.

What Phase A does NOT yet prove

Three intentional limitations and where they stand now:
GapStatusTracking
The agent ACTUALLY controls the G-addressShippedagent_chain_proof: "sep10" flips on bound agentsPOST /v1/agents/:id/stellar/challenge → sign → POST /stellar/bind
Identity discoverable from chain alone🟡 Wired, latent — code path complete, blocked on upstream AttestProtocol contract initWork in progress, tracked with upstream
Enforced at the rail even if Sly is offline🟡 Abstraction shippedoz_soroban flag in receipt, on-chain custody contract still being deployedWork in progress
With all three at production, the agentic identity survives Sly going offline.

StellarRailAdapter — the settlement-side capability

The buyer-side x402 endpoint (/v1/x402/stellar/pay) stays specialized for the protocol’s 402-challenge-then-pay flow. The underlying capability — “Sly can move USDC on Stellar” — is generalized in StellarRailAdapter, Sly’s first concrete (non-mock) RailAdapter implementation. It exposes the same interface as Sly’s other rail adapters:
MethodImplementation
submitSettlementValidates inputs + signs SAC USDC transfer + returns idempotent externalId
getTransactionLooks up tx hash via Horizon
getTransactionsPaginated Horizon history for reconciliation
getBalanceClassic USDC balance via Horizon /accounts/<G>
healthCheckParallel ping of Horizon + Soroban RPC, 3s timeout each
Sweeps, payouts, fan-out, treasury rebalances — anywhere Sly moves USDC on Stellar internally — flow through this adapter. Same shape as the (eventual) Circle adapter, same shape as future rails.

Limitations & known steps

  • Sandbox uses stellar:testnet. Mainnet (stellar:pubnet) is fully implemented and ships once your tenant has production access.
  • The buyer needs SAC USDC. Friendbot funds XLM; the Soroban USDC contract requires a classic USDC balance behind a trustline. Use Circle’s testnet faucet → select Stellar Testnet → paste your buyer G-address. ~1 second to land.
  • Witness mode (not bilateral). Sly signs receipts alone. Bilateral ed25519 (payer + payee + Sly) ships with Epic 97.

Roadmap

Shipped

Stellar testnet + mainnet settlement · L1–L5 governance · witness receipts with full agentic identity (SEP-10, custody disclosure, rail selection) · dashboard surface · offline verification.

Work in progress

OZ Soroban smart-account custody (`oz_soroban` provider) · CCTP V2 treasury rebalance · AttestProtocol on-chain anchoring (pending upstream contract init).

Compare rails

Side-by-side: Base vs Stellar, selectRail(), allow-list configuration.

Want production Stellar?

Email us with your use case and we’ll get you onto mainnet.