GMGN Callout OpenAPI
The GMGN Callout OpenAPI lets approved partners programmatically publish and read on-chain "callouts" — a signal from a wallet that it is calling a specific token, optionally with a thesis and a linked Twitter/X identity.
Application Form: https://docs.google.com/forms/d/e/1FAIpQLScRnqI0PSQBEewJnF3JnfRSm50PylZRcIAfE7bl96Yp7RCQCg/viewform?usp=dialog
All endpoints are POST, accept and return application/json (UTF-8), and are authenticated with an AK/SK HMAC signature on every request. Rate limits are enforced per ak. Your ak / sk credentials are issued by GMGN.
Base URL
https://papi.gmgn.ai/callout/openapi/v1
Content-Type
application/json (UTF-8)
Auth
AK/SK HMAC-SHA256 signature (headers on every request)
Where to start
/global
Read-only
Every callout across all chains and wallets, newest first. The simplest way to integrate — no filters, no parameters beyond a cursor.
/token
Read-only
One token's cross-wallet feed, plus its Best Callout and paid pinned declaration.
/get_record
Read-only
One wallet's callout history, and the only endpoint that reports the true callout source.
/create
Write
Publish a callout, or a Callback onto someone else's call.
If you only want to consume the firehose — a community bot, a feed, a dashboard — you need /global and nothing else.
POST /global — Global callout stream (read-only)
The global callout stream: every callout across all chains and all wallets, in strict reverse-chronological order (newest first), with a cursor that pages toward older records. Built for read-only community, bot, and feed integrations.
POST https://papi.gmgn.ai/callout/openapi/v1/globalFour fixed constraints
These are fixed server-side and cannot be changed by any request parameter:
1
Last 7 days only
Once paging reaches the 7-day boundary, next_page_token stops being returned and pagination terminates naturally.
2
1 QPS
Per ak, counted independently from the other endpoints' shared ~10 QPS pool. See Rate limits.
3
No filtering
The server ignores any chains / only_kol / only_declaration / limit you send. It always returns the full cross-chain stream.
4
100 records per page
Fixed page size.
Request body
page_token
string
Pagination cursor (next_page_token from the previous page). Omit or leave empty for the first page.
ℹ️ Every field other than
page_tokenis ignored — the global stream accepts no filters. An empty body or a malformed body is treated as a first-page request and returns200, not400.
Success response
records[] fields
chain
string
Chain.
call_wallet
string
Wallet that made the callout.
call_token
string
Token address called.
call_price
string
Token price at callout time.
call_mc
string
Market cap at callout time.
ulid
string
Callout unique identifier.
create_time
int64
Callout time, Unix milliseconds.
token_symbol
string
Token symbol.
token_logo
string
Token logo URL.
multiplier
string
Current multiplier vs. callout price.
twitter_username
string
Caller display name.
twitter_handle
string
Caller @handle.
holding_percentage
string
Caller's holding percentage of the token.
source
string
Callout source — GMGN-native callouts report the device (web / android / ios); third-party platform callouts report that platform's identifier.
is_kol
bool
Whether the calling wallet is a GMGN-tagged KOL wallet (KOLs who linked their own Twitter/X; public data). Always returned as true or false.
is_declaration
bool
Whether this is a paid declaration callout. omitempty — present only when true; a missing field means false.
Ordering and pagination
Records are in strict descending order by
create_time(thenulid), merged across chains — paging never duplicates or skips a record.Pass
page_token= the previous response'snext_page_tokento fetch the next (older) page.An empty or absent
next_page_tokenmeans you have reached the 7-day boundary or exhausted the data — stop paging.Other
omitemptyfields (e.g.callback_*) are absent when they have no value.
ℹ️ This endpoint returns only the boolean
is_declarationflag. It does not return paid-declaration details such asamount_usdor the declaration's start time. Contact us if you need those.
Response envelope
Every endpoint returns a {code, message, data} envelope. Always unwrap data — do not read top-level fields as business data.
HTTP 200+code = 0— Request succeeded. The business payload is underdata.HTTP 4xx / 5xx—code(int) andmessage(string) describe the error. Nodatais returned.
Two layers of outcome for writes
For POST /create, a transport-level HTTP 200 does not mean the callout was accepted. There are two distinct layers:
Transport / auth / limits — HTTP status code (
400,401,429,500).Business rule — inside
data, the booleandata.success. Whenfalse, inspectdata.reject.reason.
Data types
Prices, market caps, multipliers, percentages, and paid amounts are strings (e.g.
"0.5","3.2") to preserve precision. Parse with a decimal-safe library, not native floats.Timestamps are Unix milliseconds (int64) unless a field is explicitly an ISO-8601 string (e.g.
created_aton the/tokenfeed).ulidis the unique identifier of a callout.Fields marked
omitemptyare absent from the JSON when empty — do not assume a key exists.
Authentication
Every request must be signed with your AK/SK credentials using HMAC-SHA256. Keep the sk server-side — never ship it in a client app or browser.
Required headers
X-Ak
Your issued access key.
X-Timestamp
Current time as a Unix millisecond timestamp.
X-Signature
Lowercase hex HMAC-SHA256 of the payload below.
Signature payload
Concatenate these fields in order, with no separators:
ak
Same value as X-Ak.
timestamp
Same value as X-Timestamp (millisecond string).
method
Uppercase HTTP method, e.g. POST.
path
Request path including the API prefix, excluding host and query, e.g. /callout/openapi/v1/global.
rawQuery
URL query string (empty string for these POST endpoints).
body
Raw request body — must match the bytes actually sent exactly. Empty string if there is no body.
⚠️ Timestamp window: ±30 seconds. If
X-Timestampdiffers from server time by more than 30s the request is rejected. Keep your client clock synced (NTP).ℹ️ Because the signature covers the raw body bytes, sign the exact serialized JSON string you send. Do not re-serialize, pretty-print, or reorder keys between signing and sending.
Signing examples
Authentication failures (HTTP 401)
message
Meaning
missing auth header
One of X-Ak / X-Timestamp / X-Signature is absent.
invalid timestamp
X-Timestamp is malformed or outside the ±30s window.
invalid ak
The access key is not recognized.
invalid signature
The computed signature does not match.
api not allowed
This ak is not permitted to call this endpoint.
ip not allowed
The request originated from a non-allowlisted IP.
Rate limits
Limits are enforced per ak.
Request rate (QPS)
Per your allocation (default ≈ 10 QPS)
HTTP 429 rate limit exceeded
/create, /get_record, /token
Global stream rate (QPS)
1 QPS (strict, per ak)
HTTP 429 rate limit exceeded
/global only
Callout 24h quota
Per your allocation
HTTP 429 ak daily quota exceeded
/create only
The read endpoints (
/global,/get_record,/token) do not consume the callout 24h quota./globalhas its own 1 QPS bucket, counted separately from the ~10 QPS pool shared by the other endpoints. It is also restricted to the last 7 days and supports no filtering — see the four fixed constraints.The 24h callout quota is distinct from the per-
twitter_idand per-wallet business limits, which surface as business rejects (data.success = false) rather thanHTTP 429— see reject reasons.
POST /token — Callouts by token
Return the cross-wallet callout feed for one token: all callouts on that token, the highest-multiplier callout (top_message), the paid pinned declaration (vip_message), and a pagination cursor.
Request body
chain
string
✅
Chain.
call_token
string
✅
Token address.
cursor
string
Pagination cursor. Empty for the first page.
limit
int
Page size, max 50. Values <= 0 or > 50 are capped at 50.
⚠️ Note the asymmetry with
/get_record: this endpoint caps an out-of-rangelimitat 50, whereas/get_recordfalls back to 20.
Success response
messages[] fields
id
string
Message identifier.
content
string
Callout thesis / text (source language).
display_content
string
Translated text. Always empty on this API — the OpenAPI path forces an empty app_lang, so only the source content is returned.
media_url
string / null
Attached media, if any.
username
string
Caller handle.
display_name
string
Caller display name.
profile_image_url
string / null
Caller avatar URL.
wallet_address
string
Caller wallet address.
user_twitter_url
string
Caller Twitter/X profile URL.
follower_count
int64
Caller follower count.
like_count
int64
Like count. Currently always 0 (retained for structural compatibility after the pump sunset).
reply_count
int64
Reply count. Currently always 0 (same reason).
created_at
string
ISO-8601 timestamp of the callout.
source
string / null
Always gmgn on this endpoint — see note below.
multiplier
string
Multiplier vs. callout price.
ulid
string
Callout unique identifier.
callback_count
int
How many times this post has been called back.
callback_to_ulid
string
ULID of the original post this one calls back to.
callback_to_chain
string
Chain of that original post.
callback_to_wallet
string
Wallet of that original post.
Callbacks
callback_count is present on both original posts and callback posts — it counts how many callbacks a post received. The callback_to_* trio points at the original post being called back; when all three are empty, the record is an original post, not a callback. All are omitempty.
top_message — Best Callout
The highest-multiplier callout for this token in the last 30 days (compared as decimals).
⚠️ Returned on every page, not just the first — the current implementation does not distinguish first page from subsequent pages. It is absent when there are no callouts in the 30-day window.
vip_message — paid pinned declaration
The paid pinned declaration, assembled from callout-declaration records with success recharge status. Same structure as a messages[] item, plus:
amount_usd
string
The paid tier amount. Filled only on vip_message — never on top_message.
omitempty— absent when there is nosuccessrecord.Sits alongside
top_message; both can appear at the same time.
ℹ️
vip_message.amount_usdis paid-tier information and is passed through to partners as-is by this endpoint.
declaration_level
The token's current recharge tier. This is a top-level field describing the token, not a property of any single declaration. In phase one it is the default value "199", reserved for future tier expansion and bidding floor prices.
Pagination
has_more(bool) is the authoritative signal for whether to keep paging.next_cursoris returned only whenhas_moreistrue. When there are no more pages the field is omitted entirely (not an empty string ornull).
⚠️ Page on
has_more, not on the presence ofnext_cursor.ℹ️ On
/token,sourceis alwaysgmgn— this aggregated token-page view does not pass through third-party source identifiers. To distinguish callouts by originating platform, use/get_record.
POST /get_record — Callouts by wallet
Return the callout history of a single wallet, newest first, with a cursor that pages toward older records.
Request body
chain
string
✅
Chain.
call_wallet
string
✅
Wallet address to query.
limit
int
Page size. Must be between 1 and 50.
page_token
string
Pagination cursor (next_page_token from the previous page). Empty for the first page.
⚠️
limitout of range falls back to the default 20, not to 50. Sendinglimit: 100returns 20 records, not 50. The same is true forlimit <= 0. To get 50 per page you must send exactly50. (This differs from/token, which caps at 50.)
Success response
records[] fields
chain
string
Chain.
call_wallet
string
Wallet that made the callout.
call_token
string
Token address called.
call_price
string
Token price at callout time.
call_mc
string
Market cap at callout time.
ulid
string
Callout unique identifier.
multiplier
string
Current multiplier vs. callout price.
token_symbol
string
Token symbol.
token_logo
string
Token logo URL.
twitter_username
string
Caller display name.
holding_percentage
string
Caller's holding percentage of the token.
source
string
True callout source — see below.
callback_count
int
How many times this post has been called back.
callback_to_ulid / callback_to_chain / callback_to_wallet
string
The original post this one calls back to. omitempty.
source — the only endpoint that reports the real platform
source reports the true origin of the callout: GMGN-native callouts report the device name (web / android / ios), and third-party platform callouts report that platform's identifier.
ℹ️ This endpoint resolves
sourcepercall_wallet, so you can use it to distinguish platforms./tokenalways reportsgmgnand does not pass through third-party identifiers.
Callbacks
Same semantics as /token — see Callbacks. All callback_* fields are omitempty.
Pagination
Pass page_token = the previous response's next_page_token to fetch the next (older) page. An empty next_page_token means there are no older records.
OpenAPI 3.0 specification
The complete OAS 3.0 definition below can be imported directly into Swagger UI, Redoc, or Postman.
ℹ️ The
X-Signaturevalue must be computed per request — it cannot be a static value in Swagger/Postman. Use a pre-request script to build the signature overak + timestamp + method + path + rawQuery + body.
Last updated