Skip to main content

What a widget actually is

A Fluz Widget is a hosted, Fluz-rendered flow that you embed in your own site with a few lines of JavaScript. It runs in a modal on top of your page, on your domain, under your branding. It exists to do three jobs that you should not have to build yourself:

Collect the user's permission

The widget is how an end user creates or logs into their Fluz account and grants your application the scopes it needs to act on that account. No grant, no API access.

Capture sensitive data

Card numbers, SSNs, identity documents, and PINs are collected by Fluz, inside Fluz’s PCI DSS environment, and encrypted on our side. They never touch your servers.

Confirm money movement

The user sees and approves the amount and direction of a transfer in a surface they can trust, which is what turns a pre-authorized token into a completed transaction.
Everything else — issuing the card, pulling the funds, checking the balance, reading transactions — is yours to do over the API, on your own schedule, with no user present.
The mental model: the widget is a consent and sensitive-data surface, not a product. It is the narrow, high-compliance part of the flow. The API is where the work happens.

The division of labor


You can run everything behind the scenes

This is the most commonly missed point about the widget: it is not the only way to use Fluz, and it is not the way most work gets done. Once a user has granted your application scopes — whether through the widget or through the standalone OAuth grant flow — your server holds a user access token. From that point, every capability listed on the API Features page is available to you programmatically, with no widget open and no user watching:

Funding sources

Link bank cards and Plaid bank accounts, then pull funds on demand.

Wallets & transfers

Open spend accounts, deposit, withdraw, and move funds internally or across accounts.

Virtual cards

Spend controls, lock/unlock, PINs, wallet provisioning, bulk issuance.

Open loop cards

Generate hosted card links recipients claim, with full link lifecycle control.

Send money

Look up recipients by phone or email and transfer to other Fluz wallets.

Approvals & authorized users

Add team members, issue them cards, and route approval requests.
The widget’s job is to get you to the token. What you do after that is entirely server-side.

Pick how much of the flow you hand to us

You do not have to choose “all widget” or “all API.” Most integrations land somewhere in the middle, and the deciding factor is usually what sensitive data you already hold and want to keep holding.
You hand us the whole user journey.The widget handles account creation, phone + 2FA login, KYC, PIN setup, the permissions grant, and the transaction confirmation. You render a button and generate a signed token.
  • Fastest path to production — measured in hours, not sprints.
  • Zero PCI scope, zero CIP data handling on your side.
  • Least control over look and feel between the click and the callback.
Good fit: payout and withdrawal flows, marketplaces, gig platforms, rewards programs — anywhere you want money to leave your system without you becoming a financial institution.
On registering users via API: if you register and KYC a user yourself and then open the widget, pass externalId in the pre-approved transaction token so we can match the session to the account you already created rather than starting a new one. You can also pass phoneNumber, firstName, lastName, email, and username to skip the corresponding steps in the widget. See Set Up Your Server.

How widgets relate to OAuth applications

A widget is an OAuth application. It is not a separate object with a separate permission model — it is an OAuth app that ships with an embeddable front end.
1

You define the ceiling (app scopes)

On the Permissions tab of your app, you select the scopes your application is allowed to request. This is the maximum your app can ever ask for, regardless of what any individual user agrees to. Scopes that a given widget type cannot function without are grouped at the bottom of the tab and cannot be unselected.See Application Scopes for the full list — MAKE_DEPOSIT, MAKE_WITHDRAW, LIST_PAYMENT, CREATE_VIRTUALCARD, REVEAL_VIRTUALCARD, PURCHASE_GIFTCARD, and the rest.
2

You configure where the grant can go (OAuth tab)

Origin — the domain hosting the widget. Redirect URIs — where our authorization server may send the user back, no query parameters, and it must match exactly at exchange time. Webhook URLs — one or many REST endpoints, each optionally subscribed to specific events; a URL with no events selected becomes a catch-all.See Configure App Widget.
3

The user sets the floor (user scopes)

When the widget opens, the user is shown the scopes you requested — grouped under readable top-level headers rather than listed as raw enum values — and approves them. Anything they decline is simply not granted.
4

Both grants must be live

An application’s effective permissions are the intersection of the app-level grant and the user-level grant, and both must be unexpired. This is enforced at generateUserAccessToken, not at call time — so a revoked or lapsed grant surfaces as a token failure, not a mysterious mid-flow error.
5

Code becomes tokens

The grant produces an authorization code at your redirect URI. Exchange it at /token/exchange with a Basic auth header of client_id:client_secret for an accessToken, a refreshToken, and the confirmed scope array. See Exchanging an authorization code and Refreshing an access token.
The pre-approved transaction token (patToken) and the OAuth access token are different things and do different jobs. The patToken is a short-lived, single-transaction JWT signed with your apiSecret that authorizes one movement of one amount. The OAuth accessToken is what lets your server act on a user’s account over time. A widget session typically involves both.

PCI compliance and sensitive data

