Skip to main content
GET
/
v0
/
profiles
curl --request GET \
  --url https://api.formo.so/v0/profiles \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "conditions": [
    {
      "field": "users.net_worth_usd",
      "op": "gt",
      "value": 10000
    }
  ],
  "logic": "and"
}
'
{
  "data": [
    {
      "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
      "net_worth_usd": 12345.67
    }
  ],
  "page": 1,
  "size": 100,
  "total": 1,
  "has_more": false
}

Documentation Index

Fetch the complete documentation index at: https://docs.formo.so/llms.txt

Use this file to discover all available pages before exploring further.

Search and filter wallet profiles across your project with advanced filtering capabilities. You can look up an exact wallet address, run a free-text search across addresses and social fields, and combine that with structured filters in the request body.

Authentication

This endpoint requires authentication using a Workspace API Key with profiles:read permission. Include the API key in your request headers:
Authorization: Bearer <your_workspace_api_key>
The API key needs to have the read permission for profiles in the API settings. You can configure this in your workspace API key settings.

Query Parameters

address

Filter by a specific wallet address (exact match).
curl -sS -X GET \
  -H "Authorization: Bearer <your_workspace_api_key>" \
  "https://api.formo.so/v0/profiles?address=0x1234..."
Case-insensitive free-text search across wallet addresses and all supported social fields. This includes values from both global wallet profiles and project-scoped identify overrides.
curl -sS -X GET \
  -H "Authorization: Bearer <your_workspace_api_key>" \
  "https://api.formo.so/v0/profiles?search=bob_override"

expand

Comma-separated list of optional sections to include in each profile response. Supported values:
  • apps - DeFi app interactions and balances
  • chains - Per-chain activity metrics
  • tokens - Token holdings
  • labels - Wallet labels
curl -sS -X GET \
  -H "Authorization: Bearer <your_workspace_api_key>" \
  "https://api.formo.so/v0/profiles?expand=apps,chains,labels"
Expanding fields like chains, tokens, or apps increases response size and latency. The collections are capped at 50 items each.

order_by

Field to sort results by. Supported values:
  • last_onchain (default) - Last on-chain activity timestamp
  • first_onchain - First on-chain activity timestamp
  • net_worth_usd - Total net worth
  • updated_at - Last profile update timestamp
  • tx_count - Total transaction count
  • first_seen - First seen timestamp in your app
  • last_seen - Last seen timestamp in your app
  • num_sessions - Number of sessions
  • revenue - Total revenue
  • volume - Total volume
  • points - Total points

order_dir

Sort direction:
  • desc (default) - Descending order
  • asc - Ascending order

page

1-indexed page number to return.
  • Default: 1

size

Page size - number of profiles per page.
  • Default: 100
  • Maximum: 1000

Request Body (Filters)

The search endpoint supports rich filtering capabilities through a JSON request body. The body contains a filter object with conditions and logic.

Filter Schema

{
  "conditions": [
    {
      "field": "users.net_worth_usd",
      "op": "gt",
      "value": 1000
    }
  ],
  "logic": "and"
}
FieldTypeDescription
conditionsarrayArray of filter conditions
logicstringHow to combine conditions: and (all must match) or or (any must match). Default: and

Filter Condition

Each condition in the conditions array has:
FieldTypeDescription
fieldstringThe field path to filter on (see Field Reference below)
opstringThe comparison operator
valuestring | number | boolean | arrayThe value to compare against
scopestring(Optional) Only for token filters: any (wallet + protocols) or protocol (specific protocol only)
appIdstring(Optional) Only for token filters with scope: "protocol". The DeFi protocol ID (e.g., aave-v3, compound-v3)

Operators

OperatorDescriptionExample
eqEquals{"field": "users.device", "op": "eq", "value": "Desktop"}
neqNot equals{"field": "users.os", "op": "neq", "value": "Windows"}
gtGreater than{"field": "users.net_worth_usd", "op": "gt", "value": 1000}
gteGreater than or equal{"field": "users.volume", "op": "gte", "value": 100}
ltLess than{"field": "users.net_worth_usd", "op": "lt", "value": 50000}
lteLess than or equal{"field": "chains.1.balance", "op": "lte", "value": 10000}
inIn array{"field": "users.lifecycle", "op": "in", "value": ["New", "Power user"]}
ninNot in array{"field": "users.location", "op": "nin", "value": ["US", "UK"]}
containsCase-insensitive substring match for social fields only{"field": "users.twitter", "op": "contains", "value": "vitalik"}

Field Reference

User Fields (users.*)

Filter by user engagement and profile data. Use the format users.{attribute}.

Profile Fields

