Transactions API
What does this transaction payload call?
Decodes raw EVM transaction data into candidate function signatures and arguments. Four bytes do not identify a function: treat names as a best match, never as grounds to sign. Many are unknown.
/api/external/transaction-analysis/decode-calldataWhat it returns
Decodes EVM transaction input data into the function it calls and the arguments it passes. POST, with the payload in the body, because calldata routinely runs to kilobytes. READ THIS BEFORE RELYING ON THE ANSWER: the first four bytes of transaction data do NOT uniquely identify a function. Different functions share the same four bytes, and selectors that collide with familiar token calls are deliberately crafted — approve(address,uint256) and sign_szabo_bytecode(bytes16,uint128) are the same four bytes, and both take exactly the same number of argument bytes, so nothing about the payload separates them. This resource therefore answers with a LIST of candidate signatures and an unambiguous flag that can say "known to be ambiguous" or "no collision known", and NEVER "unique". Treat a returned name as a BEST MATCH, not an identification, and never approve or sign a transaction on the strength of it alone — confirm against the contract's own published source. Coverage is partial: many functions are not recognised at all (50% of distinct selectors in a 19-blob live sample), and an unrecognised one returns an empty candidate list rather than a guess. The answer does not vary by chain — the same calldata decodes identically on every chain measured — so this resource takes no chain, and for that reason it is not listed under any chain by the chain-coverage endpoint.
Chains
This endpoint is not tied to a chain: it takes no chain in its request.
Request
Send your key in the x-dex-data-key header. Replace each <placeholder> with a real value.
curl -X POST -H "x-dex-data-key: $DEXDATA_API_KEY" \
-H "content-type: application/json" \
-d '{"calldata":"<calldata>"}' \
"https://api.dexdata.io/api/external/transaction-analysis/decode-calldata"| Parameter | Description |
|---|---|
calldatabody · string · required | The transaction input data, 0x-prefixed hex, at least the four selector bytes. A bare four-byte selector is accepted and answers with the function name and an empty argument list — there are no argument bytes to decode. Anything that is not 0x-prefixed hex of whole bytes is rejected with a 400 before any lookup is made. |
Response fields
A JSON response. Every field is always present; null means the value could not be established, never zero.
| Field | Type | Description |
|---|---|---|
selector | string | The four-byte selector of the calldata you sent, 0x-prefixed and lowercased. Computed locally from your own input, so it is always present and is the one field here that no lookup can be wrong about. |
outcome | string | What the lookup did, and it maps one-to-one onto candidates. decoded: at least one signature was found (candidates is non-empty). unrecognised: the lookup ran and this selector is not known (candidates is []) — the COMMON case, not an edge one. lookup-failed: the lookup could not be made at all (candidates is null) — retry. The three are kept apart because "there is no such function", "this is not calldata" (a 400) and "we could not ask" are three different answers. |
candidates | object[] | null | Every signature this selector may belong to — ALWAYS a list, never one answer. The first entry, when present, is the one the lookup decoded, with your argument values attached; any entries after it are further signatures known to share the same four bytes, listed without argument values. When the payload cannot be decoded but the function can still be named, the first entry carries that name with signature and params both null: named, not decoded. [] means the lookup found nothing; null means the lookup could not be made. A single entry is NOT a promise of uniqueness — read unambiguous. |
candidates[].name | string | The function name, e.g. transfer. Always present on a listed candidate. |
candidates[].signature | string | null | The canonical signature, e.g. transfer(address,uint256). null when the argument list contains a structured type, which this resource does not flatten into a canonical form — a rendered mint(struct) would look like a signature you could hash, and it is not one. Also null on a candidate that could only be named, not decoded (see candidates). |
candidates[].params | any[] | null | The arguments decoded from YOUR calldata against THIS candidate. [] is a real answer: the calldata carried no argument bytes (a bare four-byte selector), or the function takes none. null means nothing was decoded against this candidate at all — always the case for an alternative signature listed because the selector is known to match more than one function: it is named as a possibility, never decoded against. |
unambiguous | boolean | null | Never `true`. false means this selector is KNOWN to match more than one function — treat the decode as a guess between the listed candidates. null means no collision is known for it, which is NOT a guarantee that none exists: a four-byte selector has no unique preimage, and no source reports one. The known-collision list behind a false is a floor, not a survey. The enum above is declarative, not a wire-level guarantee by itself — it does not validate the outgoing value (fast-json-stringify does not check a response against enum, only against type/enum to decide how to serialise a value already assumed to match). The actual guarantee is application-code discipline plus a runtime backstop in the capability (withUnambiguousBackstop in src/capabilities/decode-calldata.ts), which degrades any runtime true to null and reports it as an anomaly before it ever reaches this schema. |
Start building with DexData today
Sign in, create a key and make your first call in a minute. Free credits every month, and you only pay for calls that succeed.
Get a free API key