Build a wallet assistant for a fintech app, balance, spending & income insights, transaction status, and web embed
This recipe walks end-to-end:
Create the agent in the dashboard
Ground answers with a knowledge base
Wire HTTP actions to the fintech-api backend for wallet balance, spending/income insights, and transaction status
Deploy the SaaS chat widget
Embed the widget in your Next.js web app
The reference backend lives at fintech-api/ in the Chatropic repo (port 8083). The reference frontend is chatropic-demo-web/. You can swap in your own API URLs, the dashboard setup is the same.
Ground policy and UX answers so the agent does not guess when no API call is needed.
1
Open Documents
Documents, choose Text or Files.
2
Add fintech FAQ content
Paste or upload content covering:
What Completed vs Failed transaction status means
How income vs spending is classified (deposits, exchanges, card top-ups)
Supported insight periods (7d, 30d, 90d, 1y)
Security: the agent never asks for full card numbers or passwords in chat
Escalation: when to offer human support for disputed charges
3
Example FAQ snippet
## Transaction status- **Completed**: funds moved successfully; appears in balance and insights.- **Failed**: payment did not complete; amount is not credited. User may retry or use another method.## Spending & income insights- **Income**: money added to the wallet (e.g. Apple Pay top-up).- **Spending**: money out (e.g. currency exchange, transfers).- Insights exclude failed transactions.- Period filters: last 7 days (7d), 30 days (30d), 90 days (90d), 1 year (1y).
4
Test retrieval
New test session, ask “What does a failed transaction mean?”, answer should cite your document, not invent policy.
Data sources
Website crawl, file upload, and text paste options.
JWTs expire (default 24h). Refresh the token in Manage tokens when Playground tests start returning 401.
3
Use in action headers
On each HTTP action, add:
Authorization: Bearer {{token.fintech_demo_jwt}}
Best for end-to-end Playground or embed testing where each visitor signs in with their own wallet credentials.fintech-api exposes a minimal OAuth2 authorization-code flow that returns the same JWT used by wallet endpoints.
1
Confirm OAuth endpoints
With fintech-api running on port 8083:
Endpoint
URL
Authorize
http://localhost:8083/oauth/authorize
Token
http://localhost:8083/oauth/token
Demo OAuth client (override via env):
Field
Value
Client ID
fintech_demo
Client secret
fintech-demo-secret
2
Create customer login token
Manage tokens: new Customer login token
Field
Value
Name
fintech_wallet
Auth URI
http://localhost:8083/oauth/authorize
Token URI
http://localhost:8083/oauth/token
Client ID
fintech_demo
Client secret
fintech-demo-secret
Redirect URI
Copy from the dialog (e.g. http://localhost:8000/api/oauth/fintech_wallet/callback)
Chat message
Sign in to connect your wallet so I can check your balance and transactions.
Link label
Sign in to wallet
Generate an identity signing secret and store it on your demo app backend (see next step).
3
Use in action headers
On each HTTP action, use the per-user token instead of the static JWT:
Authorization: Bearer {{token.fintech_wallet}}
Keep the Demo (static JWT) tab configuration if you still want a quick Playground path without OAuth, use one header style per action, not both.
4
Pass embed identity (Playground or demo web)
Customer login requires a stable end-user id so OAuth tokens persist across chat sessions.Playground: open Settings and set End user ID (e.g. alex-smith-demo). For local testing you can omit a signed identity JWT when the Playground allows it.Demo web (chatropic-demo-web): when the user is logged in, pass endUser and a signed identity JWT on the Chatropic embed URL. Mint the identity JWT on your backend with the signing secret from Manage tokens (sub = user id, exp = short TTL). See Web embed, Customer login.
5
Test the flow
Ask the agent: “What’s my balance?”
When prompted, click Sign in to wallet: you are redirected to the demo login page (alex.smith@demo.com / Demo1234!).
After authorization, retry the question, actions call fintech-api with the user’s OAuth JWT.
Recommended for chatropic-demo-web: the reference Next.js host. The user signs in on your app; your backend stores their fintech JWT and exposes an agent BFF that Chatropic calls with a static service token plus the signed-in user’s id.
1
Create a static BFF token in Chatropic
Manage tokens: new Static token
Field
Value
Name
demo_bff
Secret
Same value as CHATROPIC_AGENT_BFF_TOKEN in chatropic-demo-web/.env.local
Or run the setup script (reads .env.local and wires all wallet actions to the BFF):
cd chatropic-demo-webnpm run setup:chatropic-bff
2
Point wallet actions at your BFF
HTTP actions call your Next.js app, not fintech-api directly. Use the same headers on every action:
Replace localhost:3001 with your NEXT_PUBLIC_APP_URL in other environments. Chatropic substitutes {{end_user_id}} from the embed’s endUser param on each turn.
3
Register the fintech session after login
When the user signs in to your app, POST their fintech user id and access token to your BFF session route so the agent can proxy wallet calls:
The reference app calls registerAgentSession() on:
Login (app/login/page.tsx)
Wallet load (components/wallet-provider.tsx)
Drawer open (components/chatropic-drawer.tsx), re-syncs after a dev server restart
On logout, call DELETE /api/agent/session with { userId } via unregisterAgentSession() before clearing local auth (components/sidebar.tsx).
4
Pass embed identity
Mount <ChatropicDrawer endUserId={session.user.id} /> in your authenticated shell. The drawer appends endUser and a signed identity JWT to the iframe URL (/api/chatropic/identity on your backend). The widget forwards endUser to the agent on every message so {{end_user_id}} resolves to the fintech user UUID, not the anonymous chat session id.
5
Environment variables
In chatropic-demo-web/.env.local:
NEXT_PUBLIC_FINTECH_API_URL=http://localhost:8083NEXT_PUBLIC_APP_URL=http://localhost:3001CHATROPIC_AGENT_BFF_TOKEN=<shared secret, also stored as demo_bff in Manage tokens>CHATROPIC_IDENTITY_SIGNING_SECRET=<from Manage tokens>NEXT_PUBLIC_CHATROPIC_EMBED_URL=<from Deploy, SaaS app, Copy drawer snippet>
The in-memory session store in the demo app is for local development only. Production should use Redis or your session database keyed by userId.
For a real SaaS app, do not share one user’s JWT for all visitors.
1
Backend-for-frontend (recommended)
Expose agent-safe routes on your backend (e.g. GET /api/agent/wallet) that:
Validate a static service token from Chatropic (Authorization: Bearer {{token.my_bff}})
Read the signed-in user from X-End-User-Id: {{end_user_id}} (forwarded from the embed)
Look up that user’s fintech access token in your session store (registered at login via POST /api/agent/session)
Call fintech-api with the user’s token server-side and return JSON
Clear the mapping on logout with DELETE /api/agent/session.
2
Register sessions at login
After your app authenticates the user, store { userId, fintechAccessToken } server-side and expose a small registration endpoint the client calls once per login (and again when the chat drawer mounts, to survive dev restarts). See chatropic-demo-web/src/lib/agent-session-client.ts.
3
Embed identity
When the user is logged in on your site, pass endUser and identity on the embed URL so actions resolve {{end_user_id}} to the correct wallet. See Web embed, Customer login.
Several fintech actions use URL placeholders such as {{period}} or path segments like {{transaction_id}}. The agent never hand-builds the URL, it fills Parameters on the action, and Chatropic substitutes them before the HTTP call.
1
Declare parameters on the action
On each action’s configure page, set Parameters (JSON Schema). Property names must match the placeholders in the URL (period, direction, transaction_id).Use enum for fixed API values (e.g. 7d, 30d, 90d, 1y) so the planner picks valid query values. Mark fields required when the API needs them.
2
Planner picks the action and values
Each turn, the agent reads the user’s message and enabled action descriptions. When a message matches (e.g. “How much did I spend this month?”), it selects get_spending_income_insights and sets action_params, inferring period: "30d" from phrases like “this month” or “last 30 days”.
3
Substitute into the request
Before calling fintech-api, Chatropic replaces {{period}} (and other placeholders) in the URL with resolved values. Literals in the URL, such as include_insights=true: are sent on every call and do not need a parameter.
4
Ask when something is missing
If a required parameter is still empty (e.g. user asks “Why did my payment fail?” without an id), the agent asks one follow-up question (“Which transaction, do you have an id or title?”), remembers the answer across turns, then retries the action.
5
Param mapping (usually skip for this demo)
Param mapping is only needed when API query names differ from your parameter names (e.g. map action period, API time_range). For fintech-api, names match the placeholders, leave Param mapping empty.
User says
Agent sets
Request
”Spending this month”
period: "30d"
GET .../transactions?period=30d&include_insights=true
”Show income last 7 days”
period: "7d", optionally direction: "income"
GET .../transactions?period=7d&direction=income
”Status of transaction 3”
transaction_id: "3"
GET .../transactions/3
Use the action Test panel with sample parameters (e.g. period: "30d") to verify URL substitution before testing in Playground.
Return income and spending totals for a time period when the user asks “how much did I spend”, “income this month”, “net for last 30 days”, or similar insight questions.
Paste into Parameters on the action configure page:
{ "type": "object", "required": ["period"], "properties": { "period": { "type": "string", "description": "Relative time window for income and spending totals", "enum": ["7d", "30d", "90d", "1y"] } }}
The agent maps natural language to these values, “this month”, 30d, “last week”, 7d. If the user does not mention a range, the agent defaults to 30d or asks which period they mean.
Get full details and status for one transaction when the user asks about a specific payment, failed top-up, or exchange by reference or after picking from a list.
{ "type": "object", "required": ["transaction_id"], "properties": { "transaction_id": { "type": "string", "description": "Transaction id from a prior list or user reference (e.g. 1, 2, 3)" } }}
If the user does not supply an id, the agent typically calls list_transactions first or asks which payment they mean, then calls this action with the resolved transaction_id.
Playground or the Content tab on Chat widget: add chips such as:
What’s my balance?
Spending this month
Show income last 7 days
Why did my last payment fail?
2
Behavior hints
Add a short Text source to steer behavior:
For insight questions, call get_spending_income_insights with the closest period (7d, 30d, 90d, 1y). For a single payment, call get_transaction_status. Combine API results with knowledge base policy text. Never request passwords or full card numbers in chat.
3
Guardrails
Security settings: block investment advice or out-of-scope topics if needed; add Escalate to human for disputes.
Only runtime params stay in the URL: mode, endUser, identity (signed-in users), and session (Playground preview only).
Layout
Snippet
SaaS drawer
On SaaS app, use Copy drawer snippet (mode=drawer)
Website widget
On Chat widget, use Copy website widget code (mode=launcher)
Inline panel
Copy inline panel code
5
Verify
Open side drawer demo (SaaS app) or Open floating launcher demo (Chat widget), send a test message, confirm Chat logs.
Production embed snippets omit a pinned session param so each visitor gets an anonymous thread. For logged-in SaaS users, append endUser and identity dynamically, see SaaS app.
Use the chatropic-demo-web Next.js app as the reference host. After a user signs in, register their fintech session with your agent BFF, then mount the SaaS drawer so the assistant can resolve {{end_user_id}} to the correct wallet.
1
Environment variables
In chatropic-demo-web/.env.local:
NEXT_PUBLIC_FINTECH_API_URL=http://localhost:8083NEXT_PUBLIC_APP_URL=http://localhost:3001CHATROPIC_AGENT_BFF_TOKEN=<shared secret, create as demo_bff in Manage tokens>CHATROPIC_IDENTITY_SIGNING_SECRET=<from Manage tokens>NEXT_PUBLIC_CHATROPIC_EMBED_URL=<from Deploy, SaaS app, Copy drawer snippet>
Or set NEXT_PUBLIC_CHATROPIC_PUBLISHABLE_KEY: the demo app builds https://chatropic.com/embed/key/{publishable-key} and appends mode=drawer, endUser, and identity at runtime.Wire the wallet action to your BFF (one-time):
cd chatropic-demo-webnpm run setup:chatropic-bff
2
Register agent sessions
After login, POST the user’s fintech id and JWT to your BFF:
Route
Method
Body
Purpose
/api/agent/session
POST
{ userId, token }
Store fintech JWT for agent proxy
/api/agent/session
DELETE
{ userId }
Clear on logout
Client helpers live in src/lib/agent-session-client.ts (registerAgentSession, unregisterAgentSession). The reference app registers on login, wallet refresh, and when ChatropicDrawer mounts.
3
SaaS drawer component
ChatropicDrawer loads the embed iframe with mode=drawer, endUser, and a signed identity JWT:
See src/lib/chatropic-config.ts for URL building and src/app/api/chatropic/identity/route.ts for JWT signing.
4
Mount on dashboard layout
In your authenticated shell (app-shell.tsx), render the drawer when embed env vars are set and a session exists. Add Log out in the sidebar, it calls unregisterAgentSession, clears localStorage, and redirects to /login.
5
End-to-end check
Run fintech-api (:8083), customer-agent (:8000), playground (:3000), and chatropic-demo-web (:3001)
Log in with alex.smith@demo.com / Demo1234!
Open the right-side drawer, ask “What’s my balance?”
In the chatropic-demo-web server logs, confirm the wallet call arrives at http://localhost:3001/api/agent/wallet with X-End-User-Id set to the fintech user UUID (not the demo-... chat session id)
Reply should show USD 18 from fintech-api
Authentication & identity
The same identity pattern in the React Native SDK.
Actions & UI payloads
How structured action payloads render in chat.
Navigation routes
Deeplink to /transactions, /settings, etc. from chat cards.
Agent BFF: confirm registerAgentSession ran after login and X-End-User-Id on the action is the fintech user UUID (not the chat demo-... session id). Re-open the drawer or refresh the page to re-register. Run npm run setup:chatropic-bff if the wallet action still points at fintech-api directly.
BFF returns “No active session for this user”
User logged in client-side but POST /api/agent/session failed, check fintech-api is up and the demo app was restarted after env changes
Sign-in link does nothing
Confirm Redirect URI in your OAuth client matches the value from Manage tokens
Empty insights
Ensure period or from/to is set; failed txs are excluded from insight totals
Agent never calls actions
Improve action description (“when to call”); test phrasing in Playground
Widget shows but Navigation cards do not move the host page
Navigation listener setup is optional and manual for now; see Embed navigation if you need SPA routing
CORS errors from browser
Call APIs from Chatropic server-side actions, not from the iframe directly