GMGN Data API
GMGN wallets with the name GMGN shows and the X account it names for each, its labels, and the realised PnL and trade count it published: one page read newest change first, one wallet lookup, on the data key you already hold.
OpenAPI 3.1 JSON ↗ · FOMO Data API · Data key access · Auth · limits · errors
Authentication & allowance
The FOMO Data API's key, plan and allowance, unchanged: send Authorization: Bearer sk_ansem_… or the same key in X-Api-Key; a data key on plan builder or above; every served call counts once against the key's per-minute window and daily ceiling, shared with every FOMO door, and carries the same X-RateLimit headers. No call here reaches an upstream: every answer is read from our own store.
Endpoints
GET /v1/gmgn/traders — GMGN wallets, with the name and X GMGN gives them and its figures
Every GMGN wallet this store holds, newest change first: the name GMGN shows, the X account it names for the wallet, its labels, and the realised PnL and trade count GMGN published where they were read. Filter by X username.
| Query | Type · bounds | Meaning |
|---|---|---|
limit | {"type":"integer","minimum":1,"maximum":100} | Records per page, 1..100; 50 when absent. |
cursor | {"type":"string","minLength":1,"maxLength":1024} | The previous page's next_cursor, verbatim. Bound to the filters it was minted under: any other filter set is a 400 naming cursor. |
x_handle | {"type":"string","pattern":"^@?[A-Za-z0-9_]{1,15}$"} | An X username, with or without @, any case: the wallets GMGN names that account for. |
Returns the GmgnTraderPage schema below.
GET /v1/gmgn/wallet/{address} — One GMGN wallet
One wallet's record, or wallet: null when this store holds none for it (a 200, never a 404).
No query parameters: the wallet is the path's {address}.
Returns the GmgnWalletAnswer schema below.
curl -H "Authorization: Bearer $KEY" "https://api.hansem.io/v1/gmgn/traders?limit=50"
One cursor law
Pages are newest change first. While next_cursor is a string, hand it back verbatim as cursor for the next page; null is the last page. A cursor is opaque and signed, bound to the door and the filters it was minted under: any other combination is a 400 naming cursor, never silently page one.
What a record is
Every field is present on every record; a value nobody read is null, never invented. The name, the X username and the labels are GMGN's own words for the wallet: GMGN names an X account for a wallet, and that is its word, never a verification of who holds the account. The PnL and trade figures are GMGN's own as of figures_at; a wallet whose figures were never read carries null figures and a null figures_at.
Coverage — what this store holds
Every page carries coverage: how many wallets this store holds for the platform, how many of them carry an X username, and the newest change to any of them. An empty page with HTTP 200 is a real answer: read it against coverage, never as an outage. Solana wallets only.
Errors & retries
One envelope: { error: { code, message, type, request_id } }. The message names the refused parameter, never its value. A wallet this store holds nothing for is a 200 with wallet: null, never a 404.
| HTTP | Code | Meaning | Next action |
|---|---|---|---|
| 400 | invalid_request | A parameter was refused; the message names it, never its value. A cursor minted under other filters or the other order lands here. | Fix the parameter. For a cursor: send it with exactly the filters and order it was minted under, or start a new walk. |
| 401 | missing_api_key · invalid_api_key · revoked_api_key | No key, a key this system never issued, or one that was revoked. | Send Authorization: Bearer <your data key>. |
| 403 | permission_denied | The key is not a data key on plan builder or above; required_plan names the plan. | Use the data key issued for this API. |
| 404 | not_found | No route answers the path — an unknown route, never missing data: a token, author or person nobody stored answers 200. | Check the method and the path against this reference. |
| 405 | method_not_allowed | The allow header names the verb the door takes: GET on every read, POST on the resolve. | Use the verb the allow header names. |
| 429 | rate_limit_exceeded · quota_exceeded | The key's per-minute window, or its daily ceiling. Retry-After says when. | Wait Retry-After seconds. Changing doors does not reset the window — every door shares one allowance. |
| 503 | service_unavailable | The store or the usage ledger could not be read or written; nothing was served, and nothing was counted against you. | Keep your cursor and retry after Retry-After. This is never an empty page. |
Schemas
Field types, nullability and enums, as the OpenAPI document carries them. Every schema is pinned by a test to what the doors actually serve.
GmgnTrader
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"wallet": {
"type": "string",
"description": "The wallet, Solana base58 as GMGN sent it. The key of the record."
},
"chain": {
"type": "string",
"const": "solana"
},
"name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The name GMGN shows for the wallet; null when it shows none."
},
"x_handle": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The X username GMGN names for the wallet, lower-cased, without @. GMGN's word for it, never a verification of who holds the account."
},
"x_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The X display name GMGN shows beside it."
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"description": "GMGN's own labels for the wallet as last read; empty when none were read."
},
"realized_pnl_24h_usd": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"description": "The realised PnL GMGN published for the wallet over 24 hours, as of figures_at; null where it was not read."
},
"realized_pnl_7d_usd": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"description": "The same over 7 days."
},
"realized_pnl_30d_usd": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"description": "The same over 30 days."
},
"trades_7d": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
],
"description": "Buys plus sells GMGN published for the wallet over 7 days, as of figures_at."
},
"last_active_at": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
],
"description": "The wallet's last trade, as GMGN published it."
},
"figures_at": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
],
"description": "When the figures above were read from GMGN; null when no figure has been read for this wallet."
},
"seen_at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the identity words above last changed in this store."
}
},
"required": [
"wallet",
"chain",
"name",
"x_handle",
"x_name",
"tags",
"realized_pnl_24h_usd",
"realized_pnl_7d_usd",
"realized_pnl_30d_usd",
"trades_7d",
"last_active_at",
"figures_at",
"seen_at"
],
"additionalProperties": false
}GmgnTraderPage
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"records": {
"type": "array",
"items": {
"type": "object",
"properties": {
"wallet": {
"type": "string",
"description": "The wallet, Solana base58 as GMGN sent it. The key of the record."
},
"chain": {
"type": "string",
"const": "solana"
},
"name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The name GMGN shows for the wallet; null when it shows none."
},
"x_handle": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The X username GMGN names for the wallet, lower-cased, without @. GMGN's word for it, never a verification of who holds the account."
},
"x_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The X display name GMGN shows beside it."
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"description": "GMGN's own labels for the wallet as last read; empty when none were read."
},
"realized_pnl_24h_usd": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"description": "The realised PnL GMGN published for the wallet over 24 hours, as of figures_at; null where it was not read."
},
"realized_pnl_7d_usd": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"description": "The same over 7 days."
},
"realized_pnl_30d_usd": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"description": "The same over 30 days."
},
"trades_7d": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
],
"description": "Buys plus sells GMGN published for the wallet over 7 days, as of figures_at."
},
"last_active_at": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
],
"description": "The wallet's last trade, as GMGN published it."
},
"figures_at": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
],
"description": "When the figures above were read from GMGN; null when no figure has been read for this wallet."
},
"seen_at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the identity words above last changed in this store."
}
},
"required": [
"wallet",
"chain",
"name",
"x_handle",
"x_name",
"tags",
"realized_pnl_24h_usd",
"realized_pnl_7d_usd",
"realized_pnl_30d_usd",
"trades_7d",
"last_active_at",
"figures_at",
"seen_at"
],
"additionalProperties": false
}
},
"next_cursor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Hand it back as cursor for the next page; null when this page was the last."
},
"filters": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
}
},
"coverage": {
"type": "object",
"properties": {
"wallets": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "Wallets this store holds for the platform."
},
"with_x": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "Of those, the wallets carrying an X username."
},
"newest_seen_at": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
],
"description": "The newest change to any of them."
}
},
"required": [
"wallets",
"with_x",
"newest_seen_at"
],
"additionalProperties": false
},
"read_at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
}
},
"required": [
"records",
"next_cursor",
"filters",
"coverage",
"read_at"
],
"additionalProperties": false
}GmgnWalletAnswer
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"wallet": {
"anyOf": [
{
"type": "object",
"properties": {
"wallet": {
"type": "string",
"description": "The wallet, Solana base58 as GMGN sent it. The key of the record."
},
"chain": {
"type": "string",
"const": "solana"
},
"name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The name GMGN shows for the wallet; null when it shows none."
},
"x_handle": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The X username GMGN names for the wallet, lower-cased, without @. GMGN's word for it, never a verification of who holds the account."
},
"x_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The X display name GMGN shows beside it."
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"description": "GMGN's own labels for the wallet as last read; empty when none were read."
},
"realized_pnl_24h_usd": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"description": "The realised PnL GMGN published for the wallet over 24 hours, as of figures_at; null where it was not read."
},
"realized_pnl_7d_usd": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"description": "The same over 7 days."
},
"realized_pnl_30d_usd": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"description": "The same over 30 days."
},
"trades_7d": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
],
"description": "Buys plus sells GMGN published for the wallet over 7 days, as of figures_at."
},
"last_active_at": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
],
"description": "The wallet's last trade, as GMGN published it."
},
"figures_at": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
],
"description": "When the figures above were read from GMGN; null when no figure has been read for this wallet."
},
"seen_at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the identity words above last changed in this store."
}
},
"required": [
"wallet",
"chain",
"name",
"x_handle",
"x_name",
"tags",
"realized_pnl_24h_usd",
"realized_pnl_7d_usd",
"realized_pnl_30d_usd",
"trades_7d",
"last_active_at",
"figures_at",
"seen_at"
],
"additionalProperties": false
},
{
"type": "null"
}
]
},
"read_at": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
}
},
"required": [
"wallet",
"read_at"
],
"additionalProperties": false
}