FieldTypeDescription
users.net_worth_usdnumberTotal net worth in USD
users.volumenumberTotal trading volume
users.revenuenumberTotal revenue
users.pointsnumberTotal points
Example - Find users with net worth > $10,000:
{
  "conditions": [
    { "field": "users.net_worth_usd", "op": "gt", "value": 10000 }
  ],
  "logic": "and"
}
Example - Find high-volume users:
{
  "conditions": [
    { "field": "users.volume", "op": "gt", "value": 5000 }
  ],
  "logic": "and"
}

Engagement Fields

FieldTypeDescription
users.devicestringDevice type (e.g., Desktop, Mobile)
users.browserstringBrowser name (e.g., Chrome, Safari)
users.osstringOperating system (e.g., macOS, Windows)
users.locationstringCountry code (e.g., US, NG)
Example - Find mobile users from the US:
{
  "conditions": [
    { "field": "users.device", "op": "eq", "value": "Mobile" },
    { "field": "users.location", "op": "eq", "value": "US" }
  ],
  "logic": "and"
}

UTM & Referral Fields

FieldTypeDescription
users.first_utm_sourcestringFirst UTM source
users.last_utm_sourcestringLast UTM source
users.first_utm_mediumstringFirst UTM medium
users.last_utm_mediumstringLast UTM medium
users.first_utm_campaignstringFirst UTM campaign
users.last_utm_campaignstringLast UTM campaign
users.first_utm_contentstringFirst UTM content
users.last_utm_contentstringLast UTM content
users.first_utm_termstringFirst UTM term
users.last_utm_termstringLast UTM term
users.first_referrerstringFirst referrer domain
users.last_referrerstringLast referrer domain
users.first_referrer_urlstringFirst referrer full URL
users.last_referrer_urlstringLast referrer full URL
users.first_refstringFirst referral code
users.last_refstringLast referral code
Example - Find users from Google Ads campaign:
{
  "conditions": [
    { "field": "users.first_utm_source", "op": "eq", "value": "google" },
    { "field": "users.first_utm_medium", "op": "eq", "value": "cpc" }
  ],
  "logic": "and"
}

Lifecycle Filter

Filter by user lifecycle stage. Valid values: Churned, New, Power user, Resurrected, Returning.
FieldTypeDescription
users.lifecyclestringUser lifecycle stage
Example - Find new and power users:
{
  "conditions": [
    { "field": "users.lifecycle", "op": "in", "value": ["New", "Power user"] }
  ],
  "logic": "and"
}

Social Fields

Social fields support two modes:
  • Presence checks: use an empty string value to match profiles where the field is present.
  • Value matching: use eq, neq, or contains with a non-empty string to match the actual social value.
FieldDescription
users.ensENS name
users.farcasterFarcaster username
users.lensLens handle
users.basenamesBase names
users.lineaLinea identifier
users.discordDiscord username
users.telegramTelegram username
users.websiteWebsite URL
users.twitterTwitter/X handle
users.githubGitHub username
users.linkedinLinkedIn profile
users.emailEmail address
users.instagramInstagram handle
users.facebookFacebook profile
users.tiktokTikTok handle
users.youtubeYouTube channel or handle
users.redditReddit username
Example - Find users with any email present:
{
  "conditions": [
    { "field": "users.email", "op": "eq", "value": "" }
  ],
  "logic": "and"
}
Example - Find users with both ENS and Farcaster present:
{
  "conditions": [
    { "field": "users.ens", "op": "eq", "value": "" },
    { "field": "users.farcaster", "op": "eq", "value": "" }
  ],
  "logic": "and"
}
Example - Find users whose Twitter contains bob:
{
  "conditions": [
    { "field": "users.twitter", "op": "contains", "value": "bob" }
  ],
  "logic": "and"
}
Example - Find an exact email match:
{
  "conditions": [
    { "field": "users.email", "op": "eq", "value": "alice@formo.so" }
  ],
  "logic": "and"
}

Chain Filters (chains.*)

Filter by per-chain net worth. Supports filtering across all chains or specific chains.

All Chains

Use chains.balance to filter across all chains (returns profiles where any chain matches). Example - Find users with >$1,000 on any chain:
{
  "conditions": [
    { "field": "chains.balance", "op": "gt", "value": 1000 }
  ],
  "logic": "and"
}

Specific Chain

Use chains.{chain_id}.balance to filter on a specific chain. Common chain IDs:
  • 1 - Ethereum Mainnet
  • 137 - Polygon
  • 42161 - Arbitrum One
  • 10 - Optimism
  • 8453 - Base
  • 56 - BNB Chain
  • 43114 - Avalanche
Example - Find users with >$5,000 on Ethereum:
{
  "conditions": [
    { "field": "chains.1.balance", "op": "gt", "value": 5000 }
  ],
  "logic": "and"
}
Example - Find users with >$1,000 on both Ethereum and Polygon:
{
  "conditions": [
    { "field": "chains.1.balance", "op": "gt", "value": 1000 },
    { "field": "chains.137.balance", "op": "gt", "value": 1000 }
  ],
  "logic": "and"
}

