Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions docs/build/agentic-payments/x402/README.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,26 @@ Freighter Mobile does not currently support x402; use the Freighter browser exte

:::

## Supported Assets

x402 on Stellar supports any [SEP-41](https://stellar.org/protocol/sep-41) compliant token. The default is USDC.

### Testnet USDC

| Property | Value |
| --------------- | ---------------------------------------------------------- |
| Asset Code | `USDC` |
| Issuer | `GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5` |
| SEP-41 Contract | `CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA` |

### Mainnet USDC

| Property | Value |
| --------------- | ---------------------------------------------------------- |
| Asset Code | `USDC` |
| Issuer | `GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN` |
| SEP-41 Contract | `CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75` |

## x402 Facilitators

You can use a facilitator to verify and settle x402 payments. Two options are available for Stellar:
Expand Down
32 changes: 30 additions & 2 deletions docs/build/agentic-payments/x402/built-on-stellar.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,23 @@ Built with the [OpenZeppelin Relayer][oz-relayer] and the [x402 Facilitator Plug
| **x402 scheme** | `exact` | `exact` |
| **Supported assets** | Any [SEP-41] token (defaults to USDC) | Any [SEP-41] token (defaults to USDC) |

Verify endpoint availability:

```bash
curl -I https://channels.openzeppelin.com/x402/supported
# Expected: HTTP 200 with supported assets/networks
```

## Get started

### 1. Generate an API key

Generate an API key for the network you want to use:

- **Testnet**: https://channels.openzeppelin.com/testnet/gen
- **Mainnet**: https://channels.openzeppelin.com/gen
- **Testnet**: https://channels.openzeppelin.com/testnet/gen (no authentication required)
- **Mainnet**: https://channels.openzeppelin.com/gen (requires GitHub OAuth)

Store the generated API key securely — it cannot be retrieved after creation.

### 2. Configure the facilitator URL

Expand Down Expand Up @@ -137,6 +146,25 @@ When a payment is received, the facilitator:

After verification, the facilitator submits the payment on-chain via the OpenZeppelin Relayer and returns confirmation to the server.

## Understanding Soroban authorization

x402 on Stellar uses Soroban's authorization model rather than pre-signed transactions. When a client pays for a resource, they sign an **authorization entry** - a statement that authorizes a specific contract call.

### What the client signs

The authorization entry contains:

- **Contract ID**: The USDC token contract
- **Function**: `transfer`
- **Arguments**: `from` (payer), `to` (recipient), `amount`
- **Expiration**: When this authorization expires

This approach provides several benefits:

- The facilitator can wrap the auth entry with sponsored fees
- No sequence number conflicts
- Built-in replay protection via expiration

## Supported features

- **Networks**: `stellar:testnet`, `stellar:pubnet` ([CAIP-2](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-2.md) identifiers)
Expand Down
81 changes: 78 additions & 3 deletions docs/build/agentic-payments/x402/quickstart-guide.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -190,16 +190,42 @@ main().catch((error) => {
});
```

### Handling payment responses

When integrating x402 into your own client, handle the key response states:

```js
const response = await fetch(protectedUrl, { headers: paymentHeaders });

if (response.status === 402) {
const paymentRequired = response.headers.get("X-Payment");
console.error("Payment required:", paymentRequired);
// Re-initiate payment flow
} else if (response.status === 200) {
const data = await response.json();
console.log("Access granted:", data);
} else {
console.error("Unexpected error:", response.status);
}
```

### Setting up a testnet wallet

Next, create a fresh account and fund it with testnet XLM and testnet USDC using Stellar Lab:

- [Fund a testnet account in Stellar Lab](https://lab.stellar.org/account/fund)

1. Create a new keypair using Stellar Lab: https://lab.stellar.org/account/create
1. Create a new keypair using [Stellar Lab](https://lab.stellar.org/account/create) or the CLI:

```bash
stellar keys generate --network testnet my-x402-wallet
stellar keys address my-x402-wallet # Returns G... public key
stellar keys show my-x402-wallet # Returns S... secret key
```

2. Fund with testnet XLM (Native Stellar Token): https://lab.stellar.org/account/fund
3. Create the USDC trustline (there's a button on the fund page above), sign and submit that transaction
4. Visit the circle faucet, select Stellar Testnet from the networks and add your public key for the wallet address input: https://faucet.circle.com
3. Create the USDC trustline (there's a button on the fund page above), sign and submit that transaction (for detailed instructions, [see below](#step-3-establish-usdc-trustline))
4. Visit the Circle faucet, select Stellar Testnet from the networks and add your public key for the wallet address input: https://faucet.circle.com

Create a local environment file for the client and add your Stellar testnet secret key:

Expand All @@ -215,6 +241,55 @@ Secret keys provide full access to any digital assets held within the wallet. Us

:::

### Step 3 (expanded): Establish USDC trustline

A trustline tells Stellar your account accepts USDC. Without it, you cannot receive payments.

**Testnet USDC Issuer:** `GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5`

#### Using Stellar Lab

1. Go to [Transaction Builder](https://laboratory.stellar.org/#txbuilder?network=test)
2. Enter your public key as source account
3. Click "Fetch next sequence number"
4. Add Operation → "Change Trust"
5. Asset Code: `USDC`
6. Issuer: `GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5`
7. Sign and submit

#### Using code

```javascript
import {
Keypair,
Networks,
TransactionBuilder,
Operation,
Asset,
Horizon,
} from "@stellar/stellar-sdk";

const server = new Horizon.Server("https://horizon-testnet.stellar.org");
const keypair = Keypair.fromSecret(process.env.STELLAR_PRIVATE_KEY);
const account = await server.loadAccount(keypair.publicKey());

const USDC = new Asset(
"USDC",
"GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5",
);

const tx = new TransactionBuilder(account, {
fee: "100",
networkPassphrase: Networks.TESTNET,
})
.addOperation(Operation.changeTrust({ asset: USDC }))
.setTimeout(30)
.build();

tx.sign(keypair);
await server.submitTransaction(tx);
```

## Run The Client

Once the account is funded and the secret key is in `.env`, run the client in a second terminal:
Expand Down
Loading