> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getsly.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Settling on Stellar

> x402 settlement on Stellar testnet and Stellar mainnet, under the same L1–L5 governance loop as Base, plus the three-layer agentic identity stack (Control, Custody, Discoverability) Sly built on top of the Stellar rail.

<Note>
  **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](mailto:hello@getsly.ai) once you've
  worked through the [production access](/get-started/production-access)
  checklist.
</Note>

## 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.10–$10 commerce settlements in EVM-heavy stacks, [Base](/settlement/base) is the better fit. For sub-cent agent calls and emerging-markets fiat edges, Stellar is. See [Settlement rails](/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.

<Note>
  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](/agents/agentic-identity).
</Note>

<CardGroup cols={3}>
  <Card title="Control" icon="key">
    **SEP-10 key-control.** The agent's Stellar keypair signs a Sly-issued challenge. Receipt stamps `agent_chain_proof: "sep10"`.
  </Card>

  <Card title="Custody" icon="vault">
    **Custody provider.** The receipt names whoever signed: `env_key`, `oz_soroban`, etc. Honest disclosure today, structurally ready for tomorrow.
  </Card>

  <Card title="Discoverability" icon="anchor">
    **On-chain anchor.** Receipt hash + schema published to Soroban via AttestProtocol. Discoverable from chain alone.
  </Card>
</CardGroup>

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

<Steps>
  <Step title="Use the same Sly API key">
    Your existing tenant API key works on both rails. No new key needed.
  </Step>

  <Step title="Call /v1/x402/stellar/pay">
    ```bash theme={null}
    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()`](/settlement/rails#selectrail-the-decision-function) pick Stellar by scoring (fee\_sponsored + cheaper\_fee + faster\_finality).
  </Step>

  <Step title="Receive a signed witness receipt">
    Success returns HTTP 200 with the full envelope, **including the three identity fields**:

    ```json theme={null}
    {
      "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.
  </Step>

  <Step title="(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:

    ```bash theme={null}
    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."
  </Step>
</Steps>

## 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:

```bash theme={null}
# 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:

| Value        | What it means                        | Status                                                                                            |
| ------------ | ------------------------------------ | ------------------------------------------------------------------------------------------------- |
| `env_key`    | Private key in env (sandbox default) | ✅ Live                                                                                            |
| `oz_soroban` | OpenZeppelin Soroban smart account   | 🚧 In development — receipt-side abstraction live, on-chain custody contract still being deployed |
| `crossmint`  | Crossmint-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](https://attest.so) under Sly's schema:

```bash theme={null}
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:

```json theme={null}
{
  "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](/settlement/base#layer-3-discoverability-eas).

## Agentic identity in the receipt (cheat sheet)

Six identity-bearing fields, in canonical-encoding order:

| Field                    | Source         | Why it matters                                                                         |
| ------------------------ | -------------- | -------------------------------------------------------------------------------------- |
| `agent_id`               | Sly            | UUID — opaque identifier                                                               |
| `agent_name`             | Sly            | Human-readable, audit-log-friendly                                                     |
| `agent_kya_tier`         | Sly            | KYA tier *at sign time*. Frozen in the receipt even if the agent's tier later changes. |
| `agent_chain_proof`      | Layer 1        | `sep10` (proven) vs `asserted` (claimed only)                                          |
| `agent_custody_provider` | Layer 2        | Discloses who actually signed                                                          |
| `rail_selection`         | `selectRail()` | 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:

```json theme={null}
{
  "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

| Endpoint                                     | Purpose                                                                                           |
| -------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `POST /v1/x402/stellar/pay`                  | Governed payment — L1–L5 + Stellar settle + receipt mint                                          |
| `GET  /v1/x402/stellar/info`                 | Network, facilitator URL, demo agent address (sandbox sanity)                                     |
| `GET  /v1/x402/stellar/receipts/:receipt_id` | Fetch the full signed envelope by `rcpt_*` id                                                     |
| `GET  /v1/x402/stellar/denies?limit=25`      | Recent governance denials from the audit log                                                      |
| `POST /v1/x402/stellar/receipts/:id/anchor`  | Anchor a witness receipt hash — backend = `attest-stellar` (Soroban) or `eas-base` (Base Sepolia) |
| `POST /v1/agents/:id/stellar/challenge`      | Issue a SEP-10 chain-binding challenge                                                            |
| `POST /v1/agents/:id/stellar/bind`           | Bind a Stellar address with a signed challenge XDR                                                |
| `GET  /v1/agents/:id/chain-bindings`         | List 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

<Card title="Three layers of agentic identity on Stellar" href="https://github.com/Sly-devs/sly/blob/main/docs/demos/stellar-identity-stack/narration.md" icon="play">
  \~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).
</Card>

The earlier \~1:25 [Stellar Phase A walkthrough](https://github.com/Sly-devs/sly/blob/main/docs/demos/stellar-phase-a/narration.md) 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 verify** — `node verify-offline.mjs receipt.json` (HMAC re-derives — identity + amount + decision + custody + rail-selection are tamper-proof)
4. **Horizon** — `curl 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:

| Gap                                         | Status                                                                                                    | Tracking                                                              |
| ------------------------------------------- | --------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| The agent ACTUALLY controls the G-address   | ✅ **Shipped** — `agent_chain_proof: "sep10"` flips on bound agents                                        | `POST /v1/agents/:id/stellar/challenge` → sign → `POST /stellar/bind` |
| Identity discoverable from chain alone      | 🟡 **Wired, latent** — code path complete, blocked on upstream AttestProtocol contract init               | Work in progress, tracked with upstream                               |
| Enforced at the rail even if Sly is offline | 🟡 **Abstraction shipped** — `oz_soroban` flag in receipt, on-chain custody contract still being deployed | Work 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:

| Method             | Implementation                                                             |
| ------------------ | -------------------------------------------------------------------------- |
| `submitSettlement` | Validates inputs + signs SAC USDC transfer + returns idempotent externalId |
| `getTransaction`   | Looks up tx hash via Horizon                                               |
| `getTransactions`  | Paginated Horizon history for reconciliation                               |
| `getBalance`       | Classic USDC balance via Horizon `/accounts/<G>`                           |
| `healthCheck`      | Parallel 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](/get-started/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](https://faucet.circle.com) → 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

<CardGroup cols={2}>
  <Card title="Shipped" icon="check">
    Stellar testnet + mainnet settlement · L1–L5 governance · witness receipts with full agentic identity (SEP-10, custody disclosure, rail selection) · dashboard surface · offline verification.
  </Card>

  <Card title="Work in progress">
    OZ Soroban smart-account custody (\`oz\_soroban\` provider) · CCTP V2 treasury rebalance · AttestProtocol on-chain anchoring (pending upstream contract init).
  </Card>

  <Card title="Compare rails" icon="scale-balanced" href="/settlement/rails">
    Side-by-side: Base vs Stellar, `selectRail()`, allow-list configuration.
  </Card>

  <Card title="Want production Stellar?" icon="envelope" href="mailto:hello@getsly.ai">
    Email us with your use case and we'll get you onto mainnet.
  </Card>
</CardGroup>