App Filters (apps.*)

Filter by DeFi app interactions and balances.

All Chains

Use apps.{app_id}.balance to filter by app balance across all chains. Example - Find users with >$1,000 in Uniswap:
{
  "conditions": [
    { "field": "apps.uniswap.balance", "op": "gt", "value": 1000 }
  ],
  "logic": "and"
}

Specific Chain

Use apps.{chain_id}.{app_id}.balance to filter by app balance on a specific chain. Example - Find users with >$500 in Aave on Ethereum:
{
  "conditions": [
    { "field": "apps.1.aave.balance", "op": "gt", "value": 500 }
  ],
  "logic": "and"
}

Token Filters (tokens.*)

Filter by token holdings. Supports optional scope and appId parameters.

Token Filter Parameters

ParameterTypeDescription
scopestringany (default) = wallet + all protocols, protocol = specific protocol only
appIdstringOnly for scope: "protocol". Specifies the DeFi protocol ID (e.g., aave-v3, compound-v3, uniswap-v3)

All Chains

Use tokens.{token_address}.balance to filter by token balance across all chains. Example - Find users holding >1000 USDC (any chain):
{
  "conditions": [
    {
      "field": "tokens.0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48.balance",
      "op": "gt",
      "value": 1000
    }
  ],
  "logic": "and"
}

Specific Chain

Use tokens.{chain_id}.{token_address}.balance to filter by token balance on a specific chain. Example - Find users with >500 USDC on Ethereum:
{
  "conditions": [
    {
      "field": "tokens.1.0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48.balance",
      "op": "gt",
      "value": 500
    }
  ],
  "logic": "and"
}

Protocol-Specific Token Filters

Use scope: "protocol" with appId to filter for tokens deposited in a specific DeFi protocol. Example - Find users with USDC deposited in any protocol:
{
  "conditions": [
    {
      "field": "tokens.0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48.balance",
      "op": "gt",
      "value": 0,
      "scope": "protocol"
    }
  ],
  "logic": "and"
}
Example - Find users with USDC deposited in Aave V3:
{
  "conditions": [
    {
      "field": "tokens.0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48.balance",
      "op": "gt",
      "value": 1000,
      "scope": "protocol",
      "appId": "aave-v3"
    }
  ],
  "logic": "and"
}
Example - Find users with ETH staked in Lido:
{
  "conditions": [
    {
      "field": "tokens.0x0000000000000000000000000000000000000000.balance",
      "op": "gt",
      "value": 1,
      "scope": "protocol",
      "appId": "lido"
    }
  ],
  "logic": "and"
}

Label Filters (labels.*)

Filter by wallet labels. Use the format labels.{tag_id}. Common label IDs:
  • coinbase.verified_account - Coinbase verified account (boolean)
  • coinbase.verified_country - Coinbase verified country code
  • coinbase.verified_coinbase_one - Coinbase One membership (boolean)
  • sanctions.designated - Sanctioned address (boolean)
  • passport.models_aggregate_score - Passport aggregate score (0-100)
  • passport.unique_humanity_score - Passport uniqueness score
Example - Find Coinbase verified users:
{
  "conditions": [
    { "field": "labels.coinbase.verified_account", "op": "eq", "value": "true" }
  ],
  "logic": "and"
}
Example - Find US-verified Coinbase users:
{
  "conditions": [
    { "field": "labels.coinbase.verified_country", "op": "eq", "value": "US" }
  ],
  "logic": "and"
}
Example - Find users with high Passport score:
{
  "conditions": [
    { "field": "labels.passport.models_aggregate_score", "op": "gte", "value": "50" }
  ],
  "logic": "and"
}

Combined Filter Examples

High-Value Web3 Users

Find users with >$10,000 net worth, ENS name, and activity on Ethereum:
curl -sS -X GET \
  -H "Authorization: Bearer <your_workspace_api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "conditions": [
      { "field": "users.net_worth_usd", "op": "gt", "value": 10000 },
      { "field": "users.ens", "op": "eq", "value": true },
      { "field": "chains.1.balance", "op": "gt", "value": 0 }
    ],
    "logic": "and"
  }' \
  "https://api.formo.so/v0/profiles?expand=chains,labels"

Active DeFi Users

Find users with activity in Uniswap or Aave:
curl -sS -X GET \
  -H "Authorization: Bearer <your_workspace_api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "conditions": [
      { "field": "apps.uniswap.balance", "op": "gt", "value": 0 },
      { "field": "apps.aave.balance", "op": "gt", "value": 0 }
    ],
    "logic": "or"
  }' \
  "https://api.formo.so/v0/profiles?expand=apps"

