API reference
Start scans and read results as JSON. There's also an OpenAPI spec.
Authentication
Create a key on your account page and send it as a bearer token. Keys are shown once, so store yours somewhere safe. Revoking one takes effect immediately.
Authorization: Bearer gp_...The base URL is https://ghostprint.tools/api/v1.
Quick start
export GHOSTPRINT_KEY="gp_..."
export BASE="https://ghostprint.tools/api/v1"
export MINT="AcfayFzfssZuuedUcoRP2NT8tJa98WKojPdjtjFKpump"
# Start a scan
curl -X POST "$BASE/scans" \
-H "Authorization: Bearer $GHOSTPRINT_KEY" \
-H "Content-Type: application/json" \
-d "{\"mint\":\"$MINT\"}"
# Poll until status is "done"
curl "$BASE/scans/$MINT" -H "Authorization: Bearer $GHOSTPRINT_KEY"POST /scans
Starts a scan, or joins one already running. A token that already has a result returns straight away and uses none of your limit.
{ "mint": "AcfayFzfssZuuedUcoRP2NT8tJa98WKojPdjtjFKpump" }| Status | Meaning |
|---|---|
| 200 | A result exists. status is done |
| 202 | Queued or running. Poll GET /scans/{mint} |
| 400 | invalid_mint |
| 429 | scan_limit_reached or too_many_requests. See Retry-After |
| 503 | queue_full or free_capacity_reached. See Retry-After |
{
"mint": "AcfayFzfssZuuedUcoRP2NT8tJa98WKojPdjtjFKpump",
"status": "queued",
"used_scan_credit": false,
"scans_remaining_this_hour": 9
}GET /scans/{mint}
Returns progress, then the full report. Polling every few seconds is plenty.
{
"mint": "AcfayFzfssZuuedUcoRP2NT8tJa98WKojPdjtjFKpump",
"status": "running",
"progress": { "step": "Scoring links", "done": 0, "total": 0 }
}When status is done, the response has a report. If it's failed, it has an error message, and any credit used has been returned. A 404 with not_scanned means no scan exists yet.
| Report field | Contents |
|---|---|
token | Name, symbol, image, decimals and supply |
buyers | The first wallets, in order, with their buy transaction and supply share |
links | Each finding, with its type, wallets, confidence, reasons and transactions |
flags | Wallets funded within 5 minutes of each other |
clusters | Groups joined by medium or high confidence links |
funders | Senders that paid two or more early wallets |
excludedFunders | Program-owned senders left out of links |
coverage | What the scan read, and where it stopped |
summary | Plain-English headline and points, each citing its links |
GET /me
Your tier, how much of your hourly limit is used, and your credit balance.
{
"wallet": "...",
"tier": "account",
"scans_per_hour": 10,
"scans_used_this_hour": 2,
"scan_credits": 0
}Errors and limits
Errors share one shape. code is stable, so branch on that and not on the message.
{ "error": { "code": "scan_limit_reached", "message": "..." } }Each key can make 120 requests a minute. Every response carries X-RateLimit-Limit and X-RateLimit-Remaining. See Limits and credits for scan limits.