jupiter-perps-api-sdk
v0.1.0
Published
V2 TypeScript client for the Jupiter Perpetuals API.
Readme
Jupiter Perps API SDK
V2-only TypeScript client for the Jupiter Perpetuals API.
This package is standalone and dependency-light. It depends on @solana/web3.js,
always sends x-perps-api-version: v2, and does not import server-side route
schemas or internal Jupiter code.
Install
npm install jupiter-perps-api-sdkimport { createPerpsClient } from 'jupiter-perps-api-sdk';
const perps = createPerpsClient();The default baseUrl is https://perps-api.jup.ag/v1. You can pass a custom
baseUrl, including a /v1 URL with the v2 header or a /v2 URL.
Quickstart
Read endpoints do not require wallet signing.
import { MINTS, createPerpsClient, formatRawUsd } from 'jupiter-perps-api-sdk';
const perps = createPerpsClient();
const positions = await perps.positions.get({
walletAddress: '<wallet-address>',
});
const solStats = await perps.markets.getStats({
mint: MINTS.SOL,
});
const leaderboard = await perps.leaderboard.getCompetitionLeaderboard({
walletAddresses: ['<wallet-address>'],
startTimestamp: Math.floor(Date.now() / 1000) - 3600,
});
console.log(positions.dataList);
console.log(solStats.price);
console.log(formatRawUsd(leaderboard.dataList[0]?.livePnlUsd ?? '0'));Client Config
const perps = createPerpsClient({
baseUrl: 'https://perps-api.jup.ag/v1',
fetch: customFetch,
headers: {
'x-client-name': 'my-app',
},
});Options:
baseUrl: API base URL. Defaults tohttps://perps-api.jup.ag/v1.fetch: custom fetch implementation for runtimes that do not exposeglobalThis.fetch.headers: extra headers to send with every request.
The SDK always overwrites x-perps-api-version with v2.
API Surface
await perps.positions.get({ walletAddress });
await perps.positions.getTrades({ walletAddress });
await perps.positions.getCollateralLimits({ inputMint: MINTS.USDC, positionPubkey });
await perps.markets.getStats({ mint: MINTS.SOL });
await perps.markets.getPoolInfo({ mint: MINTS.SOL });
await perps.jlp.getInfo();
await perps.leaderboard.getCompetitionLeaderboard({
walletAddresses,
startTimestamp,
});
await perps.trading.increasePosition(input);
await perps.trading.decreasePosition(input);
await perps.trading.closeAllPositions({ walletAddress });
await perps.trading.createLimitOrder(input);
await perps.trading.updateLimitOrder(input);
await perps.trading.getLimitOrders({ walletAddress });
await perps.trading.closeLimitOrder({ positionRequestPubkey });
await perps.trading.createTpsl(input);
await perps.trading.updateTpsl(input);
await perps.trading.cancelTpsl({ positionRequestPubkey });
await perps.trading.executeTransaction({ action, serializedTxBase64 });
await perps.trading.executeSignedTransaction({ action, transaction });
await perps.trading.signAndExecute({ action, serializedTxBase64, wallet });Lower-level transaction helpers are also exported:
import {
deserializeTransaction,
serializeTransaction,
signAndExecuteTransaction,
signTransaction,
} from 'jupiter-perps-api-sdk';Trading Flow
Trading endpoints return a base64 serialized Solana transaction. Your app signs
the transaction with the user's wallet, then submits the signed transaction to
/transaction/execute.
import { createPerpsClient } from 'jupiter-perps-api-sdk';
const perps = createPerpsClient();
const increase = await perps.trading.increasePosition({
walletAddress: '<wallet-address>',
asset: 'SOL',
inputToken: 'USDC',
inputTokenAmount: '10000000',
side: 'long',
leverage: '5',
maxSlippageBps: '100',
});
if (!increase.serializedTxBase64) {
throw new Error('No transaction returned');
}
const transaction = perps.transactions.deserialize(increase.serializedTxBase64);
const signed = await wallet.signTransaction(transaction);
const result = await perps.transactions.executeSigned({
action: 'increase-position',
transaction: signed,
});
console.log(result.txid);You can use signAndExecute when your wallet object implements
signTransaction.
const result = await perps.trading.signAndExecute({
action: 'increase-position',
serializedTxBase64: increase.serializedTxBase64,
wallet,
});Amounts and Units
Most numeric request fields are strings because the API works with integer raw amounts and decimal-safe values.
- USD values are raw integers scaled by
1e6unless a field explicitly says it is formatted. - Token input amounts are raw token units. For example,
10000000USDC is 10 USDC because USDC has 6 decimals. - Slippage is in basis points. For example,
100is 1%. - Leverage is passed as a string, such as
'5'.
Formatting helpers:
import {
formatRawUsd,
rawAmountToDecimalString,
rawUsdToNumber,
} from 'jupiter-perps-api-sdk';
formatRawUsd('123456789'); // "$123.46"
rawAmountToDecimalString('10000000', 6); // "10"
rawUsdToNumber('123456789'); // 123.456789Errors
Non-2xx API responses throw PerpsApiError.
import { PerpsApiError } from 'jupiter-perps-api-sdk';
try {
await perps.positions.get({ walletAddress: '<wallet-address>' });
} catch (error) {
if (error instanceof PerpsApiError) {
console.error(error.status, error.code, error.message, error.metadata);
}
throw error;
}Examples
Example scripts live in the GitHub repository under examples/:
examples/leaderboard.tsexamples/open-position.tsexamples/close-position.ts
Run them with Bun or another TypeScript runner:
WALLETS=<wallet-address> bun examples/leaderboard.ts
WALLET_ADDRESS=<wallet-address> bun examples/open-position.ts
POSITION_PUBKEY=<position-pubkey> bun examples/close-position.tsSet PERPS_API_URL only if you need to point at a different API base URL.
Scope
This SDK intentionally includes the public v2 read, leaderboard, trading, transaction, formatting, and polling helpers. It intentionally excludes with-fee endpoints and internal or legacy server endpoints.
