Typed all the way down.
Every method, argument and return type is derived from the same contract the API itself is built from. There is no codegen step to run and nothing to regenerate — a wrong chain slug is a compile error, not a 400 you discover in production.
Install
npm i foxd-sdkimport { FoxD } from "foxd-sdk";
const foxd = new FoxD({ apiKey: process.env.FOXD_API_KEY });
const { tokens } = await foxd.market.trending({ chain: "base", limit: 10 });What 'typed' actually buys you
The chain parameter is a union, not a string. Autocomplete lists the six real chains, and anything else fails to compile:
foxd.market.trending({ chain: "base" }); // fine
foxd.market.trending({ chain: "dogecoin" }); // Type '"dogecoin"' is not assignable
foxd.market.trending({ nonsense: 1 }); // Object literal may only specify known properties
foxd.market.doesNotExist({}); // Property 'doesNotExist' does not existResponses are shaped too — tokens[0].priceUsd is number | null, so the nullability that actually exists in market data is visible at the call site rather than discovered by a crash.
Two behaviours worth knowing
Mutating calls are never retried
Read calls retry transient failures with exponential backoff and jitter. Anything that moves money does not — a timeout does not mean the write failed, and replaying a trade to be helpful would be far worse than surfacing the ambiguity.
Errors are structured
import { FoxD, FoxDError } from "foxd-sdk";
try {
await foxd.trade.execute({ /* … */ });
} catch (e) {
if (e instanceof FoxDError) {
e.code; // "spend_cap_exceeded" — stable, matchable
e.status; // 403
e.retryable; // false
}
}A real safety check
const { tokens } = await foxd.market.trending({ chain: "base", limit: 5 });
const t = tokens[0];
const [provider, sim] = await Promise.all([
foxd.analytics.security({ chain: "base", address: t.address }),
foxd.analytics.simulateHoneypot({ chain: "base", address: t.address }),
]);
// simulated:false is NOT a pass — it means no conclusion was reached.
const sellable = sim.simulated && sim.canSell === true;
if (provider.isHoneypot || !sellable) throw new Error("not sellable");
const quote = await foxd.trade.quote({
chain: "base",
tokenIn: "0x0000000000000000000000000000000000000000",
tokenOut: t.address,
amountIn: "10000000000000000", // base units, as a string
side: "buy",
});
console.log(quote.venue, quote.estimatedUsd, quote.priceImpactBps);Amounts are base-unit strings — wei on EVM, lamports on Solana. An 18-decimal amount does not survive a float, so the SDK will not accept one.
The calls you will actually write
Each of these is the typed method plus, on the other tabs, exactly what it puts on the wire — useful when you are debugging a response or porting a flow to another language.
Discovery
curl 'https://foxd.xyz/api/v1/tokens/trending?chain=base&limit=10' \
-H "Authorization: Bearer $FOXD_API_KEY"Safety, before anything else
curl 'https://foxd.xyz/api/v1/tokens/bsc/0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c/security' \
-H "Authorization: Bearer $FOXD_API_KEY"curl 'https://foxd.xyz/api/v1/tokens/bsc/0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c/simulate' \
-H "Authorization: Bearer $FOXD_API_KEY"Quote and trade
curl -X POST 'https://foxd.xyz/api/v1/trade/quote' \
-H "Authorization: Bearer $FOXD_API_KEY" \
-H 'content-type: application/json' \
-d '{"chain":"base","tokenIn":"0x0000000000000000000000000000000000000000","tokenOut":"0x532f27101965dd16442e59d40670faf5ebb142e4","amountIn":"10000000000000000","side":"buy"}'curl -X POST 'https://foxd.xyz/api/v1/trade/execute' \
-H "Authorization: Bearer $FOXD_API_KEY" \
-H 'content-type: application/json' \
-d '{"chain":"base","tokenIn":"0x0000000000000000000000000000000000000000","tokenOut":"0x532f27101965dd16442e59d40670faf5ebb142e4","amountIn":"10000000000000000","side":"buy","slippageBps":100}'Set the exit at the same time
curl -X POST 'https://foxd.xyz/api/v1/orders/take-profit' \
-H "Authorization: Bearer $FOXD_API_KEY" \
-H 'content-type: application/json' \
-d '{"chain":"base","tokenAddress":"0x532f27101965dd16442e59d40670faf5ebb142e4","amount":"1000000000000000000","targetPriceUsd":0.01}'The full cookbook — signing up headlessly, copy trading, webhooks, launching — is in the documentation.
Get an API key
Public market data needs no key. Everything account-, wallet- or trade-related does. Keys are free, scoped, and revocable in one click.