When the widget is open, the sensitive fields inside it are Fluz’s, not yours. The user is typing into our iframe, posting to our servers, under our compliance program. That means Fluz takes responsibility for:
  • Card data. PANs, expiration dates, and CVVs are captured and stored in accordance with PCI DSS requirements and encrypted at rest on our side. Your page never sees them, your logs never contain them, and your infrastructure stays out of PCI scope for these flows.
  • Full card reveal. Showing an end user their own virtual card number is a hosted Fluz surface for the same reason.
  • CIP and identity data. SSNs, dates of birth, addresses, and uploaded identity documents are collected and retained inside our verification environment.
  • PINs. Set and stored by us, never transmitted to you.
  • Bank credentials. Plaid link flows run inside the widget; you never handle the user’s banking login.
What stays your responsibility: your apiSecret and client_secret. The Installation tab renders working snippets that contain your real credentials, which is convenient and also a hazard — generate the patToken on your server, never in browser JavaScript. Anything in your page source is public.
Fluz maintains SOC 2 Type II controls and handles card data in accordance with PCI DSS requirements. If your compliance team needs documentation for a vendor review, contact your Fluz account manager.

Getting your embed code

You do not hand-write the integration. The Installation tab of your app generates it for you, pre-filled with your app’s real apiKey, and gives you two selectors: Transaction Type — choose the direction of money movement: Server Language — the snippet that generates the signed pre-approved transaction token, in the language your backend actually uses:

JavaScript

Ruby

Python

Go

Java

PHP

C# / .NET

More

Switch the selector and the code block rewrites itself — correct JWT library, correct claim names, correct HS256 signing, correct one-day expiry. Copy it, drop in your apiSecret from your secret store, and you have a working token generator. Every variant is also documented in full at Set Up Your Server. The client-side half is a single script tag plus a FluzEmbedded.init(...) call. You can let us render the button, or bind the modal to a button you already have. See Adding the JS Widget to Your Page. Your app’s configuration lives at:
for example https://fluz.app/for-developers/overview/19be9561-a6a1-4e02-8243-10ede908ef33. The tabs across the top — Overview, Permissions, OAuth, Installation — map exactly to the steps above.

Start from a template

You do not start from a blank app. From the developer dashboard, choose Browse templates and pick the one closest to what you are building. A template pre-configures the app type, the required scopes, the transaction direction, and the sequence of screens the user will see — so a new app is functional the moment you finish naming it. Templates available today include:
Treat the template as a starting point, not a specification. After it is created, go to the Permissions tab and shape the app around what you are actually trying to do — add the scopes your use case needs, remove the ones it does not. A payout widget that will later issue cards on the user’s behalf needs CREATE_VIRTUALCARD; one that only moves cash does not. Requesting fewer scopes means a shorter consent screen and a higher completion rate, so ask for what you need and nothing more.
Creating an app: Add a New App Widget · Configuring it: Configure App Widget · Turning it off: Disable or Delete Your App

What the end user sees

Once a user reaches a page hosting your widget and takes the action that opens the modal:
1

Log in or register

The user authenticates to their Fluz account with a 2FA code sent to their phone. If they do not have an account, they create one here. Passing phoneNumber in the patToken skips straight to the code entry step.
2

KYC

If you already hold the user’s SSN, pass it to us and we validate it. If not, the widget runs the full KYC flow. Responses are APPROVED, DECLINED, DUPLICATE, or ERROR — see User KYC Verification for what each means and how many attempts a user gets.
3

Grant permissions

The user reviews and approves the scopes your app requested.
4

Set a PIN

A Fluz-wide security measure, prompted again later for actions requiring elevated confirmation.
5

Confirm the transaction

The user sees the amount and direction and either approves or dismisses. Either way, you get an event.

Pay-In: funds into your platform

Check the user’s Fluz balance first to confirm they can cover the transaction.
  1. The user enters a deposit amount and clicks your button.
  2. The widget presents a confirmation screen.
    • Confirmed → we initiate the transfer from the user’s spend account to yours.
    • Denied or dismissed → we send an event.
  3. You receive a completion or failure event.
  4. Verify your own Fluz balance to confirm settlement.

Payout: funds out to your user

Check your account’s Fluz balance first. If you cannot cover the transfer, initiate a deposit from your funding source. Quarantine or hold the user’s funds on your side to prevent double-spend while the transfer is in flight.
  1. The user enters a withdrawal amount and clicks your button.
  2. The widget presents a confirmation screen.
    • Confirmed → we initiate the transfer from your operator spend account to the user’s.
    • Denied or dismissed → we send an event.
  3. You receive a completion or failure event.
  4. The widget shows the user their withdrawal is complete and gives them direct access to their Fluz virtual card.
Every money-moving call needs a unique jti in the token for idempotency, and a unique idempotencyKey on the API side. See Idempotency.

Next steps

Add a widget

Create your first app from a template.

Configure OAuth & permissions

Scopes, origins, redirect URIs, webhooks.

Set up your server

Generate the pre-approved transaction token in your language.

Embed the widget

Script tag, init call, button binding.

Everything the API can do

The full capability surface, all of it available server-side.

Build a platform

Run every capability on connected accounts with customer-scoped tokens.