Verified Power Users

Find Coinbase-verified power users from specific countries:
curl -sS -X GET \
  -H "Authorization: Bearer <your_workspace_api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "conditions": [
      { "field": "labels.coinbase.verified_account", "op": "eq", "value": "true" },
      { "field": "labels.coinbase.verified_country", "op": "in", "value": ["US", "UK", "DE"] },
      { "field": "users.lifecycle", "op": "eq", "value": "Power user" }
    ],
    "logic": "and"
  }' \
  "https://api.formo.so/v0/profiles"

Multi-Chain Whales

Find users with significant holdings across multiple chains:
curl -sS -X GET \
  -H "Authorization: Bearer <your_workspace_api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "conditions": [
      { "field": "chains.1.balance", "op": "gt", "value": 10000 },
      { "field": "chains.137.balance", "op": "gt", "value": 5000 },
      { "field": "chains.42161.balance", "op": "gt", "value": 5000 }
    ],
    "logic": "and"
  }' \
  "https://api.formo.so/v0/profiles?expand=chains&order_by=net_worth_usd&order_dir=desc"

Response

The response is a paginated envelope of wallet profiles.
{
  "data": [
    {
      "address": "0x9CC3cB28cd94eB4423B15cdA73346e204f59a407",
      "net_worth_usd": 125000.5,
      "ens": "example.eth",
      "tx_count": 1234,
      "first_onchain": "2024-01-15T10:30:00Z",
      "last_onchain": "2025-01-20T14:22:00Z",
      "lifecycle": "Returning"
    }
  ],
  "total": 150,
  "page": 1,
  "size": 100,
  "has_more": true
}

Response Fields

FieldTypeDescription
dataarrayArray of wallet profiles matching the search criteria
totalintegerTotal number of profiles matching the criteria across all pages
pageinteger1-indexed page number echoed from the request
sizeintegerPage size echoed from the request
has_morebooleantrue if there are pages after the current one

Profile Fields

Each profile in the data array includes:
FieldTypeDescription
addressstringWallet address
net_worth_usdnumberTotal net worth in USD
tx_countintegerTotal transaction count
first_onchainstringFirst on-chain activity timestamp (ISO 8601)
last_onchainstringLast on-chain activity timestamp (ISO 8601)
lifecyclestringUser lifecycle stage: Churned, New, Power user, Resurrected, Returning
ensstring | nullENS name
farcasterstring | nullFarcaster username
twitterstring | nullTwitter/X handle
discordstring | nullDiscord username
telegramstring | nullTelegram username
emailstring | nullEmail address
first_seenstring | nullFirst seen timestamp in your app
last_seenstring | nullLast seen timestamp in your app
num_sessionsinteger | nullTotal number of sessions
revenuenumber | nullTotal revenue
volumenumber | nullTotal volume
pointsnumber | nullTotal points
chainsarray | nullPer-chain data (when expanded)
appsarray | nullDeFi app data (when expanded)
tokensarray | nullToken holdings (when expanded)
labelsarray | nullWallet labels (when expanded)

Error Responses

StatusCodeDescription
400BAD_REQUESTInvalid query parameters or malformed JSON in request body
401UNAUTHORIZEDMissing or invalid API key
403FORBIDDENAPI key does not have profiles:read permission
500INTERNAL_SERVER_ERRORFailed to fetch wallet profile data

Authorizations

Authorization
string
header
required

Workspace API key (e.g. formo_xxx). Create one in the Formo dashboard under Team Settings > API Keys.

Query Parameters

address
string

Filter by wallet address

expand
string

Comma-separated: apps, chains, tokens, labels

order_by
enum<string>

Sort field

Available options:
net_worth_usd,
tx_count,
first_onchain,
last_onchain,
updated_at,
first_seen,
last_seen,
num_sessions,
revenue,
volume,
points
order_dir
enum<string>

Sort direction

Available options:
asc,
desc
page
integer
default:1

1-indexed page number (default 1).

Required range: x >= 1
size
integer
default:100

Page size (default 100, max 1000).

Required range: 1 <= x <= 1000

Body

application/json

Optional filter conditions

Filter conditions for profile search

conditions
object[]
logic
enum<string>
default:and
Available options:
and,
or

Response

Paginated wallet profile search results.

Pagination cursor returned alongside data on every paginated list endpoint. Use these to walk pages: has_more is true while page * size < total. Combine with the matching Page and Size query parameters to request the next page.

page
integer
required

1-indexed page number echoed from the request.

size
integer
required

Page size echoed from the request.

total
integer
required

Total row count across all pages.

has_more
boolean
required

True when more pages remain (page * size < total).

data
object[]
required