PerpsKit
PerpsKit is a unified layer for interacting with on-chain perpetual futures. It provides normalized market data, trading actions, account state, and transaction construction across multiple perpetual DEX protocols and networks.
What PerpsKit Does
-
Unified trading actions
A single action model works across all supported perpetual exchanges. Currently exposed action types:
Action Description openOpen a new long/short position (market or limit) closeClose (full or partial) an existing position updateLeverageChange leverage for a market updateMarginAdd or remove isolated margin from a position stopLoss/takeProfitPlace a single TP or SL trigger order setTpAndSlBundled action that creates/updates both TP and SL editOrderModify an existing open order cancelOrderCancel one or many open orders fund/withdrawDeposit or withdraw collateral (cross-chain capable) approveAgentApprove an agent wallet for delegated trading approveBuilderFeeApprove a builder-code fee recipient (Hyperliquid) -
Cross-protocol, cross-chain coverage
- Live:
- Hyperliquid (provider id
hyperliquid)
- Hyperliquid (provider id
- In progress / planned:
- GMX
- Lighter
- Drift
- dYdX v4
- Live:
-
Consistent data structures PerpsKit exposes normalized DTOs:
- MarketDto — metadata, prices, fees, leverage range, funding
- ActionDto — high-level trading intent, current status, transaction list
- TransactionDto — unsigned EIP-712 / EVM / protocol-specific payloads to sign
- PositionDto / OrderDto / BalanceDto — normalized portfolio state
- EventDto — async venue outcomes (fills, liquidations, TP/SL triggers)
-
Portfolio & balances Unified endpoints for:
- Open positions
- Open orders
- Collateral balance, margin usage, account value, unrealized PnL
Authentication
All endpoints (except /v1/health) require an x-api-key header. Keys are rate-limited per category (trial / standard / pro).
Core Endpoints
Discovery & Metadata
List providers
GET /v1/providers
Returns the available perp providers, their network, supported actions, argument schemas, and metadata.
Get provider details
GET /v1/providers/{providerId}
List markets (paginated)
GET /v1/markets?providerId=hyperliquid&sortBy=volume24h&order=desc&limit=50&offset=0
Query params:
| Param | Type | Notes |
|---|---|---|
providerId | string | Optional filter |
sortBy | volume24h | markPrice | priceChangePercent24h | Optional |
order | asc | desc | Default desc |
limit, offset | number | Standard pagination |
Each item in items[] is a MarketDto:
{
"id": "hyperliquid-eth-usdc",
"providerId": "hyperliquid",
"baseAsset": {
"symbol": "ETH",
"name": "Ethereum",
"network": "hyperliquid",
"decimals": 18
},
"quoteAsset": {
"symbol": "USDC",
"network": "hyperliquid",
"decimals": 6
},
"leverageRange": [1, 50],
"supportedMarginModes": ["isolated", "cross"],
"markPrice": 3950.42,
"oraclePrice": 3949.87,
"priceChange24h": -1.23,
"priceChangePercent24h": -0.031,
"volume24h": 3110000000,
"openInterest": 18234.56,
"makerFee": "0.0002",
"takerFee": "0.0004",
"fundingRate": "0.00012",
"fundingRateIntervalHours": 8,
"minSize": 10.22,
"metadata": {
"name": "ETH-USDC Perpetual",
"logoURI": "https://assets.stakek.it/markets/hyperliquid-eth-usdc.svg",
"url": "https://app.hyperliquid.xyz/trade/ETH"
}
}Get a single market (with chart config)
GET /v1/markets/{marketId}
Same shape as a list item, plus a chartConfig block:
{
"id": "hyperliquid-eth-usdc",
"providerId": "hyperliquid",
"...": "all MarketDto fields above",
"chartConfig": {
"pricescale": 100,
"minmov": 1,
"supportedResolutions": ["1", "5", "15", "60", "240", "1D"],
"hasIntraday": true,
"hasDaily": true
}
}Get historical candles
GET /v1/markets/{marketId}/candles?interval=1h&from=1733000000000&to=1733600000000
OHLCV data, max 5,000 candles per request. Supported intervals are exposed via the chart config on GET /v1/markets/{marketId}.
{
"marketId": "hyperliquid-eth-usdc",
"interval": "1h",
"candles": [
{
"openTime": 1704067200000,
"closeTime": 1704070799999,
"open": "42150.5",
"high": "42500.0",
"low": "42000.0",
"close": "42350.25",
"volume": "1234.56",
"trades": 482
}
]
}Actions
Execute an action
POST /v1/actions
{
"providerId": "hyperliquid",
"address": "0x1234...",
"action": "open",
"args": {
"marketId": "hyperliquid-eth-usdc",
"side": "short",
"amount": "43",
"leverage": 20,
"marginMode": "isolated"
}
}Returns an ActionDto containing one or more unsigned transactions[] to sign and submit. If args.limitPrice is set, the order is placed as a limit order; otherwise it executes as a market order.
Notes:
- The request body uses
args(notarguments). - Argument shapes per action are defined as Zod schemas inside
@stakekit/chainsand exposed viaGET /v1/providersas JSON Schema (withlabel,placeholder, andoptionsRefUI hints). - For cross-chain funding, pass
args.fromToken({ network, address?, symbol? }). PerpsKit will compute the required swap/bridge/deposit transactions and prepend them totransactions[].
Response (ActionDto):
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"providerId": "hyperliquid",
"action": "open",
"status": "CREATED",
"summary": {
"type": "Open Position",
"asset": "ETH",
"direction": "short",
"orderType": "market",
"leverage": 20,
"size": "0.215",
"collateral": "43.00",
"fee": "0.0004",
"orderValue": 859.25
},
"signedMetadata": "01012b02010181d0010081d1040000000b240345544815...",
"transactions": [
{
"id": "11111111-2222-3333-4444-555555555555",
"network": "hyperliquid",
"chainId": "1337",
"type": "OPEN_POSITION",
"status": "CREATED",
"address": "0x1234...",
"signingFormat": "EIP712_TYPED_DATA",
"signablePayload": {
"domain": { "name": "Exchange", "version": "1", "chainId": 1337 },
"types": { "Agent": [/* ... */] },
"message": { "source": "a", "connectionId": "0x..." }
},
"rawPayload": {
"type": "order",
"orders": [{ "a": 4, "b": false, "p": "0", "s": "0.215", "r": false, "t": { "limit": { "tif": "Ioc" } } }],
"grouping": "na",
"nonce": 1733332000000
}
}
],
"createdAt": "2026-02-19T10:23:45.000Z",
"completedAt": null
}status follows ActionStatus: CREATED, PROCESSING, WAITING_FOR_NEXT, SUCCESS, FAILED, CANCELED, STALE.
Each transaction's status follows PerpTransactionStatus: CREATED, QUEUED, BROADCASTED, CONFIRMED, FAILED, NOT_FOUND.
List user actions (paginated)
GET /v1/actions?address=0x...&providerId=hyperliquid&limit=20&offset=0
Optional filters: status, statuses, type (action type), marketId. Ordered by most recent first. Each item is an ActionDto (same shape as above).
Get an action
GET /v1/actions/{actionId}
Use this to:
- Poll for action progress (
statuslifecycle:CREATED→PROCESSING→SUCCESS/FAILED/CANCELED/STALE) - Read the latest per-transaction states attached to the action
Returns the same ActionDto shape as POST /v1/actions.
Transactions
Submit a signed transaction
POST /v1/transactions/{transactionId}/submit
transactionId is the UUID returned inside ActionDto.transactions[].id.
Body — provide either signedPayload (we broadcast for you) or transactionHash (you've already broadcast it):
{
"signedPayload": "0x..."
}{
"transactionHash": "0xabc..."
}Response:
{
"transactionHash": "0x8a3fb2c1d4e5f67890abcdef12345678",
"link": "https://app.hyperliquid.xyz/explorer/tx/0x8a3fb2c1d4e5f67890abcdef12345678",
"status": "CONFIRMED",
"details": { "orderStatus": "filled", "fillPrice": 3975 }
}status follows PerpTransactionStatus: CREATED, QUEUED, BROADCASTED, CONFIRMED, FAILED, NOT_FOUND.
Typical usage:
POST /v1/actions— receiveActionDtowithtransactions[].- For each transaction in order, sign according to its
signingFormat(EIP712_TYPED_DATA,EVM_TRANSACTION, etc.) usingsignablePayload. POST /v1/transactions/{transactionId}/submitfor each.- Poll
GET /v1/actions/{actionId}until a final state.
Portfolio
Positions
POST /v1/positions
Request:
{ "address": "0x1234...", "providerId": "hyperliquid" }Response — array of PositionDto:
[
{
"marketId": "hyperliquid-eth-usdc",
"side": "short",
"size": "0.215",
"entryPrice": 4000,
"markPrice": 3975,
"leverage": 20,
"marginMode": "isolated",
"margin": 43,
"unrealizedPnl": 5.38,
"funding": -1.24,
"liquidationPrice": 4200,
"pendingActions": [
{
"type": "close",
"label": "Close Position",
"args": { "marketId": "hyperliquid-eth-usdc" }
}
]
}
]Orders
POST /v1/orders
Request:
{ "address": "0x1234...", "providerId": "hyperliquid" }Response — array of OrderDto:
[
{
"marketId": "hyperliquid-eth-usdc",
"side": "long",
"type": "limit",
"size": "0.5",
"limitPrice": 3900,
"leverage": 10,
"margin": 195.0,
"reduceOnly": false,
"createdAt": 1733332000,
"pendingActions": [
{
"type": "cancelOrder",
"label": "Cancel Order",
"args": { "orderId": "abc123" }
}
]
}
]Account balance
POST /v1/balances
Request:
{ "address": "0x1234...", "providerId": "hyperliquid" }Response (BalanceDto):
{
"providerId": "hyperliquid",
"collateral": {
"symbol": "USDC",
"network": "hyperliquid",
"decimals": 6
},
"accountValue": 1280.44,
"usedMargin": 320.13,
"availableBalance": 960.31,
"unrealizedPnl": 12.8
}Events & Activity
These endpoints surface async venue outcomes that aren't directly tied to a single user-initiated action — fills, liquidations, and TP/SL triggers — plus a unified chronological feed.
List perp events
GET /v1/events?address=0x...&providerId=hyperliquid&limit=20&offset=0
Optional filters: eventType / eventTypes (order_filled, liquidation, stop_loss_triggered, take_profit_triggered), marketId, perpActionId, providerOrderId, fromDate, toDate (ISO 8601).
Each item in items[] is an EventDto:
{
"id": "8c1e7a6b-4d2c-4f95-9c0e-2b9d9c8e1234",
"eventType": "order_filled",
"providerId": "hyperliquid",
"occurredAt": "2026-04-23T07:52:05.187Z",
"marketId": "hyperliquid-eth-usdc",
"perpActionId": "550e8400-e29b-41d4-a716-446655440000",
"providerOrderId": "394438950581",
"order": {
"orderId": "394438950581",
"marketId": "hyperliquid-eth-usdc",
"asset": "ETH",
"side": "buy",
"type": "market",
"originalSizeBase": "0.0063",
"remainingSizeBase": "0.0",
"limitPrice": 2395.2,
"timeInForce": "ioc",
"reduceOnly": false,
"isPositionLevel": false,
"clientOrderId": null,
"childOrderIds": [],
"createdAt": "2026-04-23T07:52:05.187Z"
}
}Get a single event
GET /v1/events/{eventId}
Returns the same EventDto shape.
Unified activity feed
GET /v1/activity?address=0x...&providerId=hyperliquid&limit=20&offset=0
Paginated, chronological mix of timeline events (occurredAt) and user actions (createdAt), newest first. Each item is either an EventDto or an ActionDto.
Example Flow
- Discover markets —
GET /v1/markets?providerId=hyperliquid - Open a position —
POST /v1/actions(action: "open") - Sign each transaction in
ActionDto.transactions[]using itssigningFormatandsignablePayload - Submit —
POST /v1/transactions/{transactionId}/submitfor each - Poll —
GET /v1/actions/{actionId}untilstatusisSUCCESS/FAILED - Read updated state —
POST /v1/positions,POST /v1/balances
Cross-Chain Orchestration
For providers and actions that support it (e.g. fund on Hyperliquid):
- Accepts arbitrary input assets via
args.fromToken - Computes required swap, bridge, or deposit operations
- Returns all unsigned transactions in the correct sequence inside
ActionDto.transactions[]
For Hyperliquid specifically, args.fundingMethod selects the route:
| Value | Behavior |
|---|---|
bridge2 | Direct Hyperliquid Bridge2 (Arbitrum USDC only) |
lifi | LiFi bridging (any token / network) |
| omitted | bridge2 for Arbitrum USDC, lifi otherwise |
args.skipApproval: true skips the ERC-20 approval transaction when the spender is already approved.
Some providers may have restricted funding support; consult GET /v1/providers/{providerId} for the actions and arguments each provider supports.
Integration Options
Direct API Integration
Endpoint summary:
GET /v1/providers
GET /v1/providers/{providerId}
GET /v1/markets
GET /v1/markets/{marketId}
GET /v1/markets/{marketId}/candles
POST /v1/positions
POST /v1/orders
POST /v1/balances
POST /v1/actions
GET /v1/actions
GET /v1/actions/{id}
POST /v1/transactions/{transactionId}/submit
GET /v1/events
GET /v1/events/{id}
GET /v1/activity
GET /v1/health
PerpsKit Widget Integration
The Yield.xyz Perps Widget is a drop-in perpetual futures trading frontend module you can embed in any application to provide users a self-custodial perps trading experience. It's built with React and designed to feel native inside wallets, exchanges, and fintech apps.
Under the hood, the widget uses the PerpsKit API to power the full lifecycle:
- Discovers available providers and supported actions
- Retrieves markets, live pricing data, candles, and the user's portfolio state
- Constructs intent-based actions (open/close/manage positions, update orders, leverage adjustments, TP/SL)
- Returns unsigned transaction payloads for the user to sign
- Submits signed transactions for broadcast and execution
- Streams async venue outcomes via the events / activity feed
Example deployments
Embedded Trading Widget — A lightweight widget that can be embedded directly inside an existing product interface (wallets, exchanges, fintech apps). Provides users with a seamless trading experience without leaving the host application.
Full Trading Terminal Dashboard — A full-featured trading dashboard built to mirror the Hyperliquid terminal experience. Includes richer position management, portfolio analytics, and a professional layout optimized for desktop traders.
Monetization via Builder Codes
PerpsKit supports builder code integration on supported perps protocols, allowing clients to earn a configurable facilitation fee per trade. The markup is transparently included in displayed fees and paid out via each protocol's builder-code mechanism.
Hyperliquid
- Fees can be set up to 0.1% (10 bp) on perps.
- Builder fees are authorized via the
approveBuilderFeeaction by the user on first interaction. - Once authorized, subsequent order actions sent on behalf of the user may include the builder parameter
{"b": address, "f": number}:b— fee recipient addressf— builder fee in tenths of basis points (e.g.f: 10= 1 bp = 0.01%)
How builder fees are calculated
Key facts:
- Charged per fill — applies to opens, closes, and partial executions.
- Leverage does not affect the fee. It is calculated on executed notional, not user margin.
- Collected in the collateral asset (USDC). Multiple fills are charged independently.
Example. A user deposits $1,000 in collateral and opens a perp at 10x leverage = $10,000 notional. With a 1 bp builder fee filled in a single fill:
$10,000 × 0.01% = $1.00
If the user later closes at $12,000 notional, an additional $1.20 builder fee is charged on the close. A partial close of $4,000 notional charges $0.40 for that fill.
