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.
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.
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.- Full widget
- Hybrid (most common)
- Headless / API only
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.
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.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.
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 realapiKey, 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
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:
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.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.
- The user enters a deposit amount and clicks your button.
- 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.
- You receive a completion or failure event.
- 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.
- The user enters a withdrawal amount and clicks your button.
- 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.
- You receive a completion or failure event.
- 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.