About Swap API
The Definitive Swap API provides a simple interface to swap tokens. This guide demonstrates how to set up and execute a token swap using the API.
Swap Tokens in Five Steps
- Get an API Key
- Prepare the Pre Hash
- Sign the Request
- Generate A Quote
- Submit Request
Step 1: Get an API Key
Before you begin, obtain your API credentials from Definitive. Follow these steps:
- Visit the Getting Started page for instructions.
- Generate your API key and secret.
- Store them securely, for example, in a
.env
file:
API_KEY=your_api_key_here
API_SECRET=your_api_secret_here
Additionally, you could use AuthHelpers to streamline this process.
Step 2: Prepare the Pre Hash
To secure your request, you must create a "prehash" string that incorporates the HTTP method, path, query parameters, timestamp, and headers. The prehash format is:
${method}:${path}?${queryParamsString}:${timestamp}:${sortedHeaders}${bodyString};
Below is an example function to generate this prehash in JavaScript:
// if you're using typescript we recommend copying this method directly
function preparePrehash({
method,
timestamp,
path,
queryParams,
headers,
body,
}: PrehashParams) {
const filtered = Object.entries(headers).filter(([key]) =>
key.toLowerCase().startsWith("x-definitive-")
);
// ensure that the headers are sorted for consistency
const sortedHeaders = filtered
.sort(([a], [b]) => a.localeCompare(b))
.map(([key, value]) => `${key}:${JSON.stringify(value)}`)
.join(",");
// only pass x-definitive-api-key and x-definitive-timestamp
if (filtered.length > 2) {
throw new Error("Headers are too long - are you adding a new header?");
}
// stringify the query params eg. 'key=value&key2=value2'
const queryParamsString = new URLSearchParams(queryParams).toString();
// Use an empty string if no body is provided
const bodyString = body ?? "";
return `${method}:${path}?${queryParamsString}:${timestamp}:${sortedHeaders}${bodyString}`;
}
const timestamp = Date.now().toString();
// generate the message to be signed
const message = preparePrehash({
method: "POST",
path: "/v2/portfolio/trade",
timestamp,
headers: {
"x-definitive-api-key": apiKey,
"x-definitive-timestamp": timestamp,
},
queryParams: {},
});
Step 3: Sign the Request
After generating the prehash message, sign it using your API secret. Remove the dpks_ prefix from your API secret (if present) and create an HMAC using SHA-256.
/**
* Signs a message using HMAC SHA256.
*/
function signMessage(message) {
const signingSecret = apiSecret.replace("dpks_", "");
return crypto.createHmac("sha256", signingSecret)
.update(message)
.digest("hex");
}
Step 4: Generate the Quote
These orders will be scoped to the portfolio for which you created the keys. It is necessary to generate the quote in order to submit a valid request.
async function generateQuote() {
const method = "POST";
const path = "/v2/portfolio/trade/quote";
const timestamp = Date.now().toString();
const headers = {
"x-definitive-api-key": apiKey,
"x-definitive-timestamp": timestamp,
"Content-Type": "application/json"
};
// Replace these addresses with valid tokens for your trade.
const quoteRequest = {
type: "market", // "market", "limit", "twap", or "stop"
chain: "base", // example chain; change if needed
targetAsset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // e.g., USDC on base
contraAsset: "0x4200000000000000000000000000000000000006", // e.g., WETH on base
qty: "10.00", // trade quantity
orderSide: "sell", // "buy" or "sell"
slippageTolerance: "0.01", // 1% slippage tolerance
maxPriceImpact: "0.05" // 5% maximum price impact
};
const bodyString = JSON.stringify(quoteRequest);
// Prepare a prehash message using the current parameters.
const prehashMessage = preparePrehash({
method,
path,
timestamp,
headers,
queryParams: {},
body: bodyString
});
const signature = signMessage(prehashMessage);
try {
const response = await fetch(`https://ddp.definitive.fi${path}`, {
method,
headers: {
...headers,
"x-definitive-signature": signature
},
body: bodyString
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status} - ${response.statusText}`);
}
const json = await response.json();
console.log("Quote Response:", json);
return json;
} catch (error) {
console.error("Error generating quote:", error);
throw error;
}
}
Step 5: Submit the Request
Now that we have the ability to generate a prehash, sign the message, and generate a quote: we are ready to submit a request.
async function submitTradeFromQuote() {
try {
const quoteResponse = await generateQuote();
if (!quoteResponse || !quoteResponse.quote) {
throw new Error("Invalid quote response.");
}
const method = "POST";
const path = "/v2/portfolio/trade";
const timestamp = Date.now().toString();
const headers = {
"x-definitive-api-key": apiKey,
"x-definitive-timestamp": timestamp,
"Content-Type": "application/json"
};
// Use the quote object directly for the trade
const bodyString = JSON.stringify(quoteResponse.quote);
const prehashMessage = preparePrehash({
method,
path,
timestamp,
headers,
queryParams: {},
body: bodyString
});
const signature = signMessage(prehashMessage);
const response = await fetch(`https://ddp.definitive.fi${path}`, {
method,
headers: {
...headers,
"x-definitive-signature": signature
},
body: bodyString
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status} - ${response.statusText}`);
}
const orderResponse = await response.json();
console.log("Order Response:", orderResponse);
return orderResponse;
} catch (error) {
console.error("Error in submitting trade from quote:", error);
throw error;
}
}
Now, if you call submitTradeFromQuote()
it will generate a quote and submit it. Please make sure you are using the correct parameters to prevent any accidental swaps.
Key Takeaways
- Generating The Prehash
- Signing the Message
- Generating a Quote with the new v2 format
- Submitting the Request to v2 endpoints