Trading App API

REST API documentation for the Trading Application

Authentication

Protected endpoints use cookie-based auth. Log in via /api/auth/login to receive the auth_token httpOnly cookie.

The auth_token cookie is set automatically on login and sent with every same-origin request — no Authorization header is needed for browser-based access.

Base URL

https://api.PLACEHOLDER.com

Production — replace PLACEHOLDER with the assigned domain before go-live

http://10.200.0.52:3000

VPN (internal development)

http://localhost:3000

Local development

Errors

All error responses share the same JSON envelope:

{
  "error": "Description of what went wrong",
  "code":  "400"
}
HTTP StatusMeaning
400Bad Request — invalid parameters
401Unauthorized — missing or invalid auth
403Forbidden — insufficient permissions
404Not Found
409Conflict — resource already exists
500Internal Server Error

Auth

POST/auth/login

Responses

StatusDescription
400Bad Request — invalid parameters
500Internal Server Error

Example Request

curl -X POST https://<host>/api/auth/login \
  -H "Content-Type: application/json" \
  -c cookies.txt \
  -d '{
    "email": "trader@havencap.io",
    "password": "mypassword123"
  }'

Example Response

{
  "user": {
    "userId": "cm1abc123xyz",
    "email": "trader@havencap.io",
    "role": "OPERATOR",
    "createdAt": "2026-04-01T09:00:00.000Z"
  },
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
POST/auth/logout

Responses

StatusDescription
400Bad Request — invalid parameters
500Internal Server Error

Example Request

curl -X POST https://<host>/api/auth/logout \
  -b cookies.txt

Example Response

{
  "message": "Logged out"
}
GET/auth/me

Responses

StatusDescription
400Bad Request — invalid parameters
500Internal Server Error

Example Request

curl https://<host>/api/auth/me \
  -b cookies.txt

Example Response

{
  "user": {
    "userId": "cm1abc123xyz",
    "email": "trader@havencap.io",
    "role": "OPERATOR",
    "createdAt": "2026-04-01T09:00:00.000Z"
  }
}
GET/auth/refresh

Used by the middleware redirect flow: GET /api/auth/refresh?callbackUrl=/markets

Responses

StatusDescription
400Bad Request — invalid parameters
500Internal Server Error

Example Request

// Browser redirect flow — used by middleware:
GET /api/auth/refresh?callbackUrl=/markets

Example Response

// 302 redirect to /markets with refreshed auth_token cookie set
POST/auth/refresh

Used by client-side fetch interceptors: POST /api/auth/refresh

Responses

StatusDescription
400Bad Request — invalid parameters
500Internal Server Error

Example Request

curl -X POST https://<host>/api/auth/refresh \
  -b cookies.txt

Example Response

{
  "user": {
    "userId": "cm1abc123xyz",
    "email": "trader@havencap.io",
    "role": "OPERATOR",
    "createdAt": "2026-04-01T09:00:00.000Z"
  }
}
POST/auth/register

Responses

StatusDescription
400Bad Request — invalid parameters
500Internal Server Error

Example Request

curl -X POST https://<host>/api/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "email": "trader@havencap.io",
    "password": "mypassword123"
  }'

Example Response

