Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.nevermined.app/llms.txt

Use this file to discover all available pages before exploring further.

If you run a Nevermined organization, you can embed Nevermined-hosted UI flows directly into your site instead of redirecting customers to nevermined.app. Your end-users stay on your domain; the iframe handles auth, payments, and card delegations against the Nevermined backend.
This guide is for organization admins. If you haven’t upgraded to an organization yet, see Platform Partners first.

What you can embed

Checkout

Sell agent plans from your own pricing page. Reports a transaction hash on success.

Card enrollment

Let users add a payment method without leaving your site. Returns the resulting paymentMethodId.

Card delegation

List enrolled cards, create delegations, and revoke either — without redirecting to nevermined.app.

How it works

Your server  →  createInitToken({ userId, orgId, secretKey })
             →  initToken (JWT, valid 5 minutes)

Browser      →  NeverminedWidgets.initialize({ initToken, environment })
             →  exchanges initToken for a session, mounts iframe(s)

Iframe       →  postMessage events: nvm:ready, nvm:success, nvm:error, nvm:close
The widget secret never leaves your server. Your backend mints a short-lived initToken per browser session; the SDK exchanges it for a 2-hour widget session that scopes every API call to a single end-user from your system.
The secretKey is the equivalent of a password for your organization’s widget surface. Anyone who has it can mint tokens that act as any end-user of your org. Keep it in environment variables on a server you control — never commit it, never bundle it into client-side JavaScript.

Setup

1

Generate a widget key

Open Settings > Organization in the Nevermined App and scroll to the Widget Integration section.Widget Integration section before any key existsClick Generate widget key and fill in the dialog:
  • Name — a descriptive label, e.g. Production website.
  • Allowed origins — every domain where the widget will be mounted, e.g. https://yourcompany.com and https://staging.yourcompany.com. At least one origin is required. Use Add origin to add more rows. No path, query, fragment, or trailing slash. Generate widget key dialog with name and allowed origins
The Nevermined backend rejects widget sessions whose parentOrigin doesn’t match this allowlist — it’s your second line of defense if the secret ever leaks. You can edit the list later from the key’s actions menu without rotating the secret.Click Generate key. The raw secret is shown once. Copy it and store it as an environment variable on your server (for example, NVM_WIDGET_SECRET). You won’t see it again.Widget secret shown once after creation
If you lose the secret, revoke the key from the dashboard and generate a new one. There’s no recovery path — that’s by design.
2

Mint the initToken on your server

Install the server SDK on your backend and expose a small endpoint that signs an initToken for the currently logged-in end-user.
npm install @nevermined-io/ui-widgets-server
The call is the same regardless of framework:
import { createInitToken } from '@nevermined-io/ui-widgets-server'

const initToken = await createInitToken({
  userId: '<the end-user id from your system>',
  orgId: '<your org id from the dashboard>',
  secretKey: process.env.NVM_WIDGET_SECRET!,
})
Pick the framework that matches your stack:
// vite.config.ts
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [
    {
      name: 'nvm-init-token',
      configureServer(server) {
        server.middlewares.use('/api/init-token', async (req, res) => {
          const { createInitToken } = await import('@nevermined-io/ui-widgets-server')
          const initToken = await createInitToken({
            userId: req.headers['x-user-id'] as string, // resolve from your auth
            orgId: process.env.NVM_ORG_ID!,
            secretKey: process.env.NVM_WIDGET_SECRET!,
          })
          res.setHeader('content-type', 'application/json')
          res.end(JSON.stringify({ initToken, environment: 'sandbox' }))
        })
      },
    },
  ],
})
userId identifies the end-user of your site, not the org admin. Resolve it from your auth session — Nevermined uses it as the sub of the session JWT to scope every widget action to that user.
3

Mount the widget in the browser

Install the browser SDK on your frontend.
npm install @nevermined-io/ui-widgets
Fetch the initToken from your endpoint and initialize the SDK. The same nvm instance can mount any of the available widgets.
import { NeverminedWidgets } from '@nevermined-io/ui-widgets'

