Skip to content

Making Your First Request

This guide walks through making your first authenticated request to the Definitive API. The same authentication mechanism applies to both the Portfolio API and the Organization API — the only difference is the URL paths.

Authentication

Before making a request, generate an API key and secret. See Generate an API Key in the Overview guide for details.

All authenticated requests require these headers:

  • x-definitive-api-key: Your API key
  • x-definitive-signature: A signature generated using your API secret
  • x-definitive-timestamp: The current timestamp

Making Your First Request

We'll walk through a request step by step. A helper class AuthHelpers is available in the Request Authorization section to simplify this, but we'll go through the manual process first.

Step 1: Define API Key, Secret, and Timestamp

const apiKey = process.env.API_KEY;
const apiSecret = process.env.API_SECRET;
const timestamp = Date.now().toString();

Step 2: Prepare the Prehash

For security, all requests must be signed and submitted within 2 minutes. The prehash format is:

${method}:${path}?${queryParamsString}:${timestamp}:${sortedHeaders}${bodyString};

type PrehashParams = {
  method: "GET" | "POST" | "DELETE";
  path: string;
  timestamp: string;
  headers: Record<string, string | number | object>;
  queryParams?: Record<string, string>;
  body?: string;
};
 
function preparePrehash({
  method,
  timestamp,
  path,
  queryParams,
  headers,
  body,
}: PrehashParams) {
  const filtered = Object.entries(headers).filter(([key]) =>
    key.toLowerCase().startsWith("x-definitive-"),
  );
 
  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?");
  }
 
  const queryParamsString = new URLSearchParams(queryParams).toString();
  const bodyString = body ?? "";
 
  return `${method}:${path}?${queryParamsString}:${timestamp}:${sortedHeaders}${bodyString}`;
}

Step 3: Sign the Request

Remove the dpks_ prefix from your API secret and generate an HMAC SHA-256 signature:

const secret = apiSecret.replace("dpks_", "");
const signature = crypto
  .createHmac("sha256", secret)
  .update(message)
  .digest("hex");

Step 4: Make the Request

Portfolio API

const result = await fetch("https://ddp.definitive.fi/v2/portfolio/orders", {
  method: "GET",
  headers: {
    "x-definitive-api-key": apiKey,
    "x-definitive-signature": signature,
    "x-definitive-timestamp": timestamp,
  },
});
const json = await result.json();

Organization API

const result = await fetch("https://ddp.definitive.fi/v2/organization", {
  method: "GET",
  headers: {
    "Content-Type": "application/json",
    Accept: "application/json",
    "x-definitive-api-key": apiKey,
    "x-definitive-signature": signature,
    "x-definitive-timestamp": timestamp,
  },
});
const json = await result.json();

Using AuthHelpers (Recommended)

The AuthHelpers class from the Request Authorization section handles prehashing and signing automatically:

import { AuthHelpers } from "./auth-helpers";
 
// Portfolio API
const portfolioOrders = await AuthHelpers.signAndSend({
  path: "/v2/portfolio/orders",
  method: "GET",
  apiKey: process.env.API_KEY,
  apiSecret: process.env.API_SECRET,
});
 
// Organization API
const orgData = await AuthHelpers.signAndSend({
  path: "/v2/organization",
  method: "GET",
  apiKey: process.env.API_KEY,
  apiSecret: process.env.API_SECRET,
});

Common Authentication Errors

If you see 401 Unauthorized or Invalid API Authentication, check:

  1. Are your headers sorted alphabetically in the prehash?
  2. Are header values JSON.stringify'd with quotes?
  3. Is your timestamp within 2 minutes of the current time?

Correct prehash headers

const headersForPrehash = {
  "x-definitive-api-key": apiKey,
  "x-definitive-timestamp": timestamp,
};

Error Handling

Common error responses:

  • 400 Bad Request: Invalid request body, or a rejected order (e.g. cross-chain slippage mismatch)
  • 401 Unauthorized: Invalid or missing API key/signature
  • 403 Forbidden: Access denied or invalid organization ID
  • 408 Request Timeout: Timestamp is too old (>2 minutes)
  • 422 Unprocessable Entity: Not currently executable (e.g. cross-chain trading vault still initializing)
  • 500 Internal Server Error: Unexpected server error

See Error Codes for the full list.

Next Steps