Directly in the App
Users go to nevermined.app, sign in, enroll a card, and create a delegation. Zero integration work.
White-label redirect (CLI)
Your CLI or backend prints a URL. The user clicks it, completes the flow in a chromeless page, and your process receives the IDs at a localhost callback.
Embedded widgets
Drop a Nevermined-hosted iframe straight into your own pricing page. Users never leave your domain.
Only the embedded widgets (option 3, iframe) are organization-scoped — they need an active Nevermined organization with a widget key. Options 1 and 2 work for anyone: option 1 for any signed-in user, and option 2 for any holder of an NVM API key. The redirect flow has an open path for autonomous agents (
POST /api/v1/embed/session, no organization required) and an org-scoped path (POST /api/v1/widgets/session/self) used by the nvm CLI and org members.1. Directly in the Nevermined App
The fastest path for end-users and the natural fit when your users are already a part of the Nevermined community. No code, no integration.Sign in to Nevermined
Open nevermined.app and sign in with email, Google, or GitHub. First-time users land on a short onboarding flow.
Open Settings > Payment Methods
In the Nevermined App, navigate to Settings > Payment Methods. This is the dashboard for every card you have enrolled and every active delegation.
Enroll a card
Click Enroll card and pick a provider tab: Stripe, Braintree, or Visa. Card data is captured in a PCI-compliant iframe and tokenized before submission — Nevermined never stores the raw card number.See Card Enrollment for the per-provider differences (Visa requires a passkey or OTP, Braintree supports PayPal alongside cards, Stripe needs 3DS where the issuer requires it).
Create a delegation
On the enrolled card row, click Delegate. Set:
- Spending limit in dollars (minimum $0.50). The delegation is rejected once the agent has charged this amount in total.
- Duration — 1 hour, 24 hours, 7 days, 30 days, or a custom value. The delegation expires automatically.
- Max transactions (optional) — hard cap on how many times the agent can charge the card.
- API key restriction (optional) — scope the delegation to a single API key so a compromised key can only spend the budget allowed to it.
2. White-label redirect (CLI / top-level tab)
For tools that run outside the browser — CLIs, terminal-based agents, desktop apps — but still need to authorize a card. The pattern mirrorsnvm login: print a URL, the user clicks it, the browser handles the chromeless card setup, and your process receives the result at a localhost callback.
This flow works with or without an organization, depending on which session you mint:
- Autonomous agents / buyers (no org): mint an open embedded session with
POST /api/v1/embed/session— any valid NVM API key, no organization needed. This is the path for AI agents purchasing on a user’s behalf. - Org members (e.g. the
nvmCLI): mint an org-scoped session withPOST /api/v1/widgets/session/self, which requires membership in the target organization.
sessionToken of the same shape that the embed app accepts; what differs is who can mint it and what the card/delegation attach to — your own Nevermined account via the embedded path, or the organization via the widget path. See Platform Partners for the organization features.How the handshake works
nvm CLI) mint the session with POST /api/v1/widgets/session/self ({ orgId, returnUrl }) instead — same handshake, but it requires membership in the target organization.
The shortest possible integration
The Nevermined Payments CLI ships ready-made commands for this flow:{embed}/cards/<route>?… — the standalone embed app (embed.nevermined.app for live, embed.nevermined.dev for staging), not the old webapp /embed/* routes — waits up to 5 minutes for the user to complete the flow, then exits cleanly with the resulting IDs. --no-browser prints the URL instead of opening it — useful over SSH or in CI.
Build your own (any language)
If you are writing a CLI in a language other than TypeScript, or you want this baked into your own backend, follow the four steps below.Start a one-shot localhost callback server
Bind to
127.0.0.1:0 (the OS picks a free port). Listen on /callback. Note the port for step 3. Never bind to 0.0.0.0 — the callback should not be reachable from the network.Mint a session
Authenticate the request with the user’s own NVM API key. Autonomous agents and buyers should use the open embedded session — it needs no organization:Response (200 OK):The card and delegation attach to the caller’s own account. There is no org-membership check, so the failure modes are only:
| HTTP | Meaning |
|---|---|
| 400 | returnUrl is not a valid http/https URL (DTO validation). |
401 BCK.APIKEY.0004 | The NVM API key is invalid or expired — run nvm login again. |
| 429 | Rate limited — the endpoint allows 30 mint calls per minute. Back off and retry. |
Org-scoped alternative: POST /api/v1/widgets/session/self
Org-scoped alternative: POST /api/v1/widgets/session/self
Org members (and the Additional failure codes:
nvm CLI) can instead mint an org-scoped session. It returns the same sessionToken shape, but requires membership in the target organization and takes an orgId:403 BCK.WIDGET_SESSION.0018 (the caller has no active organization memberships — if you’re a buyer/agent enrolling a card, use the open POST /api/v1/embed/session flow above instead) and 403 BCK.WIDGET_SESSION.0019 (the orgId is not one of the caller’s memberships — list them via /organizations/my-memberships).Open the browser
Construct the URL and open it with the OS browser-opener (
The
xdg-open / open / start):{embed} is the standalone embed app — https://embed.nevermined.app (live) or https://embed.nevermined.dev (staging). The card surfaces moved off the webapp /embed/* routes to this dedicated app. Three routes are available:| Route | Callback returns |
|---|---|
{embed}/cards/setup | paymentMethodId + delegationId (one-shot, both steps) |
{embed}/cards/enroll | paymentMethodId only |
{embed}/cards/delegate?paymentMethodId=<id> | delegationId only |
state value is echoed back in the redirect so you can bind the callback to this specific request (CSRF). 16 bytes (32 hex characters) of cryptographic randomness is the recommended minimum.Receive the callback
The browser redirects to
<returnUrl>?paymentMethodId=…&delegationId=…&state=<echo> on success.Your server must:- Verify the
statequery parameter matches the one you issued. Compare in constant time (crypto.timingSafeEqualin Node,hmac.compare_digestin Python). Reject mismatches with a 400. - Extract the ID(s) from the query string.
- Respond
200 OKwith a friendly “you can close this tab” HTML page. - Close the server.
nvm login flow — users may switch contexts between the terminal and the browser.Allowed returnUrl hosts
The server validates returnUrl against the session’s allow-list:
localhost,127.0.0.1,[::1](any port, any path) — accepted for both session kinds.- Other
https://origins — accepted only for widget-key sessions whose key has the origin in itsallowedOriginslist. - Self-mint sessions — both the open
POST /api/v1/embed/sessionand the org-scopedPOST /api/v1/widgets/session/selfdocumented above — reject any non-localhost host. Use the widget-key flow (see option 3) if you need remote redirects.
Security checklist
- Bind only to
127.0.0.1, not0.0.0.0. - Use a per-flow cryptographically random
state. Compare in constant time. - Treat the session token like a bearer credential — don’t log it, don’t persist it beyond the flow. It carries
apiKeyHashand expires in 2 hours. - The embed page strips
sessionTokenfrom the URL immediately after consumption, so the back button doesn’t replay it.
cli-card-setup.md in the Payments SDK repo.
3. Embedded widgets (iframe)
Your end-users never leave your domain. You mint a widget session on your server with the organization’s widget-key and pass it straight to the browser SDK — no token-exchange round-trip — and the user completes the card-enrollment + delegation flow inside your own page. The full guide — including how to generate a widget key, mint widget sessions server-side, mount the iframe on your page, and react tonvm:success / nvm:error events — lives in Embed Nevermined Widgets.
Choose this path when:
- Your users are in a browser already (a website, a SaaS dashboard) and you want to keep them on your domain.
- You need brand consistency — the iframe inherits the parent page’s framing and your organization’s branding theme.
- You want a postMessage event stream rather than a one-shot redirect.
Comparison
| Directly in App | White-label redirect | Embedded widget | |
|---|---|---|---|
| Where the user finishes | nevermined.app | A chromeless page in their browser | Your own page (iframe) |
| Integration effort | None | One HTTP server + one URL open | A widget key + iframe mount |
| Requires an organization | No | No (open embed session) — or org-scoped via the widget session | Yes |
| Best for | Power users, internal teams | CLIs, terminal-based agents, desktop apps | Websites, SaaS dashboards |
| Authentication | The user’s own Privy login | The user’s own NVM API key (Bearer) | Your server-minted widget session |
| Result delivery | UI state | paymentMethodId + delegationId at a localhost callback | nvm:success postMessage to the parent page |
| Cross-origin redirect | n/a | Localhost only (self-mint), or widget-key allowedOrigins | Same as widget-key allowedOrigins |
See Also
- Card Enrollment — per-provider enrollment internals (Visa / Stripe / Braintree)
- Mandates — what a delegation does once it exists
- Embed Nevermined Widgets — full widget-key + iframe guide
- x402 Card Delegation Spec — protocol-level reference
- Platform Partners — how to become an organization