Skip to main content

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

caution

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. ethereumvezgo.com/status/ethereum-api). Detailed per-connector references are available for:

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 amount and fiat_value is 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_ticker is always USD (per-balance fiat_ticker may 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.

  1. Capture provider identity: account.provider.name (stable id, e.g. bitcoin, ethereum, coinbase, binance) and account.provider.display_name (for UI).
  2. Classify it: provider.is_blockchain === true → blockchain / self-custody wallet; otherwise → exchange. (The widget also groups providers via the provider_categories option: blockchains, wallets, exchanges.)
  3. 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)

  1. Each connection exposes one or more account.wallets[]. Persist wallet.id (stable, e.g. bitcoin:cash:usd) and wallet.address (on-chain address or xpub) as the account identity.
  2. For EVM / multi-chain providers, read the chain id from provider.misc.chain_id (chainlist.org id) and the list in provider.supported_networks. Store chain id next to the address so the same address on different chains stays distinct.
  3. Key wallets on wallet.id, not on wallet.address alone — with multi_wallet enabled, one connection can hold the same address across multiple networks.

Suggested host fields: provider_nameprovider.name, is_blockchainprovider.is_blockchain, chain_idprovider.misc.chain_id, addresswallet.address.

Exchanges (e.g. Coinbase, Binance)

  1. Provider identity is the same provider.name / display_name.
  2. Exchange sub-accounts (spot / margin / futures) surface as separate account.wallets[] entries. Persist each wallet.id and wallet.name; wallet.address is usually null for exchanges — key on wallet.id.
  3. Exchange wallets have no on-chain address — do not require an address for 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

  1. Read from GET /accounts (list) or GET /accounts/:id (one). SDK: user.accounts.getList() / user.accounts.getOne(id).
  2. 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.
  3. Deduplicate on account.id only — never on the user-visible name (names are not unique and can change). Put a unique constraint on the stored Vezgo account.id.
  4. Relate each account to its owner via the stable loginName you used to create the Vezgo user: store your_user_idaccount.id. The same loginName always returns the same set of accounts.
  5. Track status (ok / error / syncing / retry). On error, read account.error.name (e.g. LoginFailedError, SecurityQuestionError) and surface a "Reconnect" action.

3. Transactions

  1. Endpoint: GET /accounts/:id/transactions. SDK: user.transactions.getList({ accountId, from, last, limit }).
  2. Sync strategy — paginate with last for incremental sync:
    • First import: pass an old from (e.g. 2009-01-01) and page with limit (10–1000) + last (the previous page's last id) until a page comes back empty. Keep the same from across all pages.
    • Incremental sync: store the newest imported transaction.id; next run, pass it as ?last= to fetch only newer transactions.
  3. 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[]. (status is currently always null — do not rely on it.)
  4. Store each part in a child table keyed by transaction id: direction (sent/received), ticker, ticker_address, amount (string), fiat_value (string), fiat_ticker, from_address, to_address. Store fees[]: ticker, amount, fiat_value.
  5. Type mapping — translate Vezgo transaction_type into your taxonomy:
Vezgo transaction_typeDirection(s)Suggested host type
depositreceiveddeposit / transfer-in
withdrawalsentwithdrawal / transfer-out
tradesent + receivedtrade (buy/sell — see transaction_subtype)
stakingsent + receivedstake
unstakingsent + receivedunstake
rewardreceivedreward / income
bonusreceivedbonus / airdrop
othervariesother (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.

  1. Internal transfers (avoid double-counting): a withdrawal from one tracked account and a deposit into another tracked account are the same movement. Detect by matching transaction_hash (or misc.origin_id) plus the from_address/to_address pair across your accounts, and collapse them into one internal-transfer record. On EVM, misc.internal === true / misc.category === 'internal' also flag internal movements.
  2. Idempotency / natural key: use Vezgo transaction.id as 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 single trade transaction, so do not assume a 1:1 mapping to raw exchange rows.

4. Positions / Holdings

  1. 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).
  2. Persist per balance: account, wallet, ticker, ticker_address, amount (string quantity), decimals, fiat_value (string), fiat_ticker, and updated_at (use as your as_of).
  3. 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.
  4. Cost basis: Vezgo does not return a cost-basis field. If you need it, compute it from the transaction parts[].fiat_value at initiated_at.
  5. NFTs vs fungible tokens: with sync_nfts enabled, NFTs appear as balances with asset_type === 'nft' and misc.metadata (contract_address, token_id, contract_type, media_url). Fungible tokens have asset_type of null / staked / cash. Route NFTs to a separate table keyed by contract_address + token_id.

5. Securities / Assets

  1. There is no securities endpoint — Vezgo identifies each asset inline on balances and transaction parts. Build your instrument table from the assets you encounter.
  2. Identifiers Vezgo provides:
    • ticker — normalized symbol (e.g. BTC, ETH).
    • provider_ticker — the provider's own symbol (may differ; .staked suffix for staked assets).
    • ticker_address — token contract address (ERC-20 / SPL / …); null for native coins.
    • chain context — from the account's provider.misc.chain_id / provider.supported_networks.
    • decimals, name, and logo (https://data.wealthica.com/api/securities/CRYPTO:<TICKER>/logo — the CRYPTO:<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.
  3. Dedupe key:
    • Native coins → key on ticker.
    • Tokens → key on ticker_address + chain id (not ticker alone — the same ticker exists on multiple chains, e.g. USDC on Ethereum vs Polygon).
    • NFTs → key on contract_address + token_id.
  4. Collisions: when two assets share a ticker but differ in ticker_address/chain, store them as distinct instruments (use the address + chain key).
  5. 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.
  6. Price & currency: each balance/part already carries fiat_value + fiat_ticker (account-level fiat is USD). Use these directly; for another display currency, convert from USD with your own FX source.