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

Bet

Place, execute, and exit bets

Bound constraints

get
/api/which-first/limits

Per-asset constraints so you can validate bounds without a /quote round-trip. Same source as the server-side gates, so values never drift.

coin is optional and defaults to the launch asset. URL-encode HIP-3 names: ?coin=xyz%3ATSLA, not ?coin=xyz:TSLA.

Authorizations
AuthorizationstringRequired

JWT access token from POST /auth/authenticate

Query parameters
coinstringOptional

Asset name (e.g. BTC, ETH). URL-encode HIP-3 names.

Example: BTC
Responses
200

Limit constraints for the asset

application/json
codestringOptional
messagestringOptional
get/api/which-first/limits
GET /api/which-first/limits HTTP/1.1
Host: api.bound.exchange
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*
{
  "code": "1",
  "message": "common.success",
  "data": {
    "coin": "BTC",
    "mark": "61000",
    "maxLeverage": 40,
    "maxBoundDistance": "0.1",
    "minAgainstDistance": {
      "upper_first": "0.015158",
      "lower_first": "0.014846"
    }
  }
}

Price a bet

post
/api/which-first/quote

Pure pricing preview. No wallet gates, no persistence, no side effects.

wager is isolated margin, not order notional. payoutMultiple is profit / wager. To show a total-return multiple, use 1 + payoutMultiple.

This endpoint deliberately does not enforce the configured wager range or Hyperliquid's $10 minimum order notional. Treat /proposals as the authoritative gate.

Authorizations
AuthorizationstringRequired

JWT access token from POST /auth/authenticate

Body
sidestring · enumRequired

Which bound you bet on being touched first

Possible values:
upperBoundstringRequired

Upper price boundary

lowerBoundstringRequired

Lower price boundary

wagerstringRequired

Isolated margin amount in USDC

coinstringOptional

Asset name (e.g. BTC, ETH). Optional — defaults to the launch asset if omitted.

Responses
200

Construction preview

application/json
codestringOptional
messagestringOptional
post/api/which-first/quote
POST /api/which-first/quote HTTP/1.1
Host: api.bound.exchange
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 90

{
  "side": "upper_first",
  "upperBound": "63500",
  "lowerBound": "59000",
  "wager": "20",
  "coin": "BTC"
}
{
  "code": "1",
  "message": "common.success",
  "data": {
    "direction": "long",
    "leverage": 17,
    "notional": "340",
    "coinSize": "0.0056",
    "chosenBound": "63500",
    "losingBound": "59000",
    "takeProfitPrice": "63500",
    "liquidationPrice": "58656.39",
    "payoutMultiple": "0.66",
    "payoutEstimate": "13.25",
    "maxSlippage": "0.01",
    "entryPrice": "61000",
    "wager": "20"
  }
}

Create the bet

post
/api/which-first/proposals

Runs every gate, persists a proposed bet (which holds the per-asset slot), and returns the actions to sign.

Only one open bet per asset per account — including from a different wallet on the same account. A retry while one is open returns 26007.

Enforces the configured wager range (default 10-100,000 USDC) and requires price * coinSize >= $10 for both order wires.

Authorizations
AuthorizationstringRequired

JWT access token from POST /auth/authenticate

Body
sidestring · enumRequiredPossible values:
upperBoundstringRequired
lowerBoundstringRequired
wagerstringRequired
coinstringOptional

Optional — defaults to the launch asset if omitted

userAddressstringRequired

EVM wallet that signs and owns the position

Responses
200

Proposal with unsigned actions to sign

application/json
codestringOptional
messagestringOptional
post/api/which-first/proposals
POST /api/which-first/proposals HTTP/1.1
Host: api.bound.exchange
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 149

{
  "side": "upper_first",
  "upperBound": "63500",
  "lowerBound": "59000",
  "wager": "20",
  "coin": "BTC",
  "userAddress": "0xc12b0a4a5fdd42d1f4aa2a08c2193d1ac49c8167"
}
{
  "code": "1",
  "message": "common.success",
  "data": {
    "betId": "6a3d…",
    "state": "proposed",
    "proposalExpiresAt": "2026-06-26T10:30:00.000Z",
    "construction": {
      "leverage": 17,
      "takeProfitPrice": "63500"
    },
    "unsignedActions": [
      {
        "kind": "update_leverage",
        "action": {
          "type": "updateLeverage"
        }
      },
      {
        "kind": "entry",
        "action": {
          "type": "order",
          "grouping": "normalTpsl"
        }
      }
    ]
  }
}

