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

# Actions

> Every action that HedgeClient.execute runs, with its request body, notes, an example, and the API key scope it needs.

`hedge.execute(request, signer, options?)` runs one manager action to a terminal [`Outcome`](/sdk/overview#read-the-outcome). `request` is an `ActionRequest`: an object whose `action` field names a builder and whose other fields are that builder's body. TypeScript checks the body against the action.

`execute` follows batches and `next` continuations on its own. See [Execute and safety](/sdk/safety) for how.

The examples below assume `hedge` is a client, `signer` is a `TransactionSigner`, and `vault`, `position`, and similar names are address strings.

## Request bodies

`payer` is never part of a body. The API sets it from the key. Amounts are base-unit strings (`BaseUnitString`). `DecimalString` fields, such as a Phoenix `size`, are decimals like `"0.5"` and are not base units.

### Jupiter

| Action | Body besides `action` | Notes |
| - | - | - |
| `jupiter/swap` | `vault, sourceMint, destinationMint, amount, slippageBps` | `amount` is in source-mint base units. |
| `jupiter/sweep` | `vault, mint, slippageBps` | One transaction. It sells the vault's whole `mint` balance to the deposit mint, then closes that mint's Jupiter strategy. The API answers 409 while an open DLMM position or limit order uses `mint`. |
| `jupiter/initialize` | `vault, targetMint` | Opens the strategy the vault needs to hold `targetMint`. |

```ts theme={null}
const outcome = await hedge.execute(
  { action: "jupiter/swap", vault, sourceMint, destinationMint, amount: parseUnits("1.5", 6), slippageBps: 50 },
  signer,
);
```

```ts theme={null}
await hedge.execute({ action: "jupiter/initialize", vault, targetMint: mint }, signer);
await hedge.execute({ action: "jupiter/sweep", vault, mint, slippageBps: 100 }, signer);
```

### Meteora DLMM

| Action | Body besides `action` | Notes |
| - | - | - |
| `dlmm/initialize` | `vault, lbPair`, and either `width` or `lowerBinId` + `upperBinId` | Creates an empty position and any missing pair-token Jupiter strategies. `width` is 1 to 70 bins centred on the active bin. `upperBinId` is exclusive and at most 70 bins above `lowerBinId`. The new address comes back as `created.position`. |
| `dlmm/open` | `vault, lbPair, lowerBinId, upperBinId, amountX, amountY, shape, maxActiveBinSlippage` | `upperBinId` is exclusive. A range wider than 70 bins continues through `dlmm/extend`. |
| `dlmm/add` | `vault, position, amountX, amountY, shape, maxActiveBinSlippage`, optional `lowerBinId` + `upperBinId` | The optional range has both ends inclusive and must be given together, inside the position. With a range, `dlmm/add` adds only to those bins. |
| `dlmm/remove` | `vault, position, bpsToRemove`, optional `cursorBinId`, optional `lowerBinId` + `upperBinId` | Range as in `dlmm/add`. Removes `bpsToRemove` only from those bins. |
| `dlmm/flip` | `vault, position, lowerBinId, upperBinId, activeBinId, maxActiveBinSlippage` | One atomic transaction. It removes all liquidity from the bins (both ends inclusive) and re-adds that token there as Bid-Ask. The range must lie strictly above (token X) or below (token Y) `activeBinId`. It does not claim fees. |
| `dlmm/claim-fee` | `vault, position`, optional `cursorBinId` | |
| `dlmm/zap-out` | `vault, position, slippageBps`, optional `cursorBinId` | When eligible, the last transaction continues to `jupiter/sweep` for the leftover non-deposit token. |
| `dlmm/close` | `vault, position` | Removes everything, claims fees, and closes the position and its strategy. |
| `strategy/close` | `vault, strategy` | Closes an empty strategy. |

`shape` is `"spot"`, `"curve"`, or `"bidAsk"`. `maxActiveBinSlippage` is the number of bins the active price may move between build and landing before the transaction fails. `amountX` and `amountY` are in the pool's token X and token Y base units.

To open a position, read the pool first and choose a range around its active bin:

```ts theme={null}
const pool = await hedge.getPool(vault, lbPair);
const outcome = await hedge.execute(
  {
    action: "dlmm/open",
    vault,
    lbPair,
    lowerBinId: pool.activeBinId - 10,
    upperBinId: pool.activeBinId + 11, // exclusive
    amountX: "0",
    amountY: "5000000",
    shape: "spot",
    maxActiveBinSlippage: 10,
  },
  signer,
);
```

Create an empty position and read its address:

```ts theme={null}
const outcome = await hedge.execute({ action: "dlmm/initialize", vault, lbPair, width: 21 }, signer);
const position = outcome.kind === "confirmed" ? outcome.created?.position : undefined;
```

Add, remove, claim, zap out, and close:

```ts theme={null}
await hedge.execute({ action: "dlmm/add", vault, position, amountX: "0", amountY: "1000000", shape: "curve", maxActiveBinSlippage: 10 }, signer);
await hedge.execute({ action: "dlmm/add", vault, position, amountX: "0", amountY: "1000000", shape: "spot", maxActiveBinSlippage: 10, lowerBinId: -5, upperBinId: 5 }, signer);
await hedge.execute({ action: "dlmm/remove", vault, position, bpsToRemove: 5000 }, signer);
await hedge.execute({ action: "dlmm/claim-fee", vault, position }, signer);
await hedge.execute({ action: "dlmm/zap-out", vault, position, slippageBps: 100 }, signer);
await hedge.execute({ action: "dlmm/close", vault, position }, signer);
```

Build a `dlmm/flip` range with `flipSide` and `flipRange` so it lies on one side of the active bin. The active bin holds both tokens, so a flip never includes it.

```ts theme={null}
const strategy = (await hedge.getStrategies(vault)).find((s) => s.type === "dlmm" && s.position === position);
if (strategy?.type === "dlmm" && strategy.lowerBinId !== undefined && strategy.upperBinId !== undefined && strategy.activeBinId !== undefined) {
  const holdings = await hedge.getHoldings(vault);
  const side = flipSide(strategy.tokenX.mint, holdings.depositToken.mint);
  const range = flipRange({ lowerBinId: strategy.lowerBinId, upperBinId: strategy.upperBinId }, strategy.activeBinId, side);
  if (range) {
    await hedge.execute({ action: "dlmm/flip", vault, position, ...range, activeBinId: strategy.activeBinId, maxActiveBinSlippage: 10 }, signer);
  }
}
```

Close an empty strategy:

```ts theme={null}
await hedge.execute({ action: "strategy/close", vault, strategy: strategyAddress }, signer);
```

### Phoenix perpetuals

| Action | Body besides `action` | Notes |
| - | - | - |
| `phoenix/initialize` | `vault` | Records the vault's Phoenix strategy. Then call `onboardPhoenix`. The vault's deposit mint must be USDC. |
| `phoenix/deposit` | `vault, amount` | Moves idle USDC into Phoenix collateral. `amount` is in USDC base units. |
| `phoenix/withdraw` | `vault, amount` | Withdraws Phoenix collateral to the vault. `amount` is in USDC base units. A queued withdrawal needs `phoenix/sweep` later. |
| `phoenix/order` | `vault, symbol, side, size, reduceOnly, order` | `symbol` is a Phoenix market such as `"SOL"`. `side` is `"long"` or `"short"`. `size` is a decimal of the base asset, such as `"0.5"`. `order` is `{ type: "market", slippageBps }` with `slippageBps` from 1 to 2000, or `{ type: "limit", price, postOnly }` with `price` as a USD decimal. |
| `phoenix/cancel` | `vault, symbol, orders` | `orders` is `"all"` or 1 to 20 `{ priceInTicks, orderSequenceNumber }` entries from `getPhoenix(vault).openOrders`. |
| `phoenix/sweep` | `vault` | Unwraps tokens a queued Phoenix withdrawal delivered into USDC. |

Phoenix must co-sign the onboarding transaction, so onboarding is its own method and does not go through `execute`:

```ts theme={null}
await hedge.execute({ action: "phoenix/initialize", vault }, signer);
const onboarded = await hedge.onboardPhoenix(vault, signer);
```

`onboardPhoenix(vault, signer, options?)` builds the transaction, inspects it against a separate, narrower policy, signs it as fee payer, and submits it to the onboarding submit endpoint, where Phoenix adds its signature and sends it. It then polls the transaction status like `execute` and returns the same `Outcome`. It never resubmits. See [Execute and safety](/sdk/safety#phoenix-onboarding-policy).

Deposit, trade, and withdraw:

```ts theme={null}
await hedge.execute({ action: "phoenix/deposit", vault, amount: "10000000" }, signer);
await hedge.execute(
  { action: "phoenix/order", vault, symbol: "SOL", side: "long", size: "0.5", reduceOnly: false, order: { type: "market", slippageBps: 100 } },
  signer,
);
await hedge.execute(
  { action: "phoenix/order", vault, symbol: "SOL", side: "short", size: "0.5", reduceOnly: false, order: { type: "limit", price: "150.25", postOnly: true } },
  signer,
);
await hedge.execute({ action: "phoenix/cancel", vault, symbol: "SOL", orders: "all" }, signer);
await hedge.execute({ action: "phoenix/withdraw", vault, amount: "5000000" }, signer);
await hedge.execute({ action: "phoenix/sweep", vault }, signer);
```

To cancel specific orders, copy `priceInTicks` and `orderSequenceNumber` from `getPhoenix`. `openOrders` is `null` when Phoenix's API is down.

```ts theme={null}
const { openOrders } = await hedge.getPhoenix(vault);
const first = openOrders?.[0];
if (first) {
  await hedge.execute(
    { action: "phoenix/cancel", vault, symbol: first.symbol, orders: [{ priceInTicks: first.priceInTicks, orderSequenceNumber: first.orderSequenceNumber }] },
    signer,
  );
}
```

### Vault administration

| Action | Body besides `action` | Notes |
| - | - | - |
| `vault/initialize` | `name, depositMint, performanceFeeBps, managementFeeBps, depositCap, minDeposit, minWithdrawalShares` | Takes no `vault`. Needs a key that is not limited to specific vaults. A confirmed outcome carries the new address as `created.vault`. |
| `vault/update` | `vault` and at least one of `performanceFeeBps, managementFeeBps, depositCap, minDeposit, minWithdrawalShares, status, depositPaused, withdrawalPaused` | Changes only the fields you give. |
| `vault/claim-fee` | `vault` | Mints the accrued manager fee shares to the manager. |
| `vault/close` | `vault` | Closes the vault. |

`name` is at most 32 UTF-8 bytes. Both fee fields are basis points from 0 to 10000. `depositCap` and `minDeposit` are in deposit-mint base units. `minWithdrawalShares` is in share base units. `status` is `"normal"`, `"paused"`, or `"reduceOnly"`.

```ts theme={null}
const created = await hedge.execute(
  {
    action: "vault/initialize",
    name: "My vault",
    depositMint: usdcMint,
    performanceFeeBps: 1000,
    managementFeeBps: 100,
    depositCap: "1000000000000",
    minDeposit: "1000000",
    minWithdrawalShares: "1000000",
  },
  signer,
);
if (created.kind === "confirmed") console.log(created.created?.vault);

await hedge.execute({ action: "vault/update", vault, depositPaused: true }, signer);
await hedge.execute({ action: "vault/claim-fee", vault }, signer);
await hedge.execute({ action: "vault/close", vault }, signer);
```

## Key scopes

Each API key lists the actions it may run. Every write needs the `send` scope plus the action's own name. The API rejects a request when the key lacks one of them.

| To do this | The key needs |
| - | - |
| Any read | `read` |
| Run a builder with `execute` | `send` and the action's own name, such as `phoenix/order` or `dlmm/flip` |
| Follow a `next` continuation | The continuation's name too: `dlmm/extend`, `dlmm/add-range`, `dlmm/zap-out/swap`, or `jupiter/sweep` |
| `onboardPhoenix` | `send` and `phoenix/onboard` |
| `vault/initialize` | `send` and `vault/initialize`, on a key not limited to specific vaults |

So `dlmm/open` on a range wider than 70 bins needs `dlmm/open` and `dlmm/extend`. `dlmm/zap-out` needs `dlmm/zap-out`, `dlmm/zap-out/swap`, and `jupiter/sweep`. `dlmm/add` can need `dlmm/add-range`.

<Note>
  The SDK cannot check scopes before it builds. A missing scope shows up as a `failed` outcome with the API's error code. See the [API reference](/api-reference/introduction) for the authentication and error contract.
</Note>


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