Start Integration with Your AI Agent
Quickly integrate Vezgo Connect by copying a ready-made prompt into your AI coding agent. Each prompt contains the full specification — your agent will scaffold the backend and frontend in one go.
Compatible with: Perplexity, Claude Code, ChatGPT, Cursor, Windsurf, GitHub Copilot, Gemini Code Assist, or any AI coding assistant.
For a complete overview of the Vezgo API, see the Introduction.
There are two ways to integrate Vezgo Connect into your application. Choose the one that fits your architecture:
- Drop-in Connect Widget Flow — Best for web apps. Opens the Vezgo Connect widget inside your page using the JS SDK. The user connects their account without leaving your app, and you receive the result via JS callbacks.
- Connect URL / Redirect Flow — Best for mobile apps, desktop apps, or when you need full control over the UX. Loads the Vezgo Connect URL (with the user token) and redirects back to your app with the result.
Quick Start: Drop-in Connect Widget Flow
Do not paste your Client Secret into the prompt. The prompts below reference it via an environment variable (VEZGO_CLIENT_SECRET). Store the secret in your .env file or secrets manager — your AI agent will read it from there when generating backend code.
Copy the prompt below, replace the [REPLACE: ...] placeholders, and paste it into your AI coding agent:
# Task
Integrate Vezgo Connect into my app using the **Drop-in Connect Widget flow** (iframe-based). Build all files needed to:
1. Authenticate with the Vezgo API from my backend
2. Open the Vezgo Connect Widget in the frontend
3. Handle the connection result and fetch account data
Read the specification below carefully before writing any code. Do not skip any step.
---
# My app context
- **Stack**: [REPLACE: e.g. "Next.js frontend + Express backend" or "React SPA + Django API"]
- **Vezgo Client ID**: [REPLACE: your Client ID]
- **Vezgo Client Secret**: stored in environment variable `VEZGO_CLIENT_SECRET` (do NOT paste the actual secret here)
- **How I identify logged-in users**: [REPLACE: e.g. "JWT with userId in payload" or "session.user.id"]
---
# Specification
## Step 1 — Backend auth endpoint
Create a `POST /vezgo/auth` endpoint on my backend server.
This endpoint is called by the Vezgo JS SDK from the browser. It must:
1. Identify the currently logged-in user (using my app's own auth — see "My app context" above).
2. Request a Vezgo user token by calling:
```
POST https://api.vezgo.com/v1/auth/token
Headers:
loginName: <my_user_identifier>
Content-Type: application/json
Body:
{ "clientId": "<CLIENT_ID>", "secret": process.env.VEZGO_CLIENT_SECRET }
```
3. Return the response as-is: `{ "token": "..." }`
**Security rule**: The Client Secret must only exist on the backend. Never send it to the browser.
**Note on `loginName`**: Use a stable, unique identifier from your system (internal user ID, UUID, etc.). Avoid PII like emails or usernames. The same `loginName` must be used across all calls for the same user — it is what links your user to their Vezgo accounts.
## Step 2 — Frontend: install SDK and open the Connect Widget
Install the SDK:
```bash
npm install vezgo-sdk-js
```
Or load via CDN:
```html
<script src="https://unpkg.com/vezgo-sdk-js/dist/vezgo.umd.js"></script>
```
Then initialize and wire up a "Connect Account" button:
```js
import Vezgo from 'vezgo-sdk-js';
// Initialize — the SDK will call /vezgo/auth automatically to get a token
const vezgo = Vezgo.init({
clientId: '<CLIENT_ID>',
authEndpoint: '/vezgo/auth',
});
const user = vezgo.login();
// Open the Connect Widget when the user clicks "Connect Account"
function openConnect() {
user.connect()
.onConnection(async (accountId) => {
// SUCCESS — the user connected an account.
// `accountId` is the Vezgo account ID. Send it to your backend and store it.
await fetch('/vezgo/accounts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ accountId }),
});
})
.onError((error) => {
// FAILURE — the user closed the widget, or there was a connection error.
// `error` has: error_type (number), message (string), account (string|undefined)
})
.onEvent((name, data) => {
// OPTIONAL — lifecycle events during the process:
// APP_LOADED, SCREEN_LOADED, PROVIDER_SELECTED, SUBMIT_CREDENTIALS,
// SUBMIT_ANSWER, ERROR, CLOSE, FORCE_CLOSE, etc.
});
}
```
## Step 3 — Backend: fetch account data
After the frontend sends the `accountId` to the backend, fetch the full account object:
```
GET https://api.vezgo.com/v1/accounts/<accountId>
Headers:
Authorization: Bearer <user_token>
```
Store the `accountId` in your database. Vezgo automatically syncs account data daily — you can retrieve updated data at any time with the same GET request, or trigger a manual sync with `POST /accounts/<accountId>/sync`.
## Step 4 — Reconnect (implement later, but wire the handler now)
When an account's credentials expire or are revoked, the account moves to a `disconnected`/`error` state and stops syncing. To let the user reconnect it without creating a new account:
```js
user.reconnect(accountId)
.onConnection((accountId) => { /* updated existing account */ })
.onError((error) => { /* handle */ });
```
## Step 5 — Map the data into your app
After accounts connect, fetch each account and map its data into your app's domain model — providers, accounts, transactions, positions/holdings, and securities/assets. Follow the step-by-step Data mapping guide, which lists the exact Vezgo fields and recommended target columns for each area:
https://vezgo.com/docs/start-integration#data-mapping
For the exact fields, transaction types and quirks of a provider you integrate, also fetch its per-connector reference (available for the major chains and exchanges): `https://vezgo.com/status/<provider>-api/` (replace `<provider>` with `account.provider.name`, e.g. `ethereum`, `coinbase`, `binance`).
---
# Constraints
- Token lifetime: 10 minutes by default — always request a fresh token right before opening the widget.
- For testing, use the **Vezgo Demo** provider: username `vezgo`, password `vezgo` for a successful connection. See the [Vezgo Demo institution](/connecting-a-user#the-vezgo-demo-institution) docs for other test scenarios (2FA, errors, MFA).
- Vezgo also supports `multi_wallet` mode (connect multiple wallets/networks in one flow) and `sync_nfts` — see "Connect URL parameters" in the Connecting a User docs.
# References (fetch these docs for the latest API details)
- JS SDK source & examples: https://github.com/wealthica/vezgo-sdk-js
- Connect a user (full reference): https://vezgo.com/docs/connecting-a-user
- Authentication: https://vezgo.com/docs/authentication
- API reference: https://vezgo.com/docs/api
Quick Start: Connect URL / Redirect Flow
Copy the prompt below, replace the [REPLACE: ...] placeholders, and paste it into your AI coding agent:
# Task
Integrate Vezgo Connect into my app using the **Connect URL / Redirect flow**. Build all files needed to:
1. Generate a Vezgo user token on the backend
2. Send the user to the Vezgo Connect URL
3. Handle the redirect callback with the connection result
Read the specification below carefully before writing any code. Do not skip any step.
---
# My app context
- **Stack**: [REPLACE: e.g. "Express.js backend serving a React SPA" or "Rails API + React Native mobile"]
- **Vezgo Client ID**: [REPLACE: your Client ID]
- **Vezgo Client Secret**: stored in environment variable `VEZGO_CLIENT_SECRET` (do NOT paste the actual secret here)
- **Redirect URI**: [REPLACE: e.g. "https://myapp.com/vezgo/callback" — must be registered with Vezgo]
- **How I identify logged-in users**: [REPLACE: e.g. "JWT with userId in payload" or "session.user.id"]
- **Platform**: [REPLACE: "web", "iOS", "Android", or "desktop"]
---
# Specification
## Step 1 — Backend: generate a Vezgo user token
Create a backend function that generates a Vezgo user token for a given user:
```
POST https://api.vezgo.com/v1/auth/token
Headers:
loginName: <my_user_identifier>
Content-Type: application/json
Body:
{ "clientId": "<CLIENT_ID>", "secret": process.env.VEZGO_CLIENT_SECRET }
Response:
{ "token": "eyJ..." }
```
**Security rule**: The Client Secret must only exist on the backend. Never send it to the browser or mobile app.
## Step 2 — Send the user to Vezgo Connect
The Connect URL must be loaded as a **POST request** with the token in form data. The simplest approach is to render a server-side page with an auto-submitting HTML form:
```html
<form method="POST" action="https://connect.vezgo.com/connect?client_id=<CLIENT_ID>&redirect_uri=<REDIRECT_URI>&state=<STATE>">
<input type="hidden" name="token" value="<USER_TOKEN>" />
<noscript><button type="submit">Continue to Vezgo</button></noscript>
</form>
<script>document.forms[0].submit();</script>
```
Create a backend endpoint (e.g. `GET /vezgo/connect`) that:
1. Gets a fresh Vezgo user token (Step 1)
2. Encodes any app state into the `state` parameter (base64) so you can restore context after redirect
3. Renders the auto-submitting form above
### Connect URL parameters
| Parameter | Required | Description |
|-----------|----------|-------------|
| `client_id` | Yes | Your Vezgo Client ID |
| `redirect_uri` | Recommended | Where Vezgo redirects after completion. Must be pre-registered. |
| `state` | Recommended | Opaque string (e.g. base64) to restore your app state after redirect |
| `lang` | No | UI language: `en`, `es`, `fr`, `it` |
| `provider_categories` | No | Limit to categories: `exchanges`, `blockchains`, `wallets` |
| `providers` | No | Comma-separated allow-list of providers, e.g. `binance,coinbase,ethereum` |
| `theme` | No | `light` (default) or `dark` |
| `providers_per_line` | No | Providers per line on the select screen: `1` or `2` (default `2`) |
| `sync_nfts` | No | Show "Sync NFTs" checkbox (boolean, default `false`) |
| `multi_wallet` | No | Allow connecting multiple wallets/networks in one flow (boolean, default `false`) |
| `hide_wallet_connect_wallets` | No | Hide WalletConnect wallets from the list (boolean, default `false`) |
### URL variants for other flows
New connection (skip provider selection by appending the provider name):
`https://connect.vezgo.com/connect/<PROVIDER_NAME>?client_id=...&redirect_uri=...`
Reconnect (update credentials for an existing account):
`https://connect.vezgo.com/reconnect/<ACCOUNT_ID>?client_id=...&redirect_uri=...`
## Step 3 — Handle the redirect callback
Create a route at your redirect URI (e.g. `GET /vezgo/callback`). Vezgo redirects the user back with query parameters:
**On success:**
```
<REDIRECT_URI>?account=<ACCOUNT_ID>&code=<ACCOUNT_ID>&state=<STATE>
```
**On failure:**
```
<REDIRECT_URI>?error_type=<CODE>&message=<MSG>&state=<STATE>&force=<true|undefined>&account=<ID>
```
Your callback handler must:
1. Check if `error_type` is present — if so, show an error to the user using `message`. If `force=true`, the user explicitly closed the widget.
2. If `account` is present, store the account ID in your database linked to the user.
3. Decode and restore app state from the `state` parameter.
4. Fetch the full account data from the Vezgo API:
```
GET https://api.vezgo.com/v1/accounts/<accountId>
Headers:
Authorization: Bearer <user_token>
```
### Callback query parameters reference
| Parameter | Present on | Description |
|-----------|-----------|-------------|
| `account` | Both (on failure: only if created before the error) | The Vezgo account ID |
| `code` | Success | Same as `account` (for OAuth compliance). In `multi_wallet` mode, an object with connection details. |
| `error_type` | Failure | Numeric error code |
| `message` | Failure | Human-readable error message |
| `force` | Failure | `true` if the user explicitly closed the widget |
| `state` | Both | Your app state passed in Step 2 |
## Step 4 — Map the data into your app
After accounts connect, fetch each account and map its data into your app's domain model — providers, accounts, transactions, positions/holdings, and securities/assets. Follow the step-by-step Data mapping guide, which lists the exact Vezgo fields and recommended target columns for each area:
https://vezgo.com/docs/start-integration#data-mapping
For the exact fields, transaction types and quirks of a provider you integrate, also fetch its per-connector reference (available for the major chains and exchanges): `https://vezgo.com/status/<provider>-api/` (replace `<provider>` with `account.provider.name`, e.g. `ethereum`, `coinbase`, `binance`).
---
# Constraints
- Token lifetime: 10 minutes by default — always generate a fresh token right before redirecting.
- The redirect URI **must be pre-registered** with Vezgo. Contact Vezgo to register URIs for dev, staging, and production, or manage them in the Vezgo Portal.
- Vezgo syncs account data daily automatically. You can also trigger a manual sync via `POST /accounts/:id/sync`.
- For testing, use the **Vezgo Demo** provider: username `vezgo`, password `vezgo` for a successful connection. See the [Vezgo Demo institution](/connecting-a-user#the-vezgo-demo-institution) docs for other test scenarios.
- For mobile apps, register a custom scheme redirect URI (e.g. `com.myapp://vezgo/callback`) and handle it in your deep link handler. See [Mobile support](/mobile-support).
# References (fetch these docs for the latest API details)
- Connect a user (full reference): https://vezgo.com/docs/connecting-a-user
- URLs: https://vezgo.com/docs/urls
- API reference: https://vezgo.com/docs/api
- Mobile support: https://vezgo.com/docs/mobile-support
Data mapping
The prompts above generate the connection flow. Once an account is connected, you still need to map the Vezgo data into your app's domain model — accounts, wallets, transactions, positions/holdings, and securities/assets. This is the step-by-step guide both prompts link to; it applies equally to the Drop-in Widget and Connect URL / Redirect flows.
This guide is the cross-connector model — the fields and rules that apply to every provider. For the exact fields, transaction types, asset_type values and provider-specific quirks of a given connector, read its per-connector data-mapping reference on the provider's status page.
URL pattern: https://vezgo.com/status/<provider>-api/ — where <provider> is account.provider.name (e.g. ethereum → vezgo.com/status/ethereum-api). Detailed per-connector references are available for:
- EVM chains — Ethereum, Arbitrum, Avalanche, Base, BSC, Cronos, Fantom, Optimism, Polygon
- Bitcoin-family (UTXO) — Bitcoin, Bitcoin Cash, Dash, Dogecoin, Litecoin
- Other chains — Solana, XRP, Hedera
- Exchanges — Coinbase, Kraken, Uphold, Binance, Binance US, Gemini, Bybit, OKX, Crypto.com
Integrating a provider that isn't listed above? Browse all supported integrations at vezgo.com/status — every provider has a status page (/status/<provider>-api/), and detailed per-connector data-mapping references are added there over time.
Global rules (apply to every area below):
- Every
amountandfiat_valueis a string — parse with a decimal/bignumber type, never a float. - Every timestamp (
created_at,updated_at,initiated_at,confirmed_at, …) is milliseconds since epoch. - Account-level
fiat_tickeris alwaysUSD(per-balancefiat_tickermay differ — store it per balance). - Confirm exact field names against the object reference before writing your schema.
1. Providers
The provider is the institution holding an account. Read the catalog from GET /providers (no user token needed); read the per-account provider from account.provider.
- Capture provider identity:
account.provider.name(stable id, e.g.bitcoin,ethereum,coinbase,binance) andaccount.provider.display_name(for UI). - Classify it:
provider.is_blockchain === true→ blockchain / self-custody wallet; otherwise → exchange. (The widget also groups providers via theprovider_categoriesoption:blockchains,wallets,exchanges.) - Read
provider.auth_type(wallet= address/WalletConnect,oauth= e.g. Coinbase,token= API key + secret,password= username + password) — this determines how reconnection works.
Blockchains (e.g. Ethereum, Bitcoin, Solana)
- Each connection exposes one or more
account.wallets[]. Persistwallet.id(stable, e.g.bitcoin:cash:usd) andwallet.address(on-chain address or xpub) as the account identity. - For EVM / multi-chain providers, read the chain id from
provider.misc.chain_id(chainlist.org id) and the list inprovider.supported_networks. Store chain id next to the address so the same address on different chains stays distinct. - Key wallets on
wallet.id, not onwallet.addressalone — withmulti_walletenabled, one connection can hold the same address across multiple networks.
Suggested host fields: provider_name ← provider.name, is_blockchain ← provider.is_blockchain, chain_id ← provider.misc.chain_id, address ← wallet.address.
Exchanges (e.g. Coinbase, Binance)
- Provider identity is the same
provider.name/display_name. - Exchange sub-accounts (spot / margin / futures) surface as separate
account.wallets[]entries. Persist eachwallet.idandwallet.name;wallet.addressis usuallynullfor exchanges — key onwallet.id. - Exchange wallets have no on-chain address — do not require an
addressfor them.
Reconnection without duplicates (both types)
A reconnect (user.reconnect(accountId) or connect.vezgo.com/reconnect/<ACCOUNT_ID>) refreshes credentials on the same account.id. Match on account.id and update in place — never insert a new row on reconnect.
2. Accounts
- Read from
GET /accounts(list) orGET /accounts/:id(one). SDK:user.accounts.getList()/user.accounts.getOne(id). - Persist at minimum:
id(Vezgo account id — your stable key),provider.name,provider.is_blockchain,fiat_value(string, USD),fiat_ticker,status,created_at,updated_at. - Deduplicate on
account.idonly — never on the user-visible name (names are not unique and can change). Put a unique constraint on the stored Vezgoaccount.id. - Relate each account to its owner via the stable
loginNameyou used to create the Vezgo user: storeyour_user_id↔account.id. The sameloginNamealways returns the same set of accounts. - Track
status(ok/error/syncing/retry). Onerror, readaccount.error.name(e.g.LoginFailedError,SecurityQuestionError) and surface a "Reconnect" action.
3. Transactions
- Endpoint:
GET /accounts/:id/transactions. SDK:user.transactions.getList({ accountId, from, last, limit }). - Sync strategy — paginate with
lastfor incremental sync:- First import: pass an old
from(e.g.2009-01-01) and page withlimit(10–1000) +last(the previous page's lastid) until a page comes back empty. Keep the samefromacross all pages. - Incremental sync: store the newest imported
transaction.id; next run, pass it as?last=to fetch only newer transactions.
- First import: pass an old
- Persist per transaction:
id,account,wallet,transaction_type,transaction_subtype,transaction_hash,initiated_at,confirmed_at,fiat_calculated_at,misc.origin_id. Each transaction has 1+parts[]and 0+fees[]. (statusis currently alwaysnull— do not rely on it.) - Store each
partin a child table keyed by transactionid:direction(sent/received),ticker,ticker_address,amount(string),fiat_value(string),fiat_ticker,from_address,to_address. Storefees[]:ticker,amount,fiat_value. - Type mapping — translate Vezgo
transaction_typeinto your taxonomy:
Vezgo transaction_type | Direction(s) | Suggested host type |
|---|---|---|
deposit | received | deposit / transfer-in |
withdrawal | sent | withdrawal / transfer-out |
trade | sent + received | trade (buy/sell — see transaction_subtype) |
staking | sent + received | stake |
unstaking | sent + received | unstake |
reward | received | reward / income |
bonus | received | bonus / airdrop |
other | varies | other (inspect transaction_subtype) |
For finer detail (buy vs sell, fiat vs crypto, interest, airdrop…) read transaction_subtype (e.g. buy, sell, staking_reward, distribution). Full list: Connecting a user.
- Internal transfers (avoid double-counting): a
withdrawalfrom one tracked account and adepositinto another tracked account are the same movement. Detect by matchingtransaction_hash(ormisc.origin_id) plus thefrom_address/to_addresspair across your accounts, and collapse them into one internal-transfer record. On EVM,misc.internal === true/misc.category === 'internal'also flag internal movements. - Idempotency / natural key: use Vezgo
transaction.idas the primary key (stable across re-imports);misc.origin_id(provider's original id or blockchain hash) is the secondary cross-reference. Note: Vezgo reconciles a buy + sell (+ fee) into a singletradetransaction, so do not assume a 1:1 mapping to raw exchange rows.
4. Positions / Holdings
- Positions are not a separate endpoint — they are the
account.balances[]array on the account object (GET /accounts/:id). Refresh by re-reading the account after a sync (POST /accounts/:id/sync, or the daily auto-sync). - Persist per balance:
account,wallet,ticker,ticker_address,amount(string quantity),decimals,fiat_value(string),fiat_ticker, andupdated_at(use as youras_of). - Snapshot, not computed: balances are the provider's authoritative current holdings — replace the position set for each
(account, wallet)on every sync. Use transactions (area 3) only for movement/cost-basis, not to recompute current quantity. - Cost basis: Vezgo does not return a cost-basis field. If you need it, compute it from the transaction
parts[].fiat_valueatinitiated_at. - NFTs vs fungible tokens: with
sync_nftsenabled, NFTs appear as balances withasset_type === 'nft'andmisc.metadata(contract_address,token_id,contract_type,media_url). Fungible tokens haveasset_typeofnull/staked/cash. Route NFTs to a separate table keyed bycontract_address+token_id.
5. Securities / Assets
- There is no securities endpoint — Vezgo identifies each asset inline on balances and transaction parts. Build your instrument table from the assets you encounter.
- Identifiers Vezgo provides:
ticker— normalized symbol (e.g.BTC,ETH).provider_ticker— the provider's own symbol (may differ;.stakedsuffix for staked assets).ticker_address— token contract address (ERC-20 / SPL / …);nullfor native coins.- chain context — from the account's
provider.misc.chain_id/provider.supported_networks. decimals,name, andlogo(https://data.wealthica.com/api/securities/CRYPTO:<TICKER>/logo— theCRYPTO:<TICKER>string is Vezgo's security key).- NFTs:
misc.metadata.contract_address+token_id+contract_type. - Note: Vezgo does not return a CoinGecko/CMC id. If your instrument table keys on one, resolve it yourself from
ticker+ticker_address+ chain.
- Dedupe key:
- Native coins → key on
ticker. - Tokens → key on
ticker_address+ chain id (nottickeralone — the same ticker exists on multiple chains, e.g. USDC on Ethereum vs Polygon). - NFTs → key on
contract_address+token_id.
- Native coins → key on
- Collisions: when two assets share a
tickerbut differ inticker_address/chain, store them as distinct instruments (use the address + chain key). - Unknown / unsupported assets (fall-through): if an asset is not in your instrument table, auto-create a minimal record from (
ticker,ticker_address, chain,decimals,name) instead of dropping the balance/transaction; flag it for later enrichment. - Price & currency: each balance/part already carries
fiat_value+fiat_ticker(account-level fiat isUSD). Use these directly; for another display currency, convert from USD with your own FX source.