Relay the signed bundle

post
/api/which-first/{id}/execute

The only signed bodies Bound relays. Sign the unsignedActions from /proposals (entry) or /cash-out, keep each original kind, and send them in order.

Relay-once: 26028 fires when order ids are already recorded, another relay is in flight, or a retry found venue evidence. Never re-sign — a new nonce defeats Hyperliquid's dedup.

26025 is the only definitive "nothing landed" verdict — retrying after it is safe.

Authorizations
AuthorizationstringRequired

JWT access token from POST /auth/authenticate

Path parameters
idstringRequired

Bet ID (24-char hex string)

Example: 6a3d1f2e3b4c5d6e7f8a9b0c
Body
Responses
200

Updated bet after execution

application/json
codestringOptional
messagestringOptional
post/api/which-first/{id}/execute
POST /api/which-first/{id}/execute HTTP/1.1
Host: api.bound.exchange
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 226

{
  "actions": [
    {
      "kind": "update_leverage",
      "action": {
        "type": "updateLeverage"
      },
      "nonce": 1719396000000,
      "signature": "0x…"
    },
    {
      "kind": "entry",
      "action": {
        "type": "order",
        "grouping": "normalTpsl"
      },
      "nonce": 1719396000001,
      "signature": "0x…"
    }
  ]
}
{
  "code": "text",
  "message": "text",
  "data": {
    "_id": "text",
    "accountId": "text",
    "coin": "text",
    "evmAddress": "text",
    "side": "upper_first",
    "upperBound": "text",
    "lowerBound": "text",
    "wager": "text",
    "construction": {
      "direction": "long",
      "leverage": 1,
      "notional": "text",
      "coinSize": "text",
      "chosenBound": "text",
      "losingBound": "text",
      "takeProfitPrice": "text",
      "liquidationPrice": "text",
      "payoutMultiple": "text",
      "payoutEstimate": "text",
      "maxSlippage": "text",
      "entryPrice": "text",
      "assetIndex": 1,
      "szDecimals": 1,
      "maintenanceMarginFraction": "text",
      "builderFeeRate": "text"
    },
    "state": "proposed",
    "proposalExpiresAt": "2026-01-01T00:00:00.000Z",
    "activatedAt": "2026-01-01T00:00:00.000Z",
    "resolvedAt": "2026-01-01T00:00:00.000Z",
    "abortReason": "proposal_expired",
    "voidReason": "tp_cancelled",
    "cashOutPending": true,
    "boundBreachFlagged": true,
    "venueRefs": {
      "entryOid": "text",
      "takeProfitOid": "text",
      "closeOid": "text"
    },
    "actuals": {
      "actualEntryPrice": "text",
      "actualLiquidationPrice": "text",
      "actualPayoutMultiple": "text",
      "actualCoinSize": "text",
      "actualMarginUsed": "text",
      "fundingAtActivation": "text",
      "finalProceeds": "text",
      "feesPaid": "text",
      "fundingPaid": "text",
      "netProceeds": "text"
    },
    "relayClaimedAt": "2026-01-01T00:00:00.000Z",
    "createdAt": 1,
    "updatedAt": 1,
    "deletedAt": "2026-01-01T00:00:00.000Z"
  }
}

Exit early

post
/api/which-first/{id}/cash-out

Returns an unsigned bundle that cancels the resting take-profit and closes the position reduce-only. Only for an active bet.

Sign both actions and send them to POST /{id}/execute — same as the entry bundle. Repeating a cash-out is a no-op; a bet that is no longer active returns 26012.

Authorizations
AuthorizationstringRequired

JWT access token from POST /auth/authenticate

Path parameters
idstringRequired

Bet ID (24-char hex string)

Example: 6a3d1f2e3b4c5d6e7f8a9b0c
Body
objectOptional
Responses
200

Cash-out bundle with unsigned actions

application/json
codestringOptional
messagestringOptional
post/api/which-first/{id}/cash-out
POST /api/which-first/{id}/cash-out HTTP/1.1
Host: api.bound.exchange
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 2

{}
{
  "code": "1",
  "message": "common.success",
  "data": {
    "betId": "6a3d…",
    "unsignedActions": [
      {
        "kind": "cancel",
        "action": {
          "type": "cancel"
        }
      },
      {
        "kind": "cash_out_close",
        "action": {
          "type": "order"
        }
      }
    ]
  }
}

Last updated