Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 2 additions & 2 deletions .windsurf/rules/nevermined-router.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ back. For spend to date read `GET /api/v1/delegation/{id}` → `amountSpentCents
written, so `requestId` won't suppress it.
- `BCK.ROUTER.0011` (402) — card rail: needs 3-D Secure, which an agent can't complete. Nothing
charged; each retry strands a single-use credential. **Don't auto-retry.**
- Only `0006` (500) and `0007` (429, too many concurrent) are **retryable**; everything else is a
decision, and retrying it unchanged gives the same answer.
- Only `BCK.ROUTER.0006` (500) and `0007` (429, too many concurrent) are **retryable**; everything
Comment thread
r-marques marked this conversation as resolved.
else is a decision, and retrying it unchanged gives the same answer.

**Never widen a Delegation, and never create a second one, to get past a refusal.** The cap is the
user's decision; a fresh one to escape an exhausted Delegation defeats it.
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ They give AI coding assistants (Claude Code, Cursor, Copilot, Codex, Windsurf, C
⚠️ **Windsurf's 6,000-character cap is a hard truncation, and `nevermined-router.md` is at its
ceiling.** Windsurf silently drops everything past 6,000 characters — it does not error, and what it
drops is the **end** of the file, which is where the guardrails and accounting sections live. As of
2026-08-17 `.windsurf/rules/nevermined-router.md` is **5,980 of 6,000** characters (its payments
2026-08-17 `.windsurf/rules/nevermined-router.md` is **5,991 of 6,000** characters (its payments
sibling is 3,759; the 12,000 all-files cap is not the binding one).

The other three IDE rule files share a fuller body; **Windsurf's copy is deliberately terser and is
Expand Down
8 changes: 7 additions & 1 deletion products/router/rails-x402.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

x402 is the HTTP-native payment protocol where a server answers an unpaid request with **HTTP 402** and an `accepts` array describing what it will take. The Router reads that array, picks an option it can fund, signs the payment from your custodial wallet, and hands back a credential.

You don't need the service to know anything about Nevermined. If it speaks x402, it's payable.

Check warning on line 9 in products/router/rails-x402.mdx

View check run for this annotation

Mintlify / Mintlify Validation (neverminedag) - vale-spellcheck

products/router/rails-x402.mdx#L9

Did you really mean 'Nevermined'?

## What a challenge looks like

Expand Down Expand Up @@ -46,17 +46,23 @@
| --- | --- |
| **Scheme** | `exact` — an EIP-3009 `TransferWithAuthorization`, a single-use signed authorization the merchant redeems |
| **Networks** | `base` (chain `8453`) and `base-sepolia` (chain `84532`), by name or as CAIP-2 (`eip155:8453`) |
| **Assets** | `USDC` and `EURC` — 6-decimal stablecoins |

Check warning on line 49 in products/router/rails-x402.mdx

View check run for this annotation

Mintlify / Mintlify Validation (neverminedag) - vale-spellcheck

products/router/rails-x402.mdx#L49

Did you really mean 'stablecoins'?

Anything outside that isn't payable on this rail today: other schemes, other chains, and non-EVM networks such as Solana.

Check warning on line 51 in products/router/rails-x402.mdx

View check run for this annotation

Mintlify / Mintlify Validation (neverminedag) - vale-spellcheck

products/router/rails-x402.mdx#L51

Did you really mean 'Solana'?

<Note>
A **mixed-chain 402 still works** as long as one option is fundable. If a service advertises both a Solana option and a Base option, the Router skips the one it can't parse and pays the Base one. It only fails if *no* entry survives the filter — that's `400 BCK.ROUTER.0001`.

Check warning on line 54 in products/router/rails-x402.mdx

View check run for this annotation

Mintlify / Mintlify Validation (neverminedag) - vale-spellcheck

products/router/rails-x402.mdx#L54

Did you really mean 'fundable'?

Check warning on line 54 in products/router/rails-x402.mdx

View check run for this annotation

Mintlify / Mintlify Validation (neverminedag) - vale-spellcheck

products/router/rails-x402.mdx#L54

Did you really mean 'Solana'?
</Note>

### How an option gets chosen

Given several fundable entries, the Router filters to `scheme: "exact"` on a funded network with a funded asset, then prefers **USDC**. The asset symbol is read from the entry's **`extra.name`** field — a service that omits it won't match the symbol filter even if its `asset` address is USDC.
Given several fundable entries, the Router filters to `scheme: "exact"` on a funded network with a funded asset, then prefers **USDC**. The asset symbol is resolved from the entry's **`asset` address**, matched against the canonical token addresses for that chain — never from `extra.name`, which is something else entirely (see below). A token the Router doesn't recognise on that chain isn't fundable, however the entry labels it.

Check warning on line 59 in products/router/rails-x402.mdx

View check run for this annotation

Mintlify / Mintlify Validation (neverminedag) - vale-spellcheck

products/router/rails-x402.mdx#L59

Did you really mean 'fundable'?

Check warning on line 59 in products/router/rails-x402.mdx

View check run for this annotation

Mintlify / Mintlify Validation (neverminedag) - vale-spellcheck

products/router/rails-x402.mdx#L59

Did you really mean 'fundable'?

### `extra.name` is the EIP-712 domain, not a ticker

`extra.name` and `extra.version` are the settlement token's **EIP-712 domain** — the `name()` and `version()` the token contract itself signs under, and what the payment authorization is signed against. They are frequently *not* the ticker: canonical Base-mainnet USDC signs under `"USD Coin"`, while the Base Sepolia deployment signs under `"USDC"`.

Check warning on line 63 in products/router/rails-x402.mdx

View check run for this annotation

Mintlify / Mintlify Validation (neverminedag) - vale-spellcheck

products/router/rails-x402.mdx#L63

Did you really mean 'Sepolia'?

Both fields are **required**. If you are the seller, copy them from the token contract's `name()` and `version()` exactly — an authorization signed under the wrong domain produces a signature the token cannot recover, so guessing the ticker yields a payment that simply cannot settle.

## Money and budget

Expand Down Expand Up @@ -85,10 +91,10 @@
Fund for the merchant's amount **plus** any [routing fee](/products/router/how-it-works#fund-for-the-amount-plus-the-fee) — the fee is a second transfer from the same wallet, so the quoted price alone doesn't cover both.
</Warning>

The asset to send is the one the service's 402 advertises — `USDC` or `EURC`, 6 decimals, on the network in that entry. Base mainnet USDC is `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`.

Check warning on line 94 in products/router/rails-x402.mdx

View check run for this annotation

Mintlify / Mintlify Validation (neverminedag) - vale-spellcheck

products/router/rails-x402.mdx#L94

Did you really mean 'mainnet'?

<Warning>
`base` is **Base mainnet** and moves real funds; `base-sepolia` is the testnet. **Which of them your deployment will fund is decided by the environment you are pointed at, not by the service.** A sandbox deployment funds testnets only and a live deployment funds mainnet only — that split is the real-money firewall and an operator cannot widen it. If you call a mainnet service from sandbox, no entry survives the filter and you get `400 BCK.ROUTER.0001`. Read `settlement.network` on the response to be sure what just happened.

Check warning on line 97 in products/router/rails-x402.mdx

View check run for this annotation

Mintlify / Mintlify Validation (neverminedag) - vale-spellcheck

products/router/rails-x402.mdx#L97

Did you really mean 'mainnet'?

Check warning on line 97 in products/router/rails-x402.mdx

View check run for this annotation

Mintlify / Mintlify Validation (neverminedag) - vale-spellcheck

products/router/rails-x402.mdx#L97

Did you really mean 'testnet'?

Check warning on line 97 in products/router/rails-x402.mdx

View check run for this annotation

Mintlify / Mintlify Validation (neverminedag) - vale-spellcheck

products/router/rails-x402.mdx#L97

Did you really mean 'testnets'?

Check warning on line 97 in products/router/rails-x402.mdx

View check run for this annotation

Mintlify / Mintlify Validation (neverminedag) - vale-spellcheck

products/router/rails-x402.mdx#L97

Did you really mean 'mainnet'?
</Warning>

## Authorization lifetime
Expand All @@ -108,11 +114,11 @@

## Operator configuration

These are set per deployment, not per call. You only need them if you run your own Nevermined deployment.

Check warning on line 117 in products/router/rails-x402.mdx

View check run for this annotation

Mintlify / Mintlify Validation (neverminedag) - vale-spellcheck

products/router/rails-x402.mdx#L117

Did you really mean 'Nevermined'?

| Env var | Default | Purpose |
| --- | --- | --- |
| `ROUTER_FUNDED_NETWORKS` | derived from `ENVIRONMENT` | Networks the Router will fund a payment on. Sandbox derives the testnets, live derives mainnet; only a local/dev instance falls back to the permissive `base,base-sepolia`. On a deployed instance this variable can only **narrow** the derived set — it can never add a network, so it cannot move a box across the sandbox/live firewall. Setting it to an empty string is an explicit "fund nothing", not "use the default". |

Check warning on line 121 in products/router/rails-x402.mdx

View check run for this annotation

Mintlify / Mintlify Validation (neverminedag) - vale-spellcheck

products/router/rails-x402.mdx#L121

Did you really mean 'testnets'?

Check warning on line 121 in products/router/rails-x402.mdx

View check run for this annotation

Mintlify / Mintlify Validation (neverminedag) - vale-spellcheck

products/router/rails-x402.mdx#L121

Did you really mean 'mainnet'?
| `ROUTER_FUNDED_SYMBOLS` | `USDC,EURC` | Asset symbols it will pay in |
| `ROUTER_PREFER_SYMBOL` | `USDC` | Which symbol wins when a 402 offers several |
| `ROUTER_MAX_AUTH_TTL_SECS` | `3600` | Ceiling on the signed authorization's validity window |
Expand Down