Tok{In} API
The Tok{In} API offers an array of features that can help determine whether a token is malicious or not. From storage checks, to simulation and static analysis features. The Tok{In} API supports all ERC20 contracts on Ethereum, Binance Smart Chain, Arbitrum, Base, Avalanche, and Robinhood Chain (New). The features cover all Uniswap V2/V3/V4 forks, Aerodrome V2/Slipstream (Base), and launchpad tokens: both bonding curves (four.meme and flap.sh on BSC, trench.today and flap on Robinhood Chain) and launchpads that seed a standard DEX pool directly (Pons, Noxa, Virtuals, Doppler, varo.rialto, bow.fun and letscash.fun on Robinhood Chain).
For AI coding agents (Claude Code, Cursor, Copilot, etc.): a migration guide written specifically for you lives at
AGENTS.mdalongside this page (canonical URL:https://docs.dedaub.com/docs/token_safety/AGENTS). Read it end-to-end before changing any code that integrates with Tok{In}: it covers the GoPlus → Tok{In} drop-in swap, field mappings, always-nullfields, and common migration pitfalls.
Usage
curl -X 'GET' \
'https://tokin-api.dedaub.com/token/{chain}/{token_address}' \
-H 'accept: application/json' \
-H 'X-API-Key: YOUR-API-KEY'
chain: The chain of the token
token_address: The address of the token
User Interface
A Swagger UI for easier interaction with the API is available at https://tokin-api.dedaub.com .
Available Chains
| Chain | Slug | Chain ID |
|---|---|---|
| Ethereum | ethereum | 1 |
| Binance Smart Chain | binance | 56 |
| Arbitrum | arbitrum | 42161 |
| Base | base | 8453 |
| Avalanche | avalanche | 43114 |
| Robinhood Chain (New) | robinhood | 4663 |
DEX coverage is most complete on Ethereum, with more pools being added to the other chains over time.
Quote tokens per chain
Pool discovery and liquidity valuation are anchored on each chain's wrapped native token plus its canonical ~$1 stablecoins. That anchor set is not the same on every chain:
| Chain | Wrapped native | Stable anchors |
|---|---|---|
| Ethereum, Arbitrum, Base | WETH | USDC, USDT |
| Binance Smart Chain | WBNB | USDC, USDT |
| Avalanche | WAVAX | USDC, USDT |
| Robinhood Chain | WETH | USDG, USDE |
Robinhood Chain has no canonical USDC or USDT: USDG and USDE are the real ~$1 tokens there, and any USDC/USDT-named deployment on 4663 is an impostor. Pools quoted in a non-anchor token can still be valued when a price is available (see Notes on liquidity).
Response Formats
The Tok{In} API supports multiple response formats via the response_format query parameter.
Available Formats
| Format | Description |
|---|---|
dedaub | Default format |
goplus | GoPlus-compatible format |
Usage
# Default (Dedaub format)
GET /token/{chain}/{token_address}
# GoPlus format
GET /token/{chain}/{token_address}?response_format=goplus
GoPlus Format Mapping
The GoPlus format transforms the default Tok{In} schema to a GoPlus-compatible one, with the following caveats.
Direct Mappings
| Dedaub Field | GoPlus Field | Notes |
|---|---|---|
is_open_source | is_open_source | Boolean → "1"/"0" string |
is_proxy | is_proxy | Boolean → "1"/"0" string |
mint_or_burn_function | is_mintable | Boolean → "1"/"0" string |
owner_address | owner_address | Direct string |
can_selfdestruct | selfdestruct | Boolean → "1"/"0" string |
external_call | external_call | Boolean → "1"/"0" string |
is_in_dex | is_in_dex | Boolean → "1"/"0" string |
receive_tax | buy_tax | Decimal as string; pool-aware, see caveat 4 |
send_tax | sell_tax | Decimal as string; pool-aware, see caveat 4 |
cannot_buy | cannot_buy | Boolean → "1"/"0" string |
tax_can_be_modified | slippage_modifiable | Boolean → "1"/"0" string |
trading_cooldown | trading_cooldown | Boolean → "1"/"0" string |
creator_address | creator_address | Direct string |
creator_percent | creator_percent | Decimal as string |
is_launchpad_token | launchpad_token | Boolean → "1"/"0" string |
Computed Mappings
| GoPlus Field | Derived From | Logic |
|---|---|---|
transfer_pausable | cannot_buy, pause_status_can_be_modified | True if either is True |
is_blacklisted | has_blacklist_or_whitelist | Same value (temporary) |
is_whitelisted | has_blacklist_or_whitelist | Same value (temporary) |
is_anti_whale | has_trading_cap, has_position_cap | True if either is True |
anti_whale_modifiable | trading_cap_can_be_modified, position_cap_can_be_modified | True if either is True |
hidden_owner | allowance_bypass, privileged_spenders | True when the bypass is address specific, so at least one address is named |
owner_change_balance | owner_can_change_balance | Same value |
Fields Without Direct Equivalent (returns null)
| GoPlus Field | Reason |
|---|---|
cannot_sell_all | Not currently tracked |
can_take_back_ownership | Not currently tracked |
gas_abuse | Not currently tracked |
personal_slippage_modifiable | Not currently tracked |
lp_total_supply | Not currently tracked |
is_airdrop_scam | Not currently tracked |
trust_list | Not currently tracked |
holder_count | Not currently tracked |
owner_balance | Not currently tracked |
owner_percent | Not currently tracked |
Caveats
-
is_blacklisted/is_whitelisted: Currently both map fromhas_blacklist_or_whitelist. We cannot distinguish between blacklist-only, whitelist-only, or both. -
Boolean Format: GoPlus uses string format (
"1"/"0") instead of booleans. All boolean fields are converted accordingly. -
Tax Terminology: Our
send_taxmaps to GoPlussell_tax, and ourreceive_taxmaps to GoPlusbuy_tax. Note the direction inverts: code computing slippage must follow the rename. -
buy_tax/sell_taxare pool-aware, and may disagree with the contract-level tax. Ingoplusmode these are taken from the first pool index[]that reports a tax, falling back to the contract-levelreceive_tax/send_taxonly when no pool reports one. The pool figure reflects what a real swap would cost and is usually the more useful number, but it meansbuy_taxin agoplusresponse can differ fromreceive_taxin the equivalentdedaubresponse for the same token. If you compare the two formats, expect this and prefer the pool figure for trade decisions. -
is_honeypotis alwaysnull. It is present in the response shape but not yet produced. Integrations that gate trades onis_honeypot === "1"will treat every token as safe after migrating. Derive an equivalent fromcannot_buy, the per-pooldex[].buy_success/sell_success(dedaubmode), and the tax fields; or block while the field is unavailable. See Readingbuy_success/sell_successfirst, because thenull/"pending"states matter for exactly this decision. -
hidden_owneris narrower than it looks: it is"1"only when the bypass is address-specific. A universal bypass (where the allowance check is skipped for everyone) setsallowance_bypassbut leavesprivileged_spendersempty, and maps to"0"because no undisclosed owner exists. It isnullwhen the check could not run, which is not the same as"0". Use the Dedaub format if you need to tell those three apart, or to read the offending addresses.
Static Analysis Features
We leverage the Gigahorse decompiler to analyze contracts whose source code is unavailable. The decompiled bytecode is checked for patterns commonly associated with undesirable behaviors in ERC20 tokens.
mint_or_burn_function:
There is a public function that changes the token's total supply.
can_selfdestruct:
The contract contains a selfdestruct call. (Note: The EVM no longer supports the SELFDESTRUCT opcode, so this is now a no-op.)
transfer_guarded_by_storage:
The transfer function's execution depends on a storage variable (e.g., a flag or mapping check). This is a signal that transfers can be conditionally blocked by the contract owner or via some internal logic.
transfer_from_guarded_by_storage:
The transferFrom function's execution depends on a storage variable. Same implications as transfer_guarded_by_storage: it indicates that delegated transfers can be conditionally blocked.
trading_cooldown:
An address must wait for a certain period after its last transfer before it can transfer tokens again.
view_function_modifies_state:
A function with the signature of one of the view functions defined by EIP-20 updates a storage variable.
has_trading_cap:
The amount of tokens transferred by a single call to transfer cannot exceed a value, either constant or held in storage.
has_trading_cap_functionality:
There is code that could enforce a trading cap. This can be true even if the cap is disabled.
trading_cap_can_be_modified:
The transfer amount cap is held in storage and there is a function that can update it.
has_position_cap:
The amount of tokens an address can hold cannot exceed a value, either constant or held in storage.
has_position_cap_functionality:
There is code that could enforce a position cap. This can be true even if the cap is disabled.
position_cap_can_be_modified:
The position cap is held in storage and there is a function that can update it.
has_owner_functionality:
There is functionality that could let one or more addresses have access to functionality of the token that the rest do not. This can be true even if the owner has been renounced.
owner_address:
The address of the owner.
has_pause_functionality:
The token has code that could pause trading. Can be true even if the current state of the contract does not allow pausing functionality to be re-enabled.
pause_status_can_be_modified:
The pause status can be changed in the future.
has_blacklist_or_whitelist:
Addresses can be restricted from trading the token.
external_call:
There is a call to another contract, whose target is not statically known and/or returns arbitrary data that are used by the token.
timebomb:
Certain functionality is only enabled after a specific timestamp.
has_tax_functionality:
This token has a tax functionality implemented. This could be true even if the current tax is 0 as the taxes could have been wiped.
tax_can_be_modified:
Tax value can be updated.
is_open_source:
This indicates whether the contract's source code is available.
has_open_source_implementation:
For proxy contracts: indicates whether the implementation contract's source code is verified. Only relevant when is_proxy is true. null for non-proxy contracts.
is_proxy:
Indicates if the contract is a proxy contract.
balance_update_function:
A list of function selectors (e.g., "0xa9059cbb") that modify the token's balance storage slot. Expected selectors are transfer and transferFrom; additional selectors may indicate hidden mint/burn or fee-skimming logic.
"balance_update_function": [
"0xa9059cbb",
"0x23b872dd"
]
allowance_update_function:
A list of function selectors that modify the token's allowance storage slot. Expected selectors include approve, transferFrom, increaseAllowance, and decreaseAllowance; unexpected selectors may indicate allowance manipulation.
"allowance_update_function": [
"0x095ea7b3",
"0x23b872dd",
"0x39509351",
"0xa457c2d7"
]
Simulation Features
transfer_success:
Whether a holder's balance can actually be moved. false means the transfer did not go through, so the token may block transfers entirely, which is a common honeypot trait. null means the check did not settle, carries no signal, and must not be read as a pass.
allowance_bypass:
true when some caller can move another holder's tokens through transferFrom without ever having been approved, the shape of a hidden drain backdoor.
The check is behavioural rather than a pattern match on the code, because a backdoor address is rarely a plain literal in a contract. Read it together with privileged_spenders, which is what separates the two positive cases:
allowance_bypass | privileged_spenders | Meaning |
|---|---|---|
true | one or more addresses | Address specific bypass. Those callers can move any holder's balance with no approval in place |
true | empty | Universal bypass. The token does not enforce allowances at all |
false | empty | Allowances are enforced |
null | empty | The check did not run. Unknown, and never safe |
⚠ Tri-state. null means the check could not run and must not be rendered as safe. Only false is an all-clear.
privileged_spenders:
The addresses that can move a holder's balance with no allowance in place. Empty when allowance_bypass is false, and also when the bypass is universal rather than address specific, so read it together with allowance_bypass, never on its own.
"allowance_bypass": true,
"privileged_spenders": [
"0x961c7a5dde069aa1a4ea73e5b506e4312105f08d"
]
transfer_tax:
send_tax(%): Calculated as the percentage loss from the sender's balance. For example, if the sender sent 100 tokens and 110 were deducted, the send tax is 10%.receive_tax(%): Calculated as the percentage the recipient received. For example, if the sender sent 100 tokens and the recipient only received 90, the receive tax is 10%.- All values are expressed as percentages (e.g., 0.0 means 0%).
dex:
An array of liquidity pools where the token is paired with one of the chain's quote tokens (the wrapped native or a canonical stablecoin), along with details on liquidity and trading behavior. Launchpad bonding curves are reported here too, as synthetic pools.
{
"pair": "0x...",
"liquidity_type": "UniV2",
"liquidity": 2455608.22,
"buy_success": true,
"buy_tax": 0.0,
"sell_success": true,
"sell_tax": 0.0,
"errorMessage": null,
"errorCode": null,
"pool_id": null,
"is_launchpad": null
}
-
pair: Address of the liquidity pair. -
liquidity_type: Type of the pool:Type Description UniV2Uniswap V2 or compatible fork UniV3Uniswap V3 or compatible fork UniV4Uniswap V4 or compatible fork SolidlyAerodrome (more Solidly forks coming!) SolidlyV3Aerodrome Slipstream four.memeFour.Meme bonding curve (BSC) flapFlap.sh bonding curve (BSC, Robinhood Chain) trench.todayTrench bonding curve (Robinhood Chain) The last three are bonding curves rather than DEX pools; they always carry
is_launchpad: true.Uniswap V4 pools are simulated like V2 and V3.
buy_success,sell_success,buy_taxandsell_taxare populated forUniV4pools, including pools quoted in the chain's native coin and pools sitting behind a custom hook. Earlier releases returned no buy/sell result for V4 and reported every V4 pool as 0% tax; a client that cached those values, or that special-cased V4 as "tax unknown, assume zero", should stop doing so. A hook that taxes a swap now shows up inbuy_tax/sell_taxlike any other tax. -
liquidity: USD value of the pool's known-token reserves:- Measured on the known token side. It is an approximation rather than an exact figure, and it is a reliable indicator of pool health and liquidity status. See Notes on
liquidityfor the per version caveats.
- Measured on the known token side. It is an approximation rather than an exact figure, and it is a reliable indicator of pool health and liquidity status. See Notes on
-
buy_success: Whether buying the token (e.g., WETH -> token) succeeded. Four-valued; see below. -
buy_tax(%): Tax incurred on a buy.nullor"pending"on the same terms asbuy_success. -
sell_success: Whether selling the token succeeded. Four-valued, same asbuy_success. -
sell_tax(%): Tax incurred on a sell. -
errorMessage/errorCode: Populated for failed queries (e.g., low liquidity, failed swaps). -
pool_id: ID of the pool in case of Uniswap V4, otherwisenull. -
is_launchpad:trueif this pool is from a launchpad bonding curve (e.g., four.meme, flap.sh, trench.today).nullotherwise.
Reading buy_success / sell_success: null is not a failure
These four fields are not booleans. Each carries one of four values, and conflating the last two with false is the most common way to misread a Tok{In} response:
| Value | Meaning | Safe reading |
|---|---|---|
true | Simulated, and the trade succeeded | Tradeable on this pool |
false | Simulated, and the trade failed | A real negative signal |
"pending" | Simulation is still running | Not yet known; poll again |
null | No simulation was attempted for this pool | Unknown, carries no signal |
null occurs where a swap simulation does not apply or was not run: bonding-curve pools are the common case, since a curve is not swapped against like a DEX pool.
⚠ Do not render null or "pending" as "cannot buy" or "cannot sell". A client that treats these as falsy will report a healthy token as unsellable. Branch on === true and === false explicitly and handle the other two as "unknown". If you need a single tradeability verdict, require sell_success === false before calling a token unsellable, not merely "not true".
Because these fields are typed as boolean-or-string, statically typed clients should model them as a union (e.g. bool | "pending" | None) rather than bool.
is_liquid:
This boolean indicates if the token is liquid, i.e. if at least one pool has more than $100 of value in it, measured on the chain's quote token side: WETH/USDC/USDT on most chains, WETH/USDG/USDE on Robinhood Chain.
Notes on liquidity
- For V2 pools, using the known token side (e.g., WETH in WETH/XYZ) is reliable since the reserves are fixed.
- For V3 pools, the figure is measured on the known token side and is an approximation. It can include uncollected fees and dust, and it does not account for the active price range. It remains a strong signal of pool activity and health, and a very low value is a reliable indicator of an illiquid or abandoned pool.
- For V4 pools, no per pool balance exists to read: every token balance is held by a single
PoolManagercontract rather than by one contract per pool. Liquidity for these pools is sourced from external market data for the pool id, as base and quote liquidity in USD. - For launchpad bonding curve pools (four.meme, flap.sh, trench.today), liquidity is derived from the on-chain reserve data of the bonding curve contract, converted to USD using the quote token price. Curves that quote in the chain's native coin rather than naming a quote token (trench.today, and flap on Robinhood Chain) are valued against the wrapped native.
- When neither side of a pool is a chain anchor, it can still be valued when an external price is available for one side. This is what makes Robinhood Chain's tokenised equities usable as quote assets: a launchpad pool quoted in
COIN,TSLA,GOOGLorSPCXcarries real, reportable liquidity. A pool with no priced side at all is dropped rather than reported at $0.
Launchpad Detection
Tok{In} detects tokens issued by launchpad platforms and reports which platform issued them, on every supported chain.
| Platform | Slug | Chains |
|---|---|---|
| Ape.store | ape.store | Ethereum, BSC, Base, Robinhood Chain |
| Arena | arena | Avalanche, Robinhood Chain |
| ArrowPad | arrowpad | Robinhood Chain |
| Bags | bags | Robinhood Chain |
| bow.fun | bow.fun | Robinhood Chain |
| Circus | circus | Robinhood Chain |
| Clanker | clanker | Ethereum, BSC, Base, Arbitrum, Robinhood Chain |
| Coinbarrel | coinbarrel | Robinhood Chain |
| Doppler (bankr, long.xyz) | doppler | Base, Robinhood Chain |
| DYOR Fun | dyor.fun | Base, Robinhood Chain |
| Flap.sh (bonding curve) | flap | BSC, Base, Robinhood Chain |
| Four.Meme (bonding curve) | four.meme | BSC, Base, Arbitrum |
| HoloLaunch (Holoworld) | hololaunch | BSC, Robinhood Chain |
| hood.fun | hood.fun | Robinhood Chain |
| hyper.meme | hyper.meme | Robinhood Chain |
| Klik | klik | Ethereum, BSC, Robinhood Chain |
| LaunchHood | launchhood | Robinhood Chain |
| LeaveHood | leavehood | Robinhood Chain |
| Lemon.fun | lemon.fun | Robinhood Chain |
| letscash.fun | letscash.fun | Robinhood Chain |
| Livo | livo | Ethereum, Robinhood Chain |
| Lunch.fun | lunch.fun | Robinhood Chain |
| Memecoin.fun | memecoin.fun | Robinhood Chain |
| MintFast | mintfast | Robinhood Chain |
| Noxa | noxa | Robinhood Chain |
| o1.exchange | o1.exchange | Robinhood Chain |
| ORO | oro | Robinhood Chain |
| Pew.fun | pew.fun | Robinhood Chain |
| Pmav.fun | pmav.fun | Robinhood Chain |
| Pons | pons | Robinhood Chain |
| Pons (unofficial fork) | pons-fork | Robinhood Chain |
| Potato.fm | potato.fm | Robinhood Chain |
| Real.fun | real.fun | Robinhood Chain |
| Robinfun | robinfun | Robinhood Chain |
| Stoxes | stoxes.fun | Robinhood Chain |
| Sushi | sushi | BSC, Robinhood Chain |
| Trench (bonding curve) | trench.today | Robinhood Chain |
| varo.rialto | varo.rialto | Robinhood Chain |
| Virtuals Protocol | virtuals | Base, Robinhood Chain |
| Unrecognised launchpad | launchpad | All chains |
Notes on reading the slugs:
- One slug per platform, not per product line. Where a platform runs several launch routes (Pons V1/V2, Stoxes and its RWA line, o1's crypto- and stock-quoted routes, DYOR Fun's versions), they all report the platform's single slug. Screeners that list those routes separately will show more entries than this table does.
pons-forkis an independent operator running the same Pons launcher template. Its tokens look like official Pons tokens, but the launcher belongs to someone else, so it is labelled separately: launchpad reputation is the point of the field, and conflating the two would defeat it.launchpadis a deliberate catch-all. A token that proves it came off a launchpad but whose platform we cannot yet name is still reported as launchpad-issued rather than dropped. Treat it as "yes, launchpad; platform unknown", not as a specific platform.- A platform on one chain is not the same product on another. Ape.store, Clanker, Arena and Virtuals are native to Base, Avalanche or Ethereum and also deployed on Robinhood Chain; the slug is the same, the deployment is not.
Detection is exact: it identifies the contract that issued the token, rather than guessing from the token's address. The one exception is documented below.
Graduated tokens (BSC). Four.Meme and Flap tokens carry a recognisable address pattern. It is used as a last resort on BSC only, for tokens that have left their bonding curve for a standard DEX such as PancakeSwap. Being a pattern match rather than an exact one, it can occasionally label a token that matches by coincidence. The exact signals are always preferred when available.
Bonding curves appear as pools. Four.Meme, Flap and Trench hold their reserves in a curve contract, so a token still on its curve appears in the dex array with liquidity_type set to the platform slug and is_launchpad: true. Every other platform in the table seeds a standard Uniswap pool at launch, so its tokens carry is_launchpad_token: true while their pools look like ordinary V2/V3/V4 pools.
How a platform is identified
The evidence is always the contract that issued the token. For a curve platform that is the curve contract itself. For everything else the pool is an ordinary Uniswap pool that pair discovery already finds, so only the label is missing, and it is resolved from the issuer behind that pool. Several signals supply it and they are tried cheapest first, so most tokens are labelled without an extra RPC call.
Four properties of the result matter when you consume the field:
| Property | What it means for your integration |
|---|---|
| The match is exact | A platform slug is set only when the issuer is identified. The BSC fallback above is the single exception |
| A new platform is not missed | An issuer that is recognisable but not yet named reports the generic launchpad slug rather than nothing |
| An ordinary DEX token is never labelled | Evidence that a liquidity pool token could also produce is excluded, so a Uniswap LP token never reports as launchpad issued |
| One platform can match several signals | Flap on Robinhood Chain is identifiable from its issuer and also runs a curve whose reserves are reported as a pool |
Related Fields
is_launchpad_token: tri-state.true: the token was issued by a launchpad platform.false: pools were resolved for this token and none of them, nor any provenance signal, indicates a launchpad.null: unknown. No pools were resolved, so no determination could be made. Do not read this as "not a launchpad".
launchpad_name: The launchpad platform slug (e.g."four.meme","pons","doppler", or the generic"launchpad").nullifis_launchpad_tokenis nottrue.is_launchpad(per pool):trueif the specific pool is a launchpad bonding curve.nullotherwise. A launchpad token that graduated, or that never ran a curve, hasis_launchpad_token: truewhile every pool indexhasis_launchpad: null; the two fields answer different questions.
Supply & Burn Features
decimals:
Number of decimal places the token uses (e.g., 18 for most ERC20 tokens). Used to convert between raw and human-readable amounts.
supply:
Total supply of the token, normalized by decimals (raw_supply / 10^decimals). This is the human-readable value (e.g., 1000000000 for a token with 1 billion supply).
burned_supply:
Total supply held by known burn addresses (0x000...0000 and 0x000...dead), normalized by decimals. The value is verified on-chain via multicall. 0 if no tokens have been sent to burn addresses.
burned_supply_pct:
Percentage of the total supply held by known burn addresses, capped to 2 decimal places (e.g., 6.13). 0 if no tokens have been burned.
circulating_supply:
Circulating supply of the token, calculated as supply - burned_supply. Represents the tokens that are still in active circulation.
burn_addresses:
An array of burn address balances. Each entry is a holder object with the burn address and its token balance. Only addresses with a balance > 0 are included.
"burn_addresses": [
{
"owner_address": "0x000000000000000000000000000000000000dead",
"token_amount": 61256610.0,
"pct_held": 6.13
}
]
normalized_supply (deprecated):
Use supply instead. Returns the same value as supply. Kept for backwards compatibility.
Other Features
name:
Name of the token.
symbol:
Symbol of the token.
creator_address:
Address of the creator (EOA) of the token.
creator_balance:
Amount of tokens held by the creator (normalized by decimals).
creator_percent:
Percentage of the total supply held by the creator of the token, capped to 2 decimal places.
top_holders:
Top 10 token holders, returned as an array of holder objects. Balances are verified on-chain via multicall.
[
{
"owner_address": "0x...",
"token_amount": 1234567.89,
"pct_held": 12.34
}
]
Each entry in top_holders has the following fields:
owner_address: Address of the token holder.token_amount: Amount of tokens held by that address (normalized by decimals).pct_held: Percentage of the total token supply held by that address.
is_in_dex:
The token is in at least one DEX.
cannot_buy:
Returns true if the token cannot be bought through any of the listed pools or if all the pools are too illiquid (less than $100).
owner_can_change_balance:
The token owner can modify any holder's balance directly. This field is part of the extended analysis set and may be absent from the response entirely: an absent field means "not assessed", which is not the same as false. Key off its presence before reading it.
is_launchpad_token:
true if the token was issued by a launchpad platform. false if pools were resolved and none indicates a launchpad. null if no pools were resolved, meaning no determination could be made; see Launchpad Detection for the full platform list.
launchpad_name:
The launchpad platform slug (e.g. "four.meme", "clanker", "doppler", "pons"). Falls back to the generic "launchpad" when the token is provably launchpad-issued but the platform is not yet named. null if is_launchpad_token is not true. The full list of slugs is in Launchpad Detection; treat it as an open set and keep a default branch, since new platforms are added over time.
last_scanned_at:
ISO 8601 UTC timestamp of when this token was last analyzed (e.g., "2025-01-15T12:30:00Z").
Token Safety Summary
The summary endpoint returns a compact, pre-processed view of a token's safety data, designed for dashboards and quick-scan UIs where you need actionable signals without parsing the full feature set.
curl -X 'GET' \
'https://tokin-api.dedaub.com/token/{chain}/{token_address}/summary' \
-H 'accept: application/json' \
-H 'X-API-Key: YOUR-API-KEY'
Response Fields
active_flag_count:
The number of risk signals currently active across the token's static analysis and simulation features. A flag is counted as active when it indicates a potential risk. For example, has_blacklist_or_whitelist: true or transfer_success: false. is_open_source: true is not counted (safe state), and neither is a flag whose value is null; an unknown is not a risk signal, so allowance_bypass: null leaves the count unchanged.
major_flags:
A curated list of three key safety signals covering the most impactful risk categories. Each flag has:
label: Human-readable name.description: What the flag means.value:trueif the condition is present,falseif not,nullif unknown.
| Label | Derived From | Active When |
|---|---|---|
Access Restrictions | has_blacklist_or_whitelist | true |
Transfer Restrictions | has_trading_cap_functionality or has_position_cap_functionality | either is true |
Has enough liquidity | is_liquid | false (lack of liquidity is the risk) |
detected_pool_count:
Total number of liquidity pools found for the token.
dominant_pool:
The pool with the highest liquidity, or null if no pools exist.
type: Pool type (e.g.UniV2,UniV3).address: Pool contract address.liquidity: Liquidity in USD.can_buy/can_sell: Whether buys/sells succeed in this pool.buy_tax/sell_tax: Tax as a percentage (e.g.1.0= 1%).nullif unavailable.
Example
curl -X 'GET' \
'https://tokin-api.dedaub.com/token/ethereum/0x2328434559f7dec44373822cf68052de0d671b7f/summary' \
-H 'accept: application/json' \
-H 'X-API-Key: YOUR-API-KEY'
Result:
{
"active_flag_count": 9,
"major_flags": [
{
"label": "Access Restrictions",
"description": "Addresses can be restricted from trading the token. This could be a blacklist, whitelist, or both.",
"value": true
},
{
"label": "Transfer Restrictions",
"description": "The contract limits how much can be traded in a single transaction or held by a single address.",
"value": true
},
{
"label": "Has enough liquidity",
"description": "The token has at least one WETH, USDC, or USDT pair with more than $100 in liquidity.",
"value": true
}
],
"detected_pool_count": 1,
"dominant_pool": {
"type": "UniV2",
"address": "0xa954213fb0F410c8f1b2fca9B65F11A63ab3fFdb",
"liquidity": 59292.71,
"can_buy": true,
"can_sell": true,
"buy_tax": 1.0,
"sell_tax": 1.0
}
}
Example
curl -X 'GET' \
'https://tokin-api.dedaub.com/token/ethereum/0x2328434559f7dec44373822cf68052de0d671b7f' \
-H 'accept: application/json' \
-H 'X-API-Key: YOUR-API-KEY'
Result:
{
"chain": "ethereum",
"contract_address": "0x2328434559f7dec44373822cf68052de0d671b7f",
"features": {
"mint_or_burn_function": true,
"can_selfdestruct": false,
"transfer_guarded_by_storage": true,
"transfer_from_guarded_by_storage": true,
"trading_cooldown": false,
"view_function_modifies_state": false,
"has_blacklist_or_whitelist": true,
"external_call": true,
"timebomb": true,
"has_pause_functionality": true,
"pause_status_can_be_modified": false,
"has_owner_functionality": true,
"has_tax_functionality": true,
"tax_can_be_modified": false,
"has_trading_cap_functionality": true,
"trading_cap_can_be_modified": false,
"has_position_cap_functionality": true,
"position_cap_can_be_modified": false,
"balance_update_function": [
"0xa9059cbb",
"0x23b872dd",
"0xcd05e4ad",
"0x3bd5d173"
],
"allowance_update_function": [
"0xa9059cbb",
"0x23b872dd",
"0x39509351",
"0xa457c2d7",
"0x95ea7b3"
],
"name": "Simon the Gator",
"symbol": "SIMON",
"decimals": 18,
"supply": 690000000.0,
"normalized_supply": 690000000.0,
"burned_supply": 0.0,
"burned_supply_pct": 0.0,
"circulating_supply": 690000000.0,
"is_open_source": true,
"has_open_source_implementation": null,
"is_liquid": true,
"is_proxy": true,
"owner_address": "0x0000000000000000000000000000000000000000",
"send_tax": 0,
"receive_tax": 1,
"transfer_success": true,
"allowance_bypass": false,
"privileged_spenders": [],
"creator_address": "0x9cb1a958ad57f59a91582b81ac88378c1c12ee58",
"creator_balance": 400000,
"creator_percent": 0.0,
"is_in_dex": true,
"cannot_buy": false,
"is_launchpad_token": false,
"launchpad_name": null,
"has_trading_cap": true,
"has_position_cap": false,
"last_scanned_at": "2025-06-15T10:22:33Z",
"dex": [
{
"errorMessage": null,
"errorCode": null,
"pair": "0xa954213fb0F410c8f1b2fca9B65F11A63ab3fFdb",
"liquidity_type": "UniV2",
"liquidity": 59292.7097022566,
"buy_success": true,
"buy_tax": 1,
"sell_success": true,
"sell_tax": 1,
"pool_id": null,
"is_launchpad": null
}
],
"top_holders": [],
"burn_addresses": []
},
"error": ""
}
API Response Reference
All endpoints use JSON unless otherwise noted. Authentication endpoints redirect via 307.
Common Response Codes
| Code | Meaning |
|---|---|
200 | Success |
307 | Redirect (OAuth flows) |
400 | Bad request (invalid input, failed precondition) |
401 | Missing or invalid API key / unauthenticated |
402 | A free trial allowance is spent. Not retryable; the allowance does not refill |
404 | Resource not found |
409 | Conflict (e.g. max API keys reached) |
422 | Validation error (invalid address format, missing params) |
429 | Rate limit or quota exceeded |
500 | Internal server error |
503 | Service not configured (billing) |
Token
GET /token/{chain}/{contract_address}
Returns token safety features.
| Code | Body / Detail |
|---|---|
200 | TokenResponse with features populated |
422 | TokenResponse with error: "Contract address needs to be EVM compatible" |
422 | TokenResponse with error: "Error validating item data: ..." |
500 | TokenResponse with error: "Unable to retrieve safety features for this token" |
500 | TokenResponse with error: "Error fetching items: ..." |
401 | {"detail": "API Key is missing"} or {"detail": "Invalid API Key"} |
429 | See Rate Limiting |
TokenResponse schema:
{
"chain": "ethereum",
"contract_address": "0x...",
"features": { ... },
"error": ""
}
Query param response_format=goplus returns GoPlus-compatible features shape.
GET /token/{chain}/{contract_address}/summary
Returns a compact safety summary. Uses the same cache as the full token endpoint.
| Code | Body / Detail |
|---|---|
200 | TokenSummaryResponse |
422 | TokenSummaryResponse with zeroes/nulls (invalid or burn address) |
500 | TokenSummaryResponse with zeroes/nulls (analysis failure) |
401 | {"detail": "API Key is missing"} or {"detail": "Invalid API Key"} |
429 | See Rate Limiting |
TokenSummaryResponse schema:
{
"active_flag_count": 9,
"major_flags": [
{
"label": "Access Restrictions",
"description": "...",
"value": true
}
],
"detected_pool_count": 1,
"dominant_pool": {
"type": "UniV2",
"address": "0x...",
"liquidity": 59292.71,
"can_buy": true,
"can_sell": true,
"buy_tax": 1.0,
"sell_tax": 1.0
}
}
Auth
POST /agent-keys
A free, capped API key for an automated caller that cannot sign in. Sign-in needs a mailbox, so software has no way through the OAuth flow; this is the way in for an agent or a script.
Requires no credential. Send a reason saying what you are building.
curl -X POST 'https://tokin-api.dedaub.com/agent-keys' \
-H 'Content-Type: application/json' \
| Field | Required | Notes |
|---|---|---|
reason | yes | Up to 500 characters. Recorded, and not verified. |
contact | no | Up to 200 characters. |
| Code | Body / Detail |
|---|---|
201 | {"api_key": "...", "plan": "agent", "api_calls_per_month": ..., "api_calls_per_day": ..., "rate_limit_per_minute": ..., "next_step": "..."} |
422 | Missing or over-long reason |
429 | Too many trial keys requested by this caller today. Reuse the key you have |
503 | Trial registration is unavailable on this deployment |
The trial allowance is small by design: enough to build and demonstrate an integration against a handful of tokens, not enough to run a product on.
Registration is idempotent. Asking again from the same network returns the
key you already have and the allowance you have already partly spent, so
requesting another key is not a way to get more calls. When the allowance is
spent the API answers 402 with error_code: free_quota_exhausted; it does not
refill, so neither retrying nor re-registering will help. Sign in and create a
full key instead.
AI coding agents: read AGENTS.md §2.2 and §7.1 before writing
any client against this.
GET /auth/login/{provider}
| Code | Detail |
|---|---|
307 | Redirect to OAuth provider (Google or GitHub) |
GET /auth/callback/{provider}
| Code | Detail |
|---|---|
307 | Redirect to {FRONTEND_URL}/auth/success?token=<jwt> on success |
400 | OAuth callback failure (provider error) |
Profile
All profile endpoints require a valid JWT (set via cookie from auth callback).
GET /profile/me
| Code | Body |
|---|---|
200 | User object |
401 | {"detail": "Not authenticated"} |
GET /profile/api-keys
| Code | Body |
|---|---|
200 | Array of APIKey objects |
401 | {"detail": "Not authenticated"} |
POST /profile/api-keys
| Code | Body / Detail |
|---|---|
200 | Created APIKey object |
401 | {"detail": "Not authenticated"} |
409 | {"detail": "Maximum of N API key(s) allowed per user"} |
500 | {"detail": "Error creating API key"} |
DELETE /profile/api-keys/{api_key_id}
| Code | Body |
|---|---|
200 | {"message": "API key deleted successfully"} |
200 | {"message": "API key not found or does not belong to the user"} (no-op) |
401 | {"detail": "Not authenticated"} |
GET /profile/logs
| Code | Body |
|---|---|
200 | Array of APILog objects |
401 | {"detail": "Not authenticated"} |
GET /profile/logs_status_codes
| Code | Body |
|---|---|
200 | Array of {"status_code": int, "count": int} |
401 | {"detail": "Not authenticated"} |
GET /profile/logs_chains
| Code | Body |
|---|---|
200 | Array of {"chain": string, "count": int} |
401 | {"detail": "Not authenticated"} |
GET /profile/logs_addresses
| Code | Body |
|---|---|
200 | Array of {"address": string, "count": int} |
401 | {"detail": "Not authenticated"} |
GET /profile/linked-accounts
| Code | Body |
|---|---|
200 | Array of {"id", "provider", "provider_id", "email", "linked_at"} |
401 | {"detail": "Not authenticated"} |
DELETE /profile/linked-accounts/{account_id}
| Code | Body / Detail |
|---|---|
200 | {"message": "Account unlinked successfully"} |
200 | {"message": "Account not found or does not belong to user"} (no-op) |
400 | {"detail": "Cannot unlink last provider account"} |
401 | {"detail": "Not authenticated"} |
Rate Limiting
429 responses are returned by the auth middleware for API-key-authenticated endpoints. Three independent checks:
| Check | Scope | Headers |
|---|---|---|
| Per-minute QPS | Per API key (Redis) | Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining: 0 |
| Daily quota | Per user (Redis) | X-Quota-Daily-Limit, X-Quota-Daily-Used, Retry-After |
| Monthly quota | Per user (PostgreSQL) | X-Quota-Monthly-Limit, X-Quota-Monthly-Used |
Admin users bypass all limits. Requests from app.dedaub.com bypass auth and rate limiting entirely.