---
title: "Quote a Router call: the fee-inclusive price, rail and network, without paying"
method: POST
path: "/router/quote"
tags: ["Router"]
---

# Quote a Router call: the fee-inclusive price, rail and network, without paying

`POST /router/quote`

## Request

- Base URL: `https://api.sandbox.nevermined.app/api/v1`
- URL: `https://api.sandbox.nevermined.app/api/v1/router/quote`
- Auth: HTTP bearer

Ask what `POST /route` would charge for this call, WITHOUT paying it. The Router makes the
same unpaid probe `/route` makes, reads the 402, selects the payment option exactly as a
payment would (MPP first, then x402) and prices it with the Router fee — then stops. Nothing
is signed, no credential is minted, no payment is recorded and no delegation budget is
reserved, so no money moves. A quote is not free of consequence, though: the unpaid probe
reaches the service (one that does not charge for the request performs it), and a quote
spends the same per-key and per-service rate limit as a payment — so quote once per decision
rather than repeating it.

Use it to decide whether ONE call fits the allocation you planned for it: compare
`fee.capChargedMicros` (exact) or `fee.capChargedCents` (rounded up, the figure
`maxTotalCents` is compared against) with what you want to spend, then call `/route` with
`maxTotalCents` set to that figure so a price change between quote and call is refused rather
than paid.

`delegationId` is optional. With it, the quote prices the options that delegation would select
(an organization-wallet delegation pays only in its own currency, a card delegation pays over
MPP-stripe, a recipient allowlist is enforced); without it, the options a personal crypto
delegation would select. `optionSet` says which. A quote checks neither the remaining cap nor
the wallet balance — those are the payment’s checks (BCK.ROUTER.0003, BCK.ROUTER.0009).

Provide the target `url` OR a catalog `slug` (+ optional `path`, `search`, `method`, `headers`,
`body`), as on `/route`. A non-402 answer returns `paymentRequired: false` with the upstream
status only — the upstream body and headers are never returned.

## Request body