// First registered user — becomes ADMIN and receives a token:
{
  "user": {
    "userId": "cm1abc123xyz",
    "email": "trader@havencap.io",
    "role": "ADMIN",
    "createdAt": "2026-05-01T09:00:00.000Z"
  },
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

// Subsequent registrations — account awaits admin approval:
{
  "message": "Registration successful. Your account is pending admin approval."
}
POST/auth/verify

Responses

StatusDescription
400Bad Request — invalid parameters
500Internal Server Error

Income

GET/income

Responses

StatusDescription
400Bad Request — invalid parameters
500Internal Server Error
GET/income/custom

Responses

StatusDescription
400Bad Request — invalid parameters
500Internal Server Error

Lp

GET/lp

Responses

StatusDescription
400Bad Request — invalid parameters
500Internal Server Error
GET/lp/total

Responses

StatusDescription
400Bad Request — invalid parameters
500Internal Server Error

V1

GET/v1/health

Responses

StatusDescription
400Bad Request — invalid parameters
500Internal Server Error

Example Request

curl https://<host>/api/v1/health \
  -H "Authorization: Bearer <your_token>"

Example Response

{
  "status": "ok",
  "last_indexed_block": 22450100,
  "last_indexed_timestamp": "2026-04-30T14:22:00Z",
  "chain_tip_block": 22450112,
  "ingestion_lag_seconds": 144.0
}
GET/v1/transactions

Responses

StatusDescription
400Bad Request — invalid parameters
500Internal Server Error

Example Request

curl -G https://<host>/api/v1/transactions \
  -H "Authorization: Bearer <your_token>" \
  --data-urlencode "address=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" \
  --data-urlencode "from_date=2026-04-01T00:00:00Z" \
  --data-urlencode "sort=-timestamp" \
  --data-urlencode "page_size=20"

Example Response

{
  "data": [
    {
      "hash": "0xabc123...",
      "block_number": 22400001,
      "block_timestamp": "2026-04-30T12:00:12Z",
      "from_address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "to_address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
      "value_native": "0.00 ETH",
      "value_usd": 0.00,
      "gas_used": 65000,
      "gas_price_gwei": 12.5,
      "gas_fee_usd": 2.44,
      "status": "success",
      "token_transfers": [
        {
          "token_symbol": "USDC",
          "amount_display": "250.00 USDC",
          "amount_usd": 250.00
        }
      ]
    }
  ],
  "page": 1,
  "page_size": 20,
  "total_results": 142,
  "total_pages": 8,
  "next_page_url": "https://<host>/api/v1/transactions?...&page=2",
  "prev_page_url": null
}
GET/v1/blocks/{block_number}

Responses

StatusDescription
400Bad Request — invalid parameters
500Internal Server Error

Example Request

curl https://<host>/api/v1/blocks/22400001 \
  -H "Authorization: Bearer <your_token>"

Example Response

{
  "block_number": 22400001,
  "block_timestamp": "2026-04-30T12:00:12Z",
  "transaction_count": 3,
  "transaction_hashes": [
    "0xabc123...",
    "0xdef456...",
    "0x789abc..."
  ]
}
GET/v1/tokens/{contract_address}

Responses

StatusDescription
400Bad Request — invalid parameters
500Internal Server Error

Example Request

curl https://<host>/api/v1/tokens/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 \
  -H "Authorization: Bearer <your_token>"

Example Response

{
  "contract_address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
  "symbol": "USDC",
  "name": "USD Coin",
  "decimals": 6
}
GET/v1/transactions/{hash}

Responses

StatusDescription
400Bad Request — invalid parameters
500Internal Server Error

Example Request

curl https://<host>/api/v1/transactions/0xabc123def456... \
  -H "Authorization: Bearer <your_token>"

Example Response

{
  "hash": "0xabc123def456...",
  "block_number": 22400001,
  "block_timestamp": "2026-04-30T12:00:12Z",
  "from_address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
  "to_address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
  "value_native": "0.00 ETH",
  "value_usd": 0.00,
  "gas_used": 65000,
  "gas_price_gwei": 12.5,
  "gas_fee_eth": 0.0008125,
  "gas_fee_usd": 2.44,
  "status": "success",
  "token_transfers": [
    {
      "contract_address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
      "token_symbol": "USDC",
      "token_name": "USD Coin",
      "token_standard": "ERC-20",
      "from_address": "0xd8dA6BF...",
      "to_address": "0xRecipient...",
      "amount_display": "250.00 USDC",
      "amount_usd": 250.00,
      "token_id": null
    }
  ],
  "price_source": "uniswap_v3",
  "price_timestamp": "2026-04-30T12:00:12Z"
}
GET/v1/transactions/address/{address}

Responses

StatusDescription
400Bad Request — invalid parameters
500Internal Server Error

Example Request

curl "https://<host>/api/v1/transactions/address/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045?page_size=10" \
  -H "Authorization: Bearer <your_token>"

Example Response

{
  "data": [ /* array of Transaction objects */ ],
  "page": 1,
  "page_size": 10,
  "total_results": 38,
  "total_pages": 4,
  "next_page_url": "https://<host>/api/v1/transactions/address/0xd8dA...?page=2",
  "prev_page_url": null
}