diff --git a/docs.json b/docs.json
index 959527d..2162368 100644
--- a/docs.json
+++ b/docs.json
@@ -177,6 +177,7 @@
"guides/stellar/passkey-signing",
"guides/stellar/stellar-quickstart",
"guides/stellar/wraith-names-lifecycle",
+ "guides/stellar/subscriptions-with-wraith-names",
"guides/wraith-names-stellar",
"guides/ops/self-hosted-deployment",
"guides/ops/monitoring-and-on-call"
diff --git a/guides/stellar/subscriptions-with-wraith-names.mdx b/guides/stellar/subscriptions-with-wraith-names.mdx
new file mode 100644
index 0000000..64a2c2c
--- /dev/null
+++ b/guides/stellar/subscriptions-with-wraith-names.mdx
@@ -0,0 +1,309 @@
+---
+title: "Subscriptions with Wraith Names"
+description: "Build recurring Stellar subscriptions that resolve a .wraith name at every billing run, so recipients can rotate stealth keys without breaking payer schedules."
+keywords: "Stellar, Soroban, Wraith names, subscriptions, recurring payments, USDC, stealth meta-address, futurenet fixtures"
+---
+
+This tutorial shows how to build a recurring Stellar subscription around a `.wraith` name instead of a raw stealth meta-address. The payer stores `merchant.wraith` as the billing destination, resolves the name before each scheduled payment, and sends USDC to the current meta-address behind that name.
+
+For the lower-level scheduler mechanics, read [Recipe 2 in the Spectre + Stellar Cookbook](/guides/spectre-stellar-cookbook#recipe-2-dao-weekly-payroll-in-usdc-on-stellar). For one-time invoices and unsigned or signed URLs, read [Stellar Payment Links](/guides/stellar-payment-links). For name state, expiry, renewal, and update rules, read [Wraith Names Lifecycle on Stellar](/guides/stellar/wraith-names-lifecycle).
+
+
+ The fixture example below uses Futurenet RPC/passphrase values and canned name records so the subscription flow can run without live Wraith contracts. Current Wraith contract deployments are listed in [Stellar Networks](/reference/stellar-networks); use Stellar testnet for live `wraith-names` contract calls until Futurenet deployments are published.
+
+
+---
+
+## Flow
+
+The subscription contract between payer and recipient is off-chain. The on-chain privacy boundary is still Wraith's Stellar stealth payment flow:
+
+1. The recipient registers or updates `merchant.wraith` to point at their current Stellar stealth meta-address.
+2. The payer stores the subscription as `{ destinationName: "merchant.wraith", amount: "25", asset: "USDC" }`.
+3. Each billing run resolves `merchant.wraith` immediately before payment.
+4. The payer derives and sends to a fresh stealth address for the resolved meta-address.
+5. If the recipient rotates keys, only the name record changes. The payer's subscription row stays the same.
+
+That last point is the difference from a raw meta-address subscription. A raw `st:xlm:...` destination is stable only while the recipient keeps the same stealth keys. A `.wraith` destination lets the recipient rotate the mapping behind the name.
+
+---
+
+## Data Model
+
+Store the destination as a name, not as the resolved meta-address.
+
+```typescript
+type SubscriptionStatus = "active" | "paused" | "cancelled";
+
+interface Subscription {
+ id: string;
+ payerAccount: string;
+ destinationName: `${string}.wraith`;
+ amount: string;
+ asset: "USDC" | "XLM";
+ cadence: "monthly";
+ nextRunAt: string;
+ status: SubscriptionStatus;
+ lastResolvedMetaAddress?: string;
+}
+
+const subscription: Subscription = {
+ id: "sub_merchant_001",
+ payerAccount: "GBILLINGPAYER...",
+ destinationName: "merchant.wraith",
+ amount: "25",
+ asset: "USDC",
+ cadence: "monthly",
+ nextRunAt: "2026-09-01T09:00:00Z",
+ status: "active",
+};
+```
+
+Keep `lastResolvedMetaAddress` only as an audit field. Do not use it as the next billing destination unless a retry policy explicitly says to retry the exact same resolved target.
+
+---
+
+## Resolve on Every Billing Run
+
+The billing worker should resolve the name just before sending. This gives the recipient a clean rotation path: update the name record before the next billing date, and the payer automatically routes future payments to the new meta-address.
+
+```typescript
+import { Chain, Wraith } from "@wraith-protocol/sdk";
+
+interface BillingResult {
+ subscriptionId: string;
+ destinationName: string;
+ resolvedMetaAddress: string;
+ status: "sent" | "failed";
+ txHash?: string;
+ error?: string;
+}
+
+export async function runMonthlySubscription(
+ subscription: Subscription
+): Promise {
+ const wraith = new Wraith({ apiKey: process.env.WRAITH_API_KEY! });
+ const payerAgent = wraith.agent(process.env.PAYER_AGENT_ID!);
+
+ try {
+ const resolvedMetaAddress = await wraith.resolveName(
+ subscription.destinationName,
+ Chain.Stellar
+ );
+
+ const response = await payerAgent.chat(
+ `send ${subscription.amount} ${subscription.asset} to ${subscription.destinationName} on stellar`
+ );
+
+ return {
+ subscriptionId: subscription.id,
+ destinationName: subscription.destinationName,
+ resolvedMetaAddress,
+ status: "sent",
+ txHash: extractTxHash(response),
+ };
+ } catch (error: any) {
+ return {
+ subscriptionId: subscription.id,
+ destinationName: subscription.destinationName,
+ resolvedMetaAddress: subscription.lastResolvedMetaAddress ?? "",
+ status: "failed",
+ error: error.message,
+ };
+ }
+}
+
+function extractTxHash(response: any): string | undefined {
+ const detail = response.toolCalls?.find((call: any) => call.name === "send_payment")?.detail;
+ if (!detail) return undefined;
+ return JSON.parse(detail).txHash;
+}
+```
+
+The chat instruction still uses `merchant.wraith`. That keeps the payment intent human-readable in logs and lets the agent perform name resolution with the same routing rules users see elsewhere in the Wraith app.
+
+---
+
+## Futurenet Fixture Example
+
+Use this fixture-backed resolver in tests and tutorials that must run with Futurenet settings while live Wraith Futurenet contracts are unavailable. The shape mirrors the fields the scheduler cares about: name, meta-address, state, and expiry ledger.
+
+```typescript
+type NameState = "active" | "grace_period" | "expired";
+
+interface NameFixture {
+ name: `${string}.wraith`;
+ metaAddress: string;
+ owner: string;
+ state: NameState;
+ expiryLedger: number;
+}
+
+const FUTURENET_SUBSCRIPTION_FIXTURES: NameFixture[] = [
+ {
+ name: "merchant.wraith",
+ metaAddress:
+ "st:xlm:eb8452e938d04e9a56ef69c47dacd8224464b030b5ca569d5b4e4399f8d0fb5529a8dd877a3803289ab3a62ac39cce4a99021a3cd0fac6ad982e051c8fa769dc",
+ owner: "GB4X7TDIRWAXKYRAYRXSTY27DZUTQKEMJKV7GBKZ3RVJJS5XCHAELUZI",
+ state: "active",
+ expiryLedger: 58_600_000,
+ },
+];
+
+export function resolveFixtureName(name: string): NameFixture {
+ const record = FUTURENET_SUBSCRIPTION_FIXTURES.find((item) => item.name === name);
+ if (!record) throw new Error(`Name not found: ${name}`);
+ if (record.state === "expired") throw new Error(`Name expired: ${name}`);
+ return record;
+}
+```
+
+Now run a monthly payment against the fixture. The example records the resolved meta-address and emits the payment intent your real worker would hand to the Wraith sender.
+
+```typescript
+const FUTURENET_RPC_URL = "https://rpc-futurenet.stellar.org";
+const FUTURENET_PASSPHRASE = "Test SDF Future Network ; October 2022";
+
+interface FixturePaymentIntent {
+ network: "futurenet";
+ rpcUrl: string;
+ networkPassphrase: string;
+ toName: string;
+ toMetaAddress: string;
+ amount: string;
+ asset: string;
+ memo: string;
+}
+
+export function buildFixturePaymentIntent(
+ subscription: Subscription
+): FixturePaymentIntent {
+ const record = resolveFixtureName(subscription.destinationName);
+
+ return {
+ network: "futurenet",
+ rpcUrl: FUTURENET_RPC_URL,
+ networkPassphrase: FUTURENET_PASSPHRASE,
+ toName: record.name,
+ toMetaAddress: record.metaAddress,
+ amount: subscription.amount,
+ asset: subscription.asset,
+ memo: `subscription:${subscription.id}`,
+ };
+}
+
+const intent = buildFixturePaymentIntent(subscription);
+console.log(intent.toName, intent.toMetaAddress);
+```
+
+For a live network run, replace `resolveFixtureName` with `wraith.resolveName("merchant.wraith", Chain.Stellar)` and keep the rest of the billing workflow the same.
+
+---
+
+## Rotation Mid-Subscription
+
+Assume the first billing run resolves `merchant.wraith` to meta-address A. Before the second run, the merchant rotates their stealth keys and updates the name record to meta-address B.
+
+```typescript
+const beforeRotation = resolveFixtureName("merchant.wraith");
+
+const afterRotation: NameFixture = {
+ ...beforeRotation,
+ metaAddress:
+ "st:xlm:61a798cab73a628668eff0cc4a5cf51d5687c947bfc674100080538049e1363a61a798cab73a628668eff0cc4a5cf51d5687c947bfc674100080538049e1363a",
+ expiryLedger: beforeRotation.expiryLedger + 6_307_200,
+};
+
+console.log("month 1:", beforeRotation.metaAddress);
+console.log("month 2:", afterRotation.metaAddress);
+```
+
+The payer does not edit the subscription. They keep sending to `merchant.wraith`; the resolver supplies the current meta-address at each run.
+
+In production, the merchant performs the rotation with the `wraith-names` `update` entrypoint or the agent flow documented in [Update Meta-Address](/guides/stellar/wraith-names-lifecycle#update-meta-address).
+
+---
+
+## Cancellation
+
+Cancellation belongs to the payer's billing system. The payer should mark the subscription cancelled and stop scheduling future sends:
+
+```typescript
+export function cancelSubscription(
+ current: Subscription,
+ cancelledAt: string
+): Subscription {
+ return {
+ ...current,
+ status: "cancelled",
+ nextRunAt: cancelledAt,
+ };
+}
+```
+
+Do not model cancellation as a name update. A `.wraith` name may receive payments from many payers, so changing the merchant's name record would affect unrelated subscriptions and payment links.
+
+---
+
+## Missed Payments
+
+When a billing run fails, separate name-resolution failures from payment-execution failures.
+
+| Failure | Recommended behavior |
+|---|---|
+| `NameNotFound` | Pause the subscription and ask the merchant to confirm the destination. |
+| `NameExpired` | Pause new sends until the merchant renews the name. Do not fall back to a stale meta-address. |
+| Grace period | Continue sending, but warn the merchant that renewal is needed. |
+| Insufficient payer balance | Retry after funding; resolve the name again before the retry unless you are retrying the same submitted transaction. |
+| Network congestion | Retry with backoff; resolve the name again for a new payment attempt. |
+
+This is stricter than the raw meta-address cookbook flow. With a raw meta-address, retries can safely reuse the stored destination because the destination is the actual routing key. With a `.wraith` name, a retry may cross a rotation boundary, so the worker should resolve again unless it is replaying a transaction already built for a specific meta-address.
+
+---
+
+## Name Expiry Edge Case
+
+A `.wraith` name can be active, in grace period, or expired. The subscription worker should treat those states differently:
+
+```typescript
+interface NameInfo {
+ state: "active" | "grace_period" | "expired";
+ expiryLedger: number;
+}
+
+export function shouldBillName(info: NameInfo): boolean {
+ if (info.state === "expired") return false;
+ return true;
+}
+
+export function renewalWarning(info: NameInfo): string | undefined {
+ if (info.state !== "grace_period") return undefined;
+ return `Name is in grace period and expires after ledger ${info.expiryLedger}.`;
+}
+```
+
+Payments initiated before expiry still target the meta-address resolved at send time. Future billing runs should stop once resolution reports the name as expired. Falling back to `lastResolvedMetaAddress` after expiry defeats the purpose of name-based routing and may send funds to a stale destination.
+
+---
+
+## Compare with Raw Meta-Address Scheduling
+
+| Concern | Raw meta-address subscription | `.wraith` name subscription |
+|---|---|---|
+| Stored destination | `st:xlm:...` | `merchant.wraith` |
+| Recipient rotation | Payer must update every subscription row | Recipient updates one name record |
+| Cancellation | Payer stops scheduler | Payer stops scheduler |
+| Retry destination | Reuse the stored meta-address | Resolve again for each new attempt |
+| Expiry behavior | No name expiry state | Pause on expired name; warn during grace period |
+| Audit trail | Shows opaque meta-address | Shows human-readable name plus resolved meta-address |
+
+Use raw meta-addresses when the recipient wants no public name mapping. Use `.wraith` names when operational stability and human-readable routing are more important than hiding the routing identifier itself.
+
+---
+
+## Related
+
+- [Wraith Names Lifecycle on Stellar](/guides/stellar/wraith-names-lifecycle)
+- [Stellar Payment Links](/guides/stellar-payment-links)
+- [Spectre + Stellar Cookbook, Recipe 2](/guides/spectre-stellar-cookbook#recipe-2-dao-weekly-payroll-in-usdc-on-stellar)
+- [Stellar Networks](/reference/stellar-networks)