- QuoteRequestDto
  - `url` string: Absolute upstream URL to route to (http/https only). Provide EXACTLY ONE of `url` or `slug` — both together is a 400. Use `slug` for a cataloged service (the opaque broker); `url` is for an off-catalog target you already hold the URL of.
  - `slug` string: Catalog slug to invoke via the opaque Router broker. The Router resolves the slug to the real upstream server-side, so the URL is never exposed. Mutually exclusive with `url`.
  - `path` string: Optional subpath appended to the resolved upstream when `slug` is used (e.g. `scrape` → the merchant's `/scrape`). Path segments only — it may not change the host: `//`, `..`, a backslash and an embedded absolute URL are rejected (400). An `@` is allowed (e.g. an `/inbox/foo@bar.com` route) — it stays in the path and the composed origin is re-asserted against the resolved host. Ignored when `url` is used.
  - `search` string: Query string for a slug-routed request, without the leading ?. It is attached to the resolved merchant URL without changing its host. Use this instead of embedding ? in path. With a raw url, include the query in url; sending search with url is refused.
  - `method` 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE': HTTP method to use for the upstream request.
  - `headers` object: Headers to forward to the upstream (e.g. the agent’s own auth). Optional.
  - `body` unknown
  - `credentialHeader` string: Header the Router should carry the minted payment credential in on the paid hop. Send this only when the service needs its own auth AND a payment: the MPP rails carry their credential in `Authorization`, which is also where your merchant auth goes, and rather than silently replacing yours the Router refuses the call with BCK.ROUTER.0021. Naming the header the service documents for its credential (a separate `Payment` header is the common one) leaves your `Authorization` untouched. It is honoured on every rail, so do not set it by default: putting the credential somewhere the service does not read makes the paid hop fail.
  - `delegationId` string: The delegation you would pay with. Optional. When given, the quote prices the options that delegation would select: an organization-wallet delegation pays only in its own currency, a card delegation pays over the MPP-stripe rail, and a recipient allowlist refuses a pay-to address it would refuse. Without it, the quote prices what a personal crypto (erc4337) delegation would select. `optionSet` in the response says which was used. Either way the quote checks neither the remaining cap nor the wallet balance.

## Response `200`

The quote. `paymentRequired: false` means the upstream did not ask for payment; otherwise `settlement` and `fee` are what `/route` would pay and reserve.

- QuoteResultDto
  - `paymentRequired` boolean, required: Whether the upstream asked for payment (answered 402). `false` means the call is free, or the upstream answered with an error before any payment challenge: read `upstreamStatus`, and expect every priced field below to be absent.
  - `upstreamStatus` number, required: The status the upstream answered the unpaid probe with — 402 when `paymentRequired` is true. The upstream body and headers are never returned.
  - `optionSet` 'delegation' | 'deployment': Which set of payment options was priced. `delegation`: the options the supplied `delegationId` would select. `deployment`: no delegation was supplied, so the options a personal crypto (erc4337) delegation would select on this deployment. Present when `paymentRequired` is true.
  - `delegationId` string, nullable: The delegation whose options were priced, or null for the `deployment` option set. Present when `paymentRequired` is true.
  - `protocol` 'x402' | 'mpp': The payment protocol the Router would pay with — the same auto-detection as `/route` (MPP first, then x402). Present when `paymentRequired` is true.
  - `x402Version` number: The x402 version that would be used, on the x402 rail.
  - `settlement` SettlementDescriptorDto
    - `recipient` string, required: The on-chain recipient (the agent’s `payTo` address from its 402).
    - `amount` string, required: Amount in the asset’s smallest unit (USDC/EURC = 6 decimals).
    - `asset` string: For x402 the asset symbol (`USDC`/`EURC`); for mpp the tempo payment token contract address (mpp carries no on-wire symbol).
    - `network` string, required: Network the payment settles on (name or CAIP-2).
    - `approxCents` string, required: The MERCHANT leg in cents (rounded up) — what this credential pays the upstream agent. This is not necessarily the whole cap charge: Nevermined’s routing fee is reserved on top, so the whole-cent total debited from the delegation is `approxCents + fee.cents` (also reported directly as `fee.capChargedCents`; the exact sub-cent debit is `fee.capChargedMicros`). With no fee configured the two are equal.
    - `scheme` 'exact' | 'charge' | 'spt': Ledger settlement scheme: `exact` for x402 (EIP-3009), `charge` for MPP-tempo (a native Tempo transaction), `spt` for MPP-stripe (a Shared Payment Token). Omitted (defaults to `exact`) on the x402 path.
  - `fee` RouterFeeDto
    - `bps` number, required: Rate applied to this payment, in basis points over a 10,000 denominator (e.g. `200` = 2%). `0` means no routing fee was charged.
    - `amount` string, required: The fee in the settlement asset’s smallest unit — the same unit as `settlement.amount`. Reported atomically rather than in cents because cents are ceiling-rounded and cannot express a sub-cent fee.
    - `cents` string, required: Cents this fee added to the delegation-cap reserve, i.e. `capChargedCents - settlement.approxCents`.
    - `capChargedCents` string, required: The delegation-cap debit for this payment (merchant leg + routing fee), rounded UP to a whole cent. The cap itself accrues at sub-cent resolution, so the exact debit is `capChargedMicros`; this figure is the per-call price guard that `maxTotalCents` is compared against.
    - `capChargedMicros` string, required: The exact delegation-cap debit for this payment (merchant leg + routing fee), in micros — millionths of the currency unit, i.e. 1/10,000 of a cent. It is a ceiling of the true price at that resolution, never below it. It is the debit AT MINT: if the routing fee or the merchant leg is later found uncollected, that part is given back to the cap while this figure stays as minted.

## Other responses

- `400`: Invalid request, no fundable option, a pay-to outside the delegation’s allowed recipients, or an upstream/402 error (BCK.ROUTER.0001); or every option advertised an EIP-712 domain its own settlement token does not sign under (BCK.ROUTER.0012); or the payment credential would overwrite a header you asked the Router to forward and no `credentialHeader` named where the service wants it instead (BCK.ROUTER.0021) — the same refusals `/route` raises before paying. A request-body validation failure arrives as BCK.HTTP.400 instead.
- `401`: Missing/invalid Nevermined API key.
- `403`: BCK.OAUTH.0030 — an OAuth-minted key may not use the Router spend rails; use a plain account key. Permanent — do not retry. A `commerce` credential quotes on `POST /api/v1/router/commerce/quote` instead.
- `404`: BCK.DELEGATION.0002 — no delegation with that `delegationId` belongs to this caller; or BCK.CATALOG.0001 — no listed catalog service has that `slug`.
- `409`: The target is a cataloged Nevermined service that must be addressed by its slug, not by raw URL (BCK.ROUTER.0014).
- `413`: BCK.ROUTER.0024 — the Router JSON request body exceeds the global 5 MiB ceiling. BCK.ROUTER.0027 — a slug-addressed request body is larger than the catalog endpoint accepts (its `maxRequestBytes` on the catalog service detail). Refused before the service is contacted: nothing was paid by this request (a retry of an already-paid `requestId` gets the 409 BCK.ROUTER.0002 instead). `params` gives `bodyBytes` and `maxRequestBytes`; shrink the body or pick a service that takes it. On `/select` it means every otherwise-payable match is below the body, reported against the largest of their limits. Not retryable unchanged.
- `429`: BCK.ROUTER.0007 — too many mode-B relays in flight for this caller at once (each holds an upstream socket and a reserved budget). Retryable: let some relays finish, then try again. A slug-addressed call (using `slug`, not `url`) has a THIRD 429 source: a per-slug invoke rate limit (BCK.HTTP.429 with `Retry-After`). Two buckets again — the per-(key, slug) ceiling is yours, but the per-slug ceiling is SHARED by everyone invoking that slug, so heavy traffic to a popular slug can limit you even when your own rate is low. Retryable after the `Retry-After` backoff. Rate limit exceeded (BCK.HTTP.429). Two buckets can produce this. The per-API-key ceiling is genuinely yours and answers with `Retry-After` (seconds) — honour it. The global bucket is NOT: these routes authenticate after it runs, so it falls back to keying on the client IP, which is currently SHARED by all external callers — you can be limited by traffic that is not yours. That one answers with `Retry-After-short` / `Retry-After-long`, plus `RateLimit-Remaining: 0` and `RateLimit-Reset` at the same expiry. A per-key 429 has bare `Retry-After` and no `RateLimit-*` triple. Retryable after a backoff either way.
- `500`: BCK.ROUTER.0013 — Nevermined holds no EIP-712 signing domain for the selected settlement token; report it rather than looping. Any other 500 is an unexpected server error.
- `503`: BCK.ROUTER.0028 — the quote could not be computed because a read it depends on failed. Nothing was signed or charged; retry with backoff.

---

[API](https://skmtc.dev/nevermined/apis/nevermined-api.md) · [All operations](https://skmtc.dev/nevermined/apis/nevermined-api/llms.txt) · [OpenAPI document](https://skmtc.dev/nevermined/apis/nevermined-api/revisions/cabbe618c80b?raw)
