For the complete documentation index, see llms.txt. This page is also available as Markdown.

Demo Code

TypeScript examples for RWA API integration. HMAC authentication uses Node crypto; on-chain actions use viem.

npm install viem

Set environment variables:

export TRADING_API_KEY="your-api-key"
export TRADING_API_SECRET="your-api-secret"
export TRADING_USER_PRIVATE_KEY="0x..."   # self-submit / One Click user wallet

API client with HMAC

import crypto from "node:crypto";

const BASE_URL = "https://mainnet-api.monday.trade/rwa/trading";

type HttpMethod = "GET" | "POST" | "DELETE";

interface TradingApiConfig {
    apiKey: string;
    apiSecret: string;
    chainId: number;
    productType: "MondayTrade";
}

function canonicalUri(path: string, query: Record<string, string | string[] | undefined> = {}): string {
    const pairs: string[] = [];
    for (const key of Object.keys(query).sort()) {
        const value = query[key];
        if (value === undefined || value === null) continue;
        if (Array.isArray(value)) {
            for (const item of value) pairs.push(`${key}=${item}`);
        } else {
            pairs.push(`${key}=${value}`);
        }
    }
    return pairs.length === 0 ? path : `${path}?${pairs.join("&")}`;
}

function signTradingApi(
    apiSecret: string,
    method: HttpMethod,
    path: string,
    query: Record<string, string | string[] | undefined>,
    timestamp: number,
    nonce: string,
    rawBody: string,
): string {
    const uri = canonicalUri(path, query);
    const payload = [method, uri, String(timestamp), nonce, rawBody].join("\n");
    return crypto.createHmac("sha256", apiSecret).update(payload, "utf8").digest("hex");
}

async function tradingApiRequest<T>(
    config: TradingApiConfig,
    method: HttpMethod,
    path: string,
    options: {
        query?: Record<string, string | string[] | undefined>;
        body?: unknown;
    } = {},
): Promise<T> {
    const query = options.query ?? {};
    const rawBody = options.body === undefined ? "" : JSON.stringify(options.body);
    const timestamp = Date.now();
    const nonce = crypto.randomUUID();
    const signature = signTradingApi(config.apiSecret, method, path, query, timestamp, nonce, rawBody);

    const url = new URL(`${BASE_URL}${canonicalUri(path, query)}`);
    const response = await fetch(url, {
        method,
        headers: {
            "content-type": "application/json",
            "x-api-key": config.apiKey,
            "x-api-ts": String(timestamp),
            "x-api-nonce": nonce,
            "x-api-sign": signature,
            "x-api-chain-id": String(config.chainId),
            "x-api-p": config.productType,
        },
        body: method === "GET" || method === "DELETE" ? undefined : rawBody,
    });

    const json = await response.json() as { code?: number; errMsg?: string; data?: T };
    if (json.code !== 200) {
        throw new Error(json.errMsg || `API error ${json.code}`);
    }
    return json.data as T;
}

Self-submit market buy (viem)

Build calldata from the API, broadcast with viem, then record the tx hash.

Deposit with ERC-20 approve (viem)

Approve the spender, then self-submit deposit calldata.

Spender addresses: cash/deposits.md.

Order with deposit (self-submit)

Use /orders/with-deposit/calldata when the same transaction should deposit an approved token and place an order. For buy orders, the cash deposit must be eligible for instant deposit. The token must be approved before submitting the returned calldata.

Stock deposit and withdrawal (self-submit)

Stock endpoints move ERC-20 stock tokens between wallet balance and exchangeBalance. Approve StockRouter for the stock token before calling stock deposit calldata.

One Click enable (viem signTypedData)

User signs the EIP-712 payload from /1ct/prepare, then submits to /1ct/enable.

After enable, use /send endpoints — see one-click-flow.md.

One Click order (via /send)

Once One Click is enabled, place orders with /orders/send. The API builds the calldata and broadcasts it through OneClickRouter, paying gas on the user's behalf — no per-order wallet signature or self-broadcast. The body is the same as /orders/calldata, plus an optional gasLimit (set a buffer; router calls can under-estimate gas on some chains). The response is the order-tx mapping, not calldata: poll it (or /orders/tx/{txHash}) until orderId is populated.

Cancel an open One Click order the same way — DELETE /api/v1/orders/{orderId}/send (query deadline required, gasLimit optional) — which also broadcasts through the router.

Query portfolio

Query corporate actions

See also authenticate/examples.md for Node.js-only HMAC snippets.

Last updated