Quick start
Every Nium Embed component uses the same Proof Key for Code Exchange (PKCE) authorization setup. Set it up once. Then change only the scopes array for each component. Each component guide gives its scope string.
Step 1: Install the packages
@nium/nium-sdk works with any frontend framework and includes TypeScript types. It runs in the browser only, so don't import it in server-side code.
Nium Embed supports these minimum browser versions:
| Browser | Minimum version |
|---|---|
| Chrome and Edge | 111 |
| Firefox | 113 |
| Safari, including iOS | 16.4 |
- npm
- Yarn
- pnpm
npm install @nium/nium-sdk js-base64
yarn add @nium/nium-sdk js-base64
pnpm add @nium/nium-sdk js-base64
Step 2: Generate the PKCE values
Run this code in your client.
import { Base64 } from 'js-base64'
export const generateCodeVerifier = () => {
const randomBytes = new Uint8Array(32)
crypto.getRandomValues(randomBytes)
return Base64.fromUint8Array(randomBytes, true)
}
const sha256 = async (plain: string) => {
const data = new TextEncoder().encode(plain)
return crypto.subtle.digest('SHA-256', data)
}
export const generateCodeChallenge = async (codeVerifier: string) => {
const hashed = await sha256(codeVerifier)
return Base64.fromUint8Array(new Uint8Array(hashed), true)
}
Step 3: Get an authorization code
Send the code challenge to your server. Your server, written in any language, calls the Nium auth endpoint and returns the authorization code.
Never call the Nium auth endpoint from the browser, because it exposes your x-api-key and clientSecret.
// server endpoint — never expose this in the browser
// sandbox shown — use https://api.nium.com in production
const response = await fetch(
`https://gateway.nium.com/client/${clientHashId}/oauth/authcode`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'YOUR_SECRET_TOKEN',
'X-Request-ID': crypto.randomUUID(), // required — unique per request, used for tracing and support
},
body: JSON.stringify({
clientHashId,
clientSecret: 'YOUR_CLIENT_SECRET',
codeChallenge,
scopes: ['SCOPE_FOR_THIS_FORM'], // changes per component — see each guide
}),
}
)
const { authorizationCode, expiresInSecs } = await response.json()
| Environment | Base URL | env value in init() |
|---|---|---|
| Sandbox | https://gateway.nium.com | sandbox |
| Production | https://api.nium.com | production |
Use the base URL that matches the env you pass to init() in Step 4. This applies to every component.
The response includes the authorizationCode and expiresInSecs, the number of seconds until the code expires (typically 300). Pass the code to init() before it expires, and request a new one if it does.
Step 4: Initialize the SDK and mount the component
Run this code in your client.
import { init, createElement } from '@nium/nium-sdk'
import { generateCodeVerifier, generateCodeChallenge } from './pkce'
// 1. Generate PKCE pair on the client
const codeVerifier = generateCodeVerifier()
const codeChallenge = await generateCodeChallenge(codeVerifier)
// 2. Send codeChallenge to your server — receive authorizationCode
const { authorizationCode } = await yourServerEndpoint({ codeChallenge })
// 3. Initialize the SDK
await init({
env: 'production', // or 'sandbox'
authCode: authorizationCode, // from your server
codeVerifier,
clientId: 'YOUR_CLIENT_HASH_ID',
})
// 4. Create and mount the component
const element = await createElement('<type>', { /* component-specific options, such as customerHashId */ })
element.mount('#container') // the id of the div where you want the iFrame
The SDK doesn't keep its session across a page reload. After a reload, or after an AUTH_EXPIRED error, repeat Steps 2 to 4 with a new authorization code.
Ask Nium support during onboarding to allowlist every domain that hosts a component, such as production and staging. This is a setup step, not an init() parameter. localhost works for development, and the component also runs in a WebView.
Step 5: Listen to events
Subscribe to the events that the component fires.
element.on('ready', () => { /* the component has loaded */ })
element.on('submit', (e) => {
// not every component emits submit, and the payload varies — see each guide
console.log(e.result)
})
element.on('error', (e) => { /* surface e.error.message to the user */ })
Every component fires ready and error. Only some components fire submit, and only Convert currencies fires cancel. Check each guide for the events it emits.
Best practices
These practices apply to all Nium Embed integrations.
- Generate the auth code on your server. Never call the Nium auth endpoint from the browser, because it exposes your API key. Your frontend generates the PKCE
codeVerifierandcodeChallenge. Send only thecodeChallengeto your server to get the auth code. Keep thecodeVerifierin your frontend and pass it toinit(). - Use
element.submit()only where it's supported. If one Next button in your UI advances across steps, programmatic submit lets your outer flow control the iFrame. Only the Beneficiary Management (payment) form supports it today. Other components reject withSUBMIT_UNSUPPORTED. - Apply
brandColorfor brand alignment.brandColorapplies your brand color to buttons, links, selected cards, focus rings, and tints in the iFrame. You inject no custom CSS. Addpreset: 'dark'if your platform uses a dark UI. - Handle
errorevents. Always wire the error handler and show your users clear feedback. Some failures, such as a failed quote or a validation error, appear only inside the iFrame, so your handler covers setup and session failures.
Next steps
- Nium Embed: Pick the component you want to add.
- Theme customization: Match the look of your platform.