const { initToken, environment } = await fetch('/api/init-token').then(r => r.json())
const nvm = await NeverminedWidgets.initialize({ initToken, environment })
Then mount whichever widget you need into a container element on your page:
nvm.checkout.start({
  did: 'did:nv:<your-agent-did>',
  // planId is optional; omit to show the plan carousel
  container: document.getElementById('checkout-widget')!,
  onReady: () => console.log('Widget rendered'),
  onSuccess: ({ did, planId, txHash }) => {
    console.log('Purchase complete', { did, planId, txHash })
  },
  onError: (err) => console.error('Checkout failed', err),
  onClose: () => console.log('User closed the widget'),
})

Available widgets

MethodMounts iframeResult
nvm.checkout.start({ did, planId?, container, ... })yesonSuccess: { did, planId, txHash }
nvm.delegations.enrollCard({ container, ... })yesonSuccess: { paymentMethodId }
nvm.delegations.listCards({ container, onCardAction, ... })yesonCardAction: { action: 'delegate', paymentMethodId }
nvm.delegations.createDelegation({ paymentMethodId, container, ... })yesonSuccess: { delegationId, paymentMethodId }
await nvm.delegations.revokeCard(paymentMethodId)no — direct API callresolves on 2xx
await nvm.delegations.revokeDelegation(delegationId)no — direct API callresolves on 2xx
All iframe-mounting methods share the same lifecycle:
CallbackWhen
onBootediframe DOM mounted (auth not yet validated)
onReadysession validated, widget interactive
onSuccessterminal success — widget destroys itself
onErrorterminal error — widget destroys itself
onCloseuser closed the widget — instance destroyed
Once a widget instance fires onSuccess, onError, or onClose, it’s terminal: calling its method again throws. Construct a fresh widget via the same nvm instance to mount another flow.

Environments

Pick the environment that matches the Nevermined dashboard you used to mint the widget key.
EnvironmentAPI baseWebapp baseWhen to use
sandboxhttps://api.sandbox.nevermined.apphttps://nevermined.appTesting on Base Sepolia with sandbox credentials
livehttps://api.live.nevermined.apphttps://nevermined.appProduction on Base mainnet

Production checklist

Server-side secrets only

Keep NVM_WIDGET_SECRET in your runtime env vars. Never commit it, never ship it to the browser, never put it in NEXT_PUBLIC_* or VITE_* variables.

Allowed origins populated

Add every domain where you mount the widget. The backend rejects sessions from any other origin.

HTTPS only

Serve both your site and your initToken endpoint over HTTPS in production. parentOrigin includes the scheme, so origins must match exactly.

Real userId per session

Pass the actual end-user identifier from your auth — never a placeholder, never the same value for every visitor.

Rotate on suspicion

If the secret might have leaked, revoke the key from the dashboard and generate a new one. Update your env var and redeploy.

Short token TTLs

Default initToken expiry is 5 minutes — leave it. Don’t cache the token server-side.

Troubleshooting

SymptomCauseFix
onError: UNAUTHORIZED, apiCode BCK.WIDGET_SESSION.0001initToken expired or signed with a wrong/revoked secretMint a fresh token; verify your secret matches the active key in the dashboard
onError: UNAUTHORIZED, apiCode BCK.WIDGET_SESSION.0002The org has no active widget keysGenerate one in the dashboard
onError: UNAUTHORIZED, apiCode BCK.WIDGET_SESSION.0005Session token expired (default 2h)The SDK auto-refreshes; if it fails persistently, re-fetch the initToken from your server
onError: UNAUTHORIZED, apiCode BCK.WIDGET_SESSION.0007initToken missing orgId or wallet claimUpgrade @nevermined-io/ui-widgets-server to the latest version
onError: UNAUTHORIZED, apiCode BCK.WIDGET_SESSION.0011The widget key was revoked while the session was aliveMint a new initToken with the new key
onError: NETWORKFetch failed before getting a responseCheck your network, CORS, and that the environment matches the API you minted the key against
Widget mounts but never fires onReadyparentOrigin doesn’t match allowedOriginsAdd your site’s origin to the key’s allowlist (mind the scheme: https:// vs http://)
[NeverminedWidgets] initialize: invalid environmentenvironment is not a supported valueUse 'sandbox' or 'live'

Platform Partners

Background on Nevermined organizations and how to upgrade your account.

Card enrollment

How Nevermined card enrollment works under the hood — the widget surfaces this same flow.