Skip to content
UDX
On this page

Quick Start

Make your first UDX request, from choosing a market to placing an order and reading its outcome.

Choose an Environment

Set the base URLs once before running the examples:

export UDX_BASE_URL="https://api.uat.udx.underdogsports.com"
export UDX_WS_URL="wss://api.uat.udx.underdogsports.com/ws"

The user acceptance testing (UAT) environment is a production-like environment used for testing. All trading performed there uses fake funds.

See Connecting for every environment’s endpoints.

Pick a Market

The market catalog is public. Read it and take the ticker for a market whose status is open:

curl "${UDX_BASE_URL}/markets?status=open"

See Discovering Markets for reading the catalog and order books in depth.

Create an API Key

Open the UDX app in the UAT environment and create an API key with access to the account you will use. Give it the read scope to stream market data and the trade scope to place orders, quotes, and RFQs. Save the API key ID and private key, then set their values in your environment:

export UDX_ACCESS_KEY="<api-key-id>"
export UDX_PRIVATE_KEY_PATH="<path-to-private-key.pem>"

See Authentication for scopes and the complete signing rules.

Place an Order

This example uses Node.js 18 or newer and only built-in modules. Save it as place-order.mjs, replace the example ticker with one from an open market, then run node place-order.mjs.

import {
  constants,
  createHash,
  createPrivateKey,
  sign,
} from "node:crypto";
import { readFileSync } from "node:fs";

const baseUrl = process.env.UDX_BASE_URL;
const accessKey = process.env.UDX_ACCESS_KEY;
const privateKeyPath = process.env.UDX_PRIVATE_KEY_PATH;

if (!baseUrl || !accessKey || !privateKeyPath) {
  throw new Error(
    "Set UDX_BASE_URL, UDX_ACCESS_KEY, and UDX_PRIVATE_KEY_PATH first.",
  );
}

const method = "POST";
const path = "/orders";
const timestamp = Date.now().toString();
const body = JSON.stringify({
  ticker: "UDX-EXAMPLE-MARKET",
  client_order_id: "first-order",
  side: "buy",
  quantity: "1",
  price: "0.55",
  time_in_force: "gtc",
});

const bodyHash = createHash("sha256").update(body).digest("hex");
const message = timestamp + method + path + bodyHash;
const privateKey = createPrivateKey(
  readFileSync(privateKeyPath, "utf8"),
);
const signature = sign("sha256", Buffer.from(message), {
  key: privateKey,
  padding: constants.RSA_PKCS1_PSS_PADDING,
  saltLength: 32,
}).toString("base64");

const response = await fetch(`${baseUrl}${path}`, {
  method,
  headers: {
    "Content-Type": "application/json",
    "UDX-Access-Key": accessKey,
    "UDX-Access-Timestamp": timestamp,
    "UDX-Access-Signature": signature,
  },
  body,
});

const result = await response.json();
if (!response.ok) {
  throw new Error(`${response.status}: ${JSON.stringify(result)}`);
}

console.log(result);

A successful submission answers 202 Accepted with an order_id. See Place an Order for the full request and response.

Read the Outcome

Placement is asynchronous: poll Get Order with the returned order_id until it reads resting, filled, or rejected.

See Asynchronous Writes for how to read outcomes and retry safely, and Placing Orders for amending and canceling what you just placed.