> ## Documentation Index
> Fetch the complete documentation index at: https://yieldxyz.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Open a perps position

> Discover a Hyperliquid market, open a leveraged position, sign the returned transactions including any builder-fee approval, and track it.

Open, sign, submit, and track a perpetual futures position through the Perps API: discover a provider and market, request an `open` action, sign whatever transactions come back (including ones you didn't ask for), and read the resulting position. This goes beyond [Perps](/documentation/trade/perps): it walks one open through real request and response shapes, including the typed-data signature Hyperliquid requires.

<Warning>
  Perps trading carries jurisdictional restrictions. Read the [perpetuals disclaimer](/legal/perpetuals-disclaimer) before integrating, and see [Geo-blocking](#geo-restrictions) below.
</Warning>

Two provider IDs are live, both settling on Hyperliquid with USDC collateral: `hyperliquid` (Hyperliquid's main perpetual dex) and `hyperliquid-xyz` (its HIP-3 builder-deployed "xyz" market set). No other venue is integrated today.

<Note>
  This guide is not a trading tutorial. It doesn't cover leverage strategy, position sizing, or PnL management, only the API calls to open and track a position.
</Note>

## Prerequisites

* Your project API key, sent as `x-api-key` on every request to `https://perps.yield.xyz/v1`. The same project key authenticates the Yield, Perps, and Borrow APIs.
* A signer that can produce an EIP-712 typed-data signature (most Hyperliquid transactions) as well as sign and broadcast a plain EVM transaction (Arbitrum funding transactions). The examples below use [viem](https://viem.sh/).

<Note>
  We construct. You sign. Every action returns unsigned transactions; yield.xyz never holds keys and never signs on your behalf. Inspect `signablePayload` before signing it, and never modify it.
</Note>

## Discover a provider and market

`GET /v1/providers` returns each live provider with its `supportedActions` and per-action `argumentSchemas`: treat it as authoritative over any table in these docs for what your project can call.

```bash cURL theme={null}
curl --request GET \
  --url https://perps.yield.xyz/v1/providers \
  --header "x-api-key: $PERPS_API_KEY"
```

Then list markets for the provider you picked and choose one by base asset. Market IDs follow `{providerId}-{coin}-{quote}`; don't hardcode one, select it from the response:

```bash cURL theme={null}
curl --request GET \
  --url 'https://perps.yield.xyz/v1/markets?providerId=hyperliquid' \
  --header "x-api-key: $PERPS_API_KEY"
```

```json Response (excerpt) theme={null}
{
  "id": "hyperliquid-eth-usdc",
  "providerId": "hyperliquid",
  "baseAsset": "ETH",
  "quoteAsset": "USDC",
  "leverageRange": [1, 25],
  "supportedMarginModes": ["cross", "isolated"],
  "minSize": 10.22,
  "markPrice": "..."
}
```

Check `leverageRange`, `supportedMarginModes`, and `minSize` against what you're about to request. Fetch markets live rather than caching them: price and funding fields change continuously.

## Fund collateral, if needed

If the account has no margin on the venue yet, deposit it first with `action: "fund"`. Native USDC on Arbitrum bridges directly through Hyperliquid's Bridge2 (`fundingMethod: "bridge2"`); anything else routes through LI.FI (`fundingMethod: "lifi"`). Omit `fundingMethod` to get the default for the source token:

```bash cURL theme={null}
curl --request POST \
  --url https://perps.yield.xyz/v1/actions \
  --header "x-api-key: $PERPS_API_KEY" \
  --header 'content-type: application/json' \
  --data '{
    "providerId": "hyperliquid",
    "address": "0xYOUR_WALLET_ADDRESS",
    "action": "fund",
    "args": { "amount": "500", "fromToken": { "network": "arbitrum", "address": "0xYOUR_USDC_ADDRESS" } }
  }'
```

Sign and submit its transactions the same way as an open, below.

## Open a position

Call `POST /v1/actions` with `providerId`, the user's `address`, `action: "open"`, and `args`: the `marketId`, a `side` (`long` or `short`), a `leverage` within the market's `leverageRange`, and either `amount` (margin/collateral in USD) or `size` (position notional in USD). The position must be at least \$10 notional: `size` of at least 10, or `amount` × `leverage` of at least 10. Omit `limitPrice` for a market order, or set it for a limit order. `marginMode` selects `cross` or `isolated` and can't change while the position is open:

```bash cURL theme={null}
curl --request POST \
  --url https://perps.yield.xyz/v1/actions \
  --header "x-api-key: $PERPS_API_KEY" \
  --header 'content-type: application/json' \
  --data '{
    "providerId": "hyperliquid",
    "address": "0xYOUR_WALLET_ADDRESS",
    "action": "open",
    "args": {
      "marketId": "hyperliquid-eth-usdc",
      "side": "long",
      "amount": "100",
      "leverage": 5,
      "marginMode": "cross"
    }
  }'
```

```json Response (excerpt) theme={null}
{
  "id": "action_abc123",
  "providerId": "hyperliquid",
  "action": "open",
  "status": "CREATED",
  "transactions": [
    { "id": "tx_1", "type": "APPROVE_BUILDER_FEE", "status": "CREATED", "signingFormat": "EIP712_TYPED_DATA", "signablePayload": "TYPED_DATA_PAYLOAD" },
    { "id": "tx_2", "type": "OPEN_POSITION", "status": "CREATED", "signingFormat": "EIP712_TYPED_DATA", "signablePayload": "TYPED_DATA_PAYLOAD" }
  ]
}
```

## Special transactions you didn't ask for

A response to `open`, `close`, `stopLoss`, `takeProfit` or `setTpAndSl` can include transactions beyond the one you requested. Sign and submit every transaction in `transactions[]`, in the order returned, whether or not you expected it; never construct one of these yourself:

* **`APPROVE_BUILDER_FEE`**: prepended when the user's currently approved max builder fee on Hyperliquid is below the builder fee applied to the order. It's a one-time approval per fee level, not a repeated cost on every trade. See [Monetization](/documentation/trade/monetization).
* **`SET_USER_ABSTRACTION`**: prepended on an `open` while your project has unified accounts enabled and the account is still eligible to switch, to switch the account into unified margin mode across Hyperliquid venues.

Both use the same `EIP712_TYPED_DATA` signing format as the position transaction itself, so your signing code doesn't need to branch on transaction `type`, only on `signingFormat`.

## Sign and submit

Each transaction carries a `signingFormat` and a `signablePayload`. Hyperliquid venue actions (approvals, opens, closes, and the rest) use `EIP712_TYPED_DATA`; an Arbitrum funding deposit uses `EVM_TRANSACTION`. Sign every transaction in the order returned, submitting each before moving to the next:

<CodeGroup>
  ```typescript Sign EIP-712 (viem) theme={null}
  import { createWalletClient, custom } from 'viem';

  const client = createWalletClient({ transport: custom(window.ethereum) });

  async function signTypedDataTx(tx: { signablePayload: Record<string, any> }) {
    const { domain, types, primaryType, message } = tx.signablePayload;
    return client.signTypedData({ account: userAddress, domain, types, primaryType, message });
  }
  ```

  ```bash cURL Submit theme={null}
  curl --request POST \
    --url https://perps.yield.xyz/v1/transactions/$TRANSACTION_ID/submit \
    --header "x-api-key: $PERPS_API_KEY" \
    --header 'content-type: application/json' \
    --data '{ "signedPayload": "0xYOUR_SIGNATURE" }'
  ```
</CodeGroup>

For an `EVM_TRANSACTION` transaction (an Arbitrum funding deposit), sign and broadcast it with your usual EVM signer; see [Transaction signing](/guides/transaction-signing/evm) for chain-specific code. Submit with either `signedPayload` (yield.xyz broadcasts it) or `transactionHash` (you already broadcast it).

Then poll the action until it settles:

```bash cURL theme={null}
curl --request GET \
  --url https://perps.yield.xyz/v1/actions/$ACTION_ID \
  --header "x-api-key: $PERPS_API_KEY"
```

## Verify

Read open positions with `POST /v1/positions`, passing `address` and `providerId` (or `providerIds` for more than one):

```bash cURL theme={null}
curl --request POST \
  --url https://perps.yield.xyz/v1/positions \
  --header "x-api-key: $PERPS_API_KEY" \
  --header 'content-type: application/json' \
  --data '{ "address": "0xYOUR_WALLET_ADDRESS", "providerId": "hyperliquid" }'
```

```json Response (excerpt) theme={null}
{
  "marketId": "hyperliquid-eth-usdc",
  "side": "long",
  "size": "0.05",
  "entryPrice": "...",
  "leverage": 5,
  "marginMode": "cross",
  "liquidationPrice": "...",
  "pendingActions": []
}
```

A limit order that hasn't filled yet won't appear here; check `POST /v1/orders` with the same `address` and `providerId` for resting orders instead. See [Core concepts](/documentation/trade/core-concepts/index) for what every position and order field means, and pass a `pendingActions` entry straight into `POST /v1/actions` instead of reconstructing it.

## Geo-restrictions

`POST /v1/actions` checks the caller's IP against banned regions and returns `403` when blocked, with a message naming the detected country. It also returns `403` (`EXECUTE_FORBIDDEN`) when your project is disabled for the provider or for Perps. See [Geo-blocking](/documentation/advanced-setup/geo-blocking/index) for how bans are configured.

## Next steps

<Columns cols={2}>
  <Card title="Perps" icon="chart-candlestick" href="/documentation/trade/perps">
    The provider, market, and action model this guide builds on.
  </Card>

  <Card title="Core concepts" icon="shapes" href="/documentation/trade/core-concepts/index">
    Every market, order, and position field this guide reads back.
  </Card>

  <Card title="Monetization" icon="percent" href="/documentation/trade/monetization">
    How the builder fee and its one-time approval are configured.
  </Card>

  <Card title="Transaction signing" icon="pen-nib" href="/guides/transaction-signing/evm">
    EVM signing code for the Arbitrum funding transaction.
  </Card>
</Columns>

The Perps widget and Perps dashboard are coming soon; see [Perps widget](/guides/widgets-dashboard/perps-widget) and [Perps dashboard](/guides/widgets-dashboard/perps-dashboard).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.