For the complete documentation index, see llms.txt. This page is also available as Markdown.

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.

Use it to:

  • Create callouts β€” a wallet calls a token, attributed to a verified Twitter/X account.

  • Read a wallet's history β€” paginate the callouts made by a single wallet.

  • Read a token's callouts β€” the cross-wallet callout feed for one token, including the highest-multiplier callout.

All endpoints are POST, accept and return application/json (UTF-8), and are authenticated with an AK/SK HMAC signature on every request. 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)


Response envelope

Every response is wrapped in a {code, message, data} envelope. Business data always lives under data β€” unwrap data; never read top-level fields directly.

{ "code": 0, "message": "", "data": { } }
Situation
Shape

HTTP 200 + code = 0

Success. Business payload is in data. For write endpoints, whether the operation was accepted is data.success.

HTTP 4xx / 5xx

code (int) + message (string) describe the error. No data.

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:

  1. Transport / auth / limits β€” HTTP status code (400, 401, 429, 500).

  2. Business rule β€” inside data, the boolean data.success. When false, inspect data.reject.reason.

Data types

  • Prices, market caps, multipliers, percentages, and token amounts are strings (e.g. "0.5", "2.3") 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_at on the /token feed).

  • ulid is the unique identifier of a callout.


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

Header
Description

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:

Field
Description

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/create.

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-Timestamp differs 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

Go
Python
Node.js

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.

Limit
Quota
Over-limit response
Applies to

Request rate (QPS)

Per your allocation (default β‰ˆ 10 QPS)

HTTP 429 rate limit exceeded

All endpoints

Callout 24h quota

Per your allocation

HTTP 429 ak daily quota exceeded

/create only

  • Read endpoints (/get_record, /token) do not consume the callout 24h quota. They are still subject to the QPS limit.

  • The 24h callout quota is distinct from the per-twitter_id and per-wallet business limits, which surface as business rejects (data.success = false) rather than HTTP 429 β€” see reject reasons.


Endpoints

POST /create β€” Create a callout

Publish a callout: one on-chain wallet calling one token. The source platform is derived automatically from your ak β€” you do not pass it.

Request body

Field
Type
Required
Description

chain

string

βœ…

Chain, e.g. sol / eth / bsc.

call_wallet

string

βœ…

On-chain wallet address making the callout.

call_token

string

βœ…

Token address being called.

twitter_id

string

βœ…

Caller's Twitter/X rest_id. Numeric-only string (^[0-9]+$).

twitter_handle

string

@handle, used as a display fallback.

twitter_username

string

Display name, used as a display fallback.

call_thesis

string

Callout rationale text. Subject to content moderation.

callback_to_chain

string

Follow-callout: chain of the original post being followed.

callback_to_wallet

string

Follow-callout: wallet of the original post being followed.

callback_to_ulid

string

Follow-callout: ULID of the original post being followed.

ℹ️ The three callback_to_* fields describe a follow-callout (calling in response to another callout). Supply all three together, or none.

Success response (HTTP 200, data.success = true)

ulid is the unique identifier of the callout.

Business reject (HTTP 200, data.success = false)

The request was well-formed and authenticated, but a business rule blocked it:

⚠️ Branch on reason (stable semantic string), never on code (troubleshooting aid only).

Reject reasons

reason

code

Meaning

twitter_not_bound

40002401

The calling wallet has no bound Twitter/X account.

twitter_not_verified

40002406

The bound Twitter/X account has not passed verification.

content_violation

40002407

call_thesis hit the content-moderation filter.

content_audit_unavailable

40002408

Moderation service unavailable β€” fail-closed reject. Retry later.

holding_too_low

40002403

The wallet's holding of this token is below the threshold.

cooldown

40002404

Same wallet + same token is in a cooldown window. next_available_at (ms) and interval_minutes describe it.

twitter_daily_limit

40002409

This twitter_id exceeded its 24h callout count. next_available_at is the window reset time.

daily_limit

40002405

24h callout count exceeded. next_available_at is the window reset time.

reject fields

Field
Type
Description

reason

string

Semantic reject reason (use this).

code

int

Numeric business code (troubleshooting only).

next_available_at

int64

For time-based rejects (cooldown, daily_limit, twitter_daily_limit): next allowed time, Unix ms.

interval_minutes

int64

For cooldown: length of the cooldown window in minutes.

ℹ️ Token safety checks (honeypot, etc.) are currently disabled. They were previously a hard block, but new pools lacking safety data caused false rejections, so the hard block was removed in favor of a disclaimer approach. No safety-related reason is returned today β€” you do not need a handler branch for it. This may be reinstated later with separate notice.

Invalid parameters (HTTP 400)

Missing or non-numeric twitter_id returns the above; other missing required fields return a corresponding 400.


POST /get_record β€” Callouts by wallet

Return the callout history of a single wallet, newest first, with a cursor that pages toward older records. Read endpoint β€” does not consume the 24h quota.

Request body

Field
Type
Required
Description

chain

string

βœ…

Chain.

call_wallet

string

βœ…

Wallet address to query.

limit

int

Page size. Max 50.

page_token

string

Pagination cursor (next_page_token from the previous page). Empty for the first page.

Success response

records[] fields

Field
Type
Description

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 (e.g. "2.3").

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.

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.

ℹ️ Unlike /token, /get_record reflects the real callout source per call_wallet. If you need to distinguish which platform a callout came from, use this endpoint.


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), and a pagination cursor. Read endpoint β€” does not consume the 24h quota.

Request body

Field
Type
Required
Description

chain

string

βœ…

Chain.

call_token

string

βœ…

Token address.

cursor

string

Pagination cursor (base64). Empty for the first page.

limit

int

Page size.

Success response

messages[] fields

Field
Type
Description

id

string

Message identifier.

content

string

Callout thesis / text.

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.

created_at

string

ISO-8601 timestamp of the callout.

source

string / null

Callout source β€” see note below.

multiplier

string

Multiplier vs. callout price.

ulid

string

Callout unique identifier.

top_message β€” the highest-multiplier callout for this token in the last 30 days. Returned only on the first page (empty cursor). If there is none, the field is omitted.

Pagination

  • has_more (bool) is the authoritative signal for whether to keep paging.

  • next_cursor is returned only when has_more is true. When there are no more pages the field is omitted entirely (not an empty string or null).

⚠️ Page on has_more, not on the presence of next_cursor.

ℹ️ On /token, source is always gmgn β€” this aggregated token-page view does not pass through third-party source identifiers. To distinguish callouts by originating platform, use /get_record, which reflects the real source per call_wallet.


HTTP status codes

Status
Meaning

200

Request handled. For writes, inspect data.success.

400

Invalid parameters (missing/malformed required field).

401

Signature authentication failed. See Authentication failures.

429

Rate limit or 24h quota exceeded. See Rate limits.

500

Internal error. Safe to retry with backoff.


OpenAPI 3.0 specification

The complete OAS 3.0 definition below can be imported directly into Swagger UI, Redoc, or Postman.

ℹ️ The X-Signature value must be computed per request β€” it cannot be a static value in Swagger/Postman. Use a pre-request script to build the signature over ak + timestamp + method + path + rawQuery + body.

Last updated