---
title: "Route and pay using the delegation from your commerce grant (mode B, OAuth)"
method: POST
path: "/router/commerce/route"
tags: ["Router"]
---

# Route and pay using the delegation from your commerce grant (mode B, OAuth)

`POST /router/commerce/route`

## Request

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

The OAuth counterpart of `POST /api/v1/router/route`, for a credential minted from a
`commerce` authorization. Identical behaviour and identical response — with one difference:
**you do not choose the delegation.** It is derived from your grant: the capped, expiring
mandate the user approved when they connected you. Sending a `delegationId` is refused, not
ignored.

The cap, its expiry, and the user revoking the grant are the boundary on what you can spend.
The routing fee is drawn from that same cap, in addition to each merchant’s price.

A plain (non-OAuth) API key cannot use this route — it has no grant to derive from. Use
`POST /api/v1/router/route` and name your own `delegationId` instead.

## Request body

- CommerceRouteRequestDto
  - `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, so `//`, `@`, `..` and an embedded absolute URL are rejected (400). Ignored when `url` is used.
  - `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
  - `protocol` 'x402' | 'mpp': Payment protocol. On the mode-B proxy (`/route`, `/proxy`) this is ADVISORY: the Router AUTO-DETECTS the protocol from the upstream 402 — `WWW-Authenticate: Payment` → `mpp`; `accepts` / `PAYMENT-REQUIRED` → `x402` — and the DETECTED protocol is authoritative for the mint (a mismatching hint here does not change what gets paid).
  - `requestId` string, required: Idempotency key — REQUIRED for routed payments (mode B). The Router makes the upstream call and pays automatically, so a retry after a dropped connection must not double-spend. At most one payment is minted per (caller, requestId); a duplicate returns 409 (BCK.ROUTER.0002) carrying the original paymentId, rather than paying again.

## Response `201`

Upstream response, relayed.

- RouteResultDto
  - `status` number, required: The upstream HTTP status code that was relayed.
  - `body` unknown, required
  - `paid` boolean, required: Whether a payment was made (false = the upstream was free).
  - `payment` RouteResultPaymentDto
    - `resultUrl` string: Where this paid result stays readable by you for 24 hours (GET it with the same API key), in case the response is lost on the way back to you. Relative to the API host. API 1.48 and later.
    - `paymentId` string, required
    - `settlement` SettlementDescriptorDto, required
      - `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, required
      - `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.
    - `txHash` string, nullable: On-chain settlement tx, if the upstream reported one.
    - `status` 'Issued' | 'Settled', required

## Other responses

- `202`: API version 1.48 or later: the payment was made but the merchant had not answered within 45 s. The call keeps running on the Router (bounded at 120 s) and its result will be readable by you for 24 hours at `resultUrl` (also the `Location` header). Poll `GET /api/v1/router/payments/{id}/result`; do not repeat the call — a retry with the same `requestId` returns this same answer, then the result.
- `400`: Malformed request, a `delegationId` was supplied (BCK.OAUTH.0034 — it is derived from your grant), both `url` and `slug` were given (BCK.ROUTER.0001), 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 — refused before minting).
- `401`: Missing/invalid Nevermined API key — or the grant behind this credential has been revoked by the user, in which case every credential minted from it is invalid: restart the authorization to obtain a new one.
- `402`: The spend could not be authorized or funded — no money moved. Three distinct causes: BCK.ROUTER.0003, the delegation cap is exceeded or the delegation is expired / exhausted / revoked; BCK.ROUTER.0009, the buyer wallet does not hold enough of the settlement asset on the target network (crypto rails) or the issuer declined the card (MPP-stripe); BCK.ROUTER.0011, the card needs 3-D Secure cardholder authentication, which an agent with no human at a browser cannot complete. None is safely auto-retryable — branch on `code`.
- `403`: This credential is not a commerce grant (BCK.OAUTH.0033), or the EIP-7702 wallet gate refused the key (BCK.ROUTER.0008).
- `404`: Something the payment needs does not exist. BCK.DELEGATION.0002 — the delegation your grant is pinned to could not be resolved for this credential: it is not this account’s, or it is bound to a different grant than the one you hold. Re-run the authorization to mint a fresh mandate. You never send a delegation id on this route, so this is not a wrong-id error; an expired, exhausted or revoked delegation is a 402 (BCK.ROUTER.0003) instead. BCK.X402.0011 — the account has no Privy wallet, i.e. signup never completed. BCK.X402.0053 — the account’s embedded wallet has been deleted, so its smart account can no longer be reconstructed; Privy documents this as unrecoverable, so provision a new account. All three are permanent — retrying creates nothing.
- `409`: The `requestId` was already used — idempotency conflict (BCK.ROUTER.0002) — or the raw `url` targets a cataloged service and must be invoked by `slug` (BCK.ROUTER.0014, not retryable).
- `422`: Organization-wallet spend refused by the group budget: the group has exhausted its budget for this period (BCK.BUDGETS.0003), or it has no budget in the settlement currency (BCK.BUDGETS.0006). Only reachable when the delegation is funded by an organization wallet — a personal delegation never returns 422.
- `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`. Retryable after a backoff either way.
- `500`: BCK.ROUTER.0010 — the payment handler reported a settlement amount the routing-fee arithmetic cannot use. For THAT code specifically: a credential may already have been minted while no payment record was written, so your `requestId` will NOT suppress a retry — do not blind-retry, report it. BCK.ROUTER.0013 — Nevermined holds no EIP-712 signing domain for the selected settlement token; nothing was signed, charged or reserved, and a retry fails identically until our token table is fixed, so report it rather than looping. Any other 500 is an unexpected server error, may carry no `code` at all, and the guidance above does not apply to it — treat it as unknown.
- `503`: BCK.X402.0052 — the account’s EIP-7702 delegation designator could not be installed on the settlement network, and the Router refuses to pay from a wallet whose funds have not been swept to the signer. Reachable only where EIP-7702 is enabled. This is a transient infrastructure fault and the ONE failure on these routes an autonomous caller SHOULD retry — back off first.

---

[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)
