> ## Documentation Index
> Fetch the complete documentation index at: https://nevermined.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Route and Pay from a Commerce Grant

> 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.



## OpenAPI

````yaml POST /router/commerce/route
openapi: 3.1.0
info:
  title: Nevermined API
  description: >-
    API for managing AI agents, payment plans, and x402 payments in the
    Nevermined ecosystem.


    ## Prerequisites


    You need a Nevermined API Key to authenticate. Get one at
    [nevermined.app](https://nevermined.app) under **Settings > API Keys**.


    See the [5-Minute Setup Guide](/docs/integrate/quickstart/5-minute-setup)
    for detailed instructions.
  license:
    name: MIT
  version: 1.0.0
servers:
  - url: https://api.sandbox.nevermined.app/api/v1
    description: Sandbox (Testing) - Base Sepolia
  - url: https://api.live.nevermined.app/api/v1
    description: Live (Production) - Base Mainnet
security:
  - bearerAuth: []
tags:
  - name: Protocol - Agents
    description: Endpoints for registering and managing AI agents
  - name: Protocol - Plans
    description: Endpoints for creating and managing payment plans
  - name: Protocol - Credits
    description: Endpoints for minting and redeeming credits
  - name: Protocol - Access
    description: Endpoints for access tokens and request validation
  - name: X402 - Permissions
    description: Endpoints for x402 delegated permissions
paths:
  /router/commerce/route:
    post:
      tags:
        - Router
      summary: >-
        Route and pay using the delegation from your commerce grant (mode B,
        OAuth)
      description: >-
        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.
      operationId: routeAndPayRequestFromGrant
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CommerceRouteRequestDto'
            examples:
              invoke-cataloged-service:
                summary: >-
                  Invoke a cataloged service through the broker, paid from the
                  grant
                value:
                  slug: webscrape-pro
                  path: scrape
                  method: POST
                  body:
                    url: https://example.com
                  requestId: order-1234
      responses:
        '201':
          description: Upstream response, relayed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RouteResultDto'
        '400':
          description: >-
            Malformed request, a `delegationId` was supplied (BCK.OAUTH.0034 —
            it is derived from your grant), or both `url` and `slug` were given
            (BCK.ROUTER.0001).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RouterErrorResponseDto'
        '401':
          description: >-
            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.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RouterErrorResponseDto'
        '402':
          description: >-
            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`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RouterErrorResponseDto'
        '403':
          description: >-
            This credential is not a commerce grant (BCK.OAUTH.0033), or the
            EIP-7702 wallet gate refused the key (BCK.ROUTER.0008).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RouterErrorResponseDto'
        '404':
          description: >-
            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.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RouterErrorResponseDto'
        '409':
          description: >-
            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).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RouterErrorResponseDto'
        '422':
          description: >-
            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.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RouterErrorResponseDto'
        '429':
          description: >-
            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.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RouterErrorResponseDto'
        '500':
          description: >-
            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.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RouterErrorResponseDto'
        '503':
          description: >-
            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.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RouterErrorResponseDto'
components:
  schemas:
    CommerceRouteRequestDto:
      type: object
      properties:
        url:
          type: string
          description: >-
            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.
          example: https://agent.example/api/resource
        slug:
          type: string
          description: >-
            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`.
          example: webscrape-pro
        path:
          type: string
          description: >-
            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.
          example: scrape
        method:
          type: string
          description: HTTP method to use for the upstream request.
          enum:
            - GET
            - POST
            - PUT
            - PATCH
            - DELETE
          default: GET
        headers:
          type: object
          description: >-
            Headers to forward to the upstream (e.g. the agent’s own auth).
            Optional.
        body:
          description: Request body to forward (JSON). Optional.
        protocol:
          type: string
          description: >-
            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).
          enum:
            - x402
            - mpp
          default: x402
        requestId:
          type: string
          description: >-
            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.
          example: order-1234
      required:
        - requestId
    RouteResultDto:
      type: object
      properties:
        status:
          type: number
          description: The upstream HTTP status code that was relayed.
          example: 200
        body:
          description: >-
            The upstream response body (parsed JSON when the upstream returned
            JSON, else a string).
          example:
            ok: true
            data: the paid resource
        paid:
          type: boolean
          description: Whether a payment was made (false = the upstream was free).
          example: true
        payment:
          description: The payment made, when `paid` is true.
          allOf:
            - $ref: '#/components/schemas/RouteResultPaymentDto'
      required:
        - status
        - body
        - paid
    RouterErrorResponseDto:
      type: object
      properties:
        code:
          type: string
          description: >-
            Router error code. `BCK.ROUTER.0001` invalid request / no fundable
            option / bad 402 (400); `BCK.ROUTER.0002` requestId already used —
            idempotency conflict (409); `BCK.ROUTER.0003` delegation budget
            exceeded, expired, or inactive (402); `BCK.ROUTER.0004` payment
            record not found (404); `BCK.ROUTER.0005` payment not in a
            settleable state (409). Framework-level `BCK.HTTP.*` codes (e.g.
            `BCK.HTTP.400` request validation, `BCK.HTTP.429` throttling) may
            also appear — see the base `code` field.
          example: BCK.ROUTER.0003
        httpStatus:
          type: number
          description: HTTP status code
          example: 500
        message:
          type: string
          description: Error message for Router operations.
          example: delegation budget exceeded, expired, or inactive
          examples:
            - >-
              delegationId is required — create one via POST
              /api/v1/delegation/create
            - 'no fundable option; offered: [...]'
            - >-
              upstream pay-to address is not in this delegation's allowed
              recipients
            - delegation budget exceeded, expired, or inactive
            - payment already settled with a different txHash
        details:
          type: string
          description: >-
            Throw-site detail string supplementing the canonical message. Only
            set when the call site supplied an opts.message; absent otherwise.
          example: Hash JWT is not signed by the node account
        error:
          type: string
          description: >-
            RFC 6749 §5.2 / RFC 8628 §3.5 top-level OAuth error string. Present
            only on the OAuth device-polling responses from `POST /oauth/token`
            (`authorization_pending`, `slow_down`, `expired_token`,
            `access_denied`), so a standards-compliant OAuth/device client can
            branch on it directly instead of on the Nevermined `code`. Absent on
            every other error.
          example: authorization_pending
        hint:
          type: string
          description: >-
            Actionable remediation hint, sourced from the catalogue or supplied
            at the throw site. Tells the caller what to fix or where to look.
          example: >-
            Verify the wallet has sufficient balance and that the plan is
            active.
        docsUrl:
          type: string
          description: Permalink to the docs page describing this error code.
          example: >-
            https://nevermined.ai/docs/development-guide/api-errors/codes#bck-x402-0008
        category:
          type: string
          description: >-
            Coarse classification of the failure, useful for client-side
            branching without parsing the message.
          enum:
            - validation
            - auth
            - business
            - integration
            - internal
          example: integration
        retryable:
          type: boolean
          description: >-
            Whether the failure is transient and the same call can be retried
            with identical inputs. Absent when the catalogue does not assert
            either way.
          example: true
        correlationId:
          type: string
          description: >-
            Request-scoped correlation id stamped by the global filter. Echoed
            in the x-correlation-id response header. Quote this when reporting
            issues.
          example: a3f6b1c4-7d2e-4a9b-8e0c-12f4d8e6c5b9
        uuid:
          type: string
          description: >-
            Per-error UUID generated at construction. Useful for log
            correlation.
          example: e-550e8400-e29b-41d4-a716-446655440000
        date:
          type: string
          description: ISO timestamp at which the error was constructed.
          example: '2026-05-09T12:34:56.789Z'
          format: date-time
        params:
          type: string
          description: >-
            JSON-stringified contextual parameters supplied at the throw site
            (e.g. IDs, state). Always a string in the wire format — parse with
            JSON.parse if needed.
          example: '{"planId":"43298432984329","reason":"Invalid configuration"}'
      required:
        - code
        - httpStatus
        - message
    RouteResultPaymentDto:
      type: object
      properties:
        paymentId:
          type: string
          example: b1f9c2e4-3d5a-4c7e-9f21-6a8b0c4d2e13
        settlement:
          $ref: '#/components/schemas/SettlementDescriptorDto'
        fee:
          description: >-
            Nevermined’s routing fee for this payment. Mode B charges it exactly
            as mode A does, so it is disclosed here too —
            `settlement.approxCents` is only the merchant leg, and
            `fee.capChargedCents` is what the delegation cap was actually
            debited.
          allOf:
            - $ref: '#/components/schemas/RouterFeeDto'
        txHash:
          type: string
          description: On-chain settlement tx, if the upstream reported one.
          nullable: true
        status:
          type: string
          enum:
            - Issued
            - Settled
          example: Settled
      required:
        - paymentId
        - settlement
        - fee
        - status
    SettlementDescriptorDto:
      type: object
      properties:
        recipient:
          type: string
          description: The on-chain recipient (the agent’s `payTo` address from its 402).
          example: '0x209693Bc6afc0C5328bA36FaF03C514EF312287C'
        amount:
          type: string
          description: Amount in the asset’s smallest unit (USDC/EURC = 6 decimals).
          example: '1000'
        asset:
          type: string
          description: >-
            For x402 the asset symbol (`USDC`/`EURC`); for mpp the tempo payment
            token contract address (mpp carries no on-wire symbol).
          example: USDC
        network:
          type: string
          description: Network the payment settles on (name or CAIP-2).
          example: base-sepolia
        approxCents:
          type: string
          description: >-
            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 total debited
            from the delegation is `approxCents + fee.cents` (also reported
            directly as `fee.capChargedCents`). With no fee configured the two
            are equal.
          example: '1'
        scheme:
          type: string
          description: >-
            Ledger settlement scheme: `exact` for x402 (EIP-3009), `charge` for
            mpp (native Tempo tx). Omitted (defaults to `exact`) on the x402
            path.
          enum:
            - exact
            - charge
          example: exact
      required:
        - recipient
        - amount
        - network
        - approxCents
    RouterFeeDto:
      type: object
      properties:
        bps:
          type: number
          description: >-
            Rate applied to this payment, in basis points over a 10,000
            denominator (e.g. `200` = 2%). `0` means no routing fee was charged.
          example: 0
        amount:
          type: string
          description: >-
            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.
          example: '0'
        cents:
          type: string
          description: >-
            Cents this fee added to the delegation-cap reserve, i.e.
            `capChargedCents - settlement.approxCents`.
          example: '0'
        capChargedCents:
          type: string
          description: >-
            Total debited from the delegation cap for this payment (merchant leg
            + routing fee), in cents.
          example: '1'
      required:
        - bps
        - amount
        - cents
        - capChargedCents
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        Your Nevermined API Key (starts with 'nvm:'). Get one at
        [nevermined.app](https://nevermined.app) under **Settings > API Keys**.

````