pump.fun Data API
pump.fun accounts, where the wallet IS the account: the username, the X account the profile declares, and the account's calls over 30 days: one page read newest change first, filtered by wallet, username or X, 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/pump/users — pump.fun accounts: the wallet, its username and declared X, its calls
Every pump.fun account this store holds, newest change first: the wallet (on pump.fun the wallet is the account), the username, the X the profile declares, and the account's calls over 30 days where the caller ledger read them. Filter by wallet, username or 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. |
wallet | {"type":"string","pattern":"^[1-9A-HJ-NP-Za-km-z]{32,44}$"} | A wallet, Solana base58 exactly: on pump.fun the wallet is the account. |
username | {"type":"string","minLength":1,"maxLength":64} | A pump.fun username, any case. |
x_handle | {"type":"string","pattern":"^@?[A-Za-z0-9_]{1,15}$"} | An X username, with or without @, any case: the accounts whose pump.fun profile declares it. |
Returns the PumpUserPage schema below.
curl -H "Authorization: Bearer $KEY" "https://api.hansem.io/v1/pump/users?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. On pump.fun the wallet is the account. The X username is the one the account's profile declares; pump.fun does not verify it. The call figures are pump.fun's own as of figures_at; calls_complete false means the count is a floor.
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.
PumpUser
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"wallet": {
"type": "string",
"description": "The account's wallet, Solana base58: on pump.fun the wallet is the account."
},
"chain": {
"type": "string",
"const": "solana"
},
"username": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "pump.fun's username for the account; null when it published none."
},
"x_handle": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The X username the account's pump.fun profile declares, lower-cased, without @. Declared by the user; pump.fun does not verify it."
},
"profile_image": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The picture pump.fun published for the account."
},
"followers": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
],
"description": "The follower count pump.fun published beside the declared X."
},
"calls_30d": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
],
"description": "Calls the account made on pump.fun inside the 30 days before figures_at, as pump.fun lists them."
},
"ran_2x_30d": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
],
"description": "Of those, the calls whose coin reached twice its called market cap, by pump.fun's own peak figure."
},
"above_entry_30d": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
],
"description": "Of those, the calls still at or above their called market cap at figures_at."
},
"best_peak_multiple_30d": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"description": "The highest peak multiple among those calls, pump.fun's figure."
},
"calls_complete": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"description": "false when the read stopped before the window's end, so calls_30d is a floor."
},
"last_called_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 account's newest call pump.fun lists."
},
"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 call figures were read from pump.fun."
},
"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",
"username",
"x_handle",
"profile_image",
"followers",
"calls_30d",
"ran_2x_30d",
"above_entry_30d",
"best_peak_multiple_30d",
"calls_complete",
"last_called_at",
"figures_at",
"seen_at"
],
"additionalProperties": false
}PumpUserPage
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"records": {
"type": "array",
"items": {
"type": "object",
"properties": {
"wallet": {
"type": "string",
"description": "The account's wallet, Solana base58: on pump.fun the wallet is the account."
},
"chain": {
"type": "string",
"const": "solana"
},
"username": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "pump.fun's username for the account; null when it published none."
},
"x_handle": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The X username the account's pump.fun profile declares, lower-cased, without @. Declared by the user; pump.fun does not verify it."
},
"profile_image": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The picture pump.fun published for the account."
},
"followers": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
],
"description": "The follower count pump.fun published beside the declared X."
},
"calls_30d": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
],
"description": "Calls the account made on pump.fun inside the 30 days before figures_at, as pump.fun lists them."
},
"ran_2x_30d": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
],
"description": "Of those, the calls whose coin reached twice its called market cap, by pump.fun's own peak figure."
},
"above_entry_30d": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
],
"description": "Of those, the calls still at or above their called market cap at figures_at."
},
"best_peak_multiple_30d": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"description": "The highest peak multiple among those calls, pump.fun's figure."
},
"calls_complete": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"description": "false when the read stopped before the window's end, so calls_30d is a floor."
},
"last_called_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 account's newest call pump.fun lists."
},
"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 call figures were read from pump.fun."
},
"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",
"username",
"x_handle",
"profile_image",
"followers",
"calls_30d",
"ran_2x_30d",
"above_entry_30d",
"best_peak_multiple_30d",
"calls_complete",
"last_called_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
}