Laser Trade
POST /v1/trades/execute
Laser Trade executes a Pump bonding-curve or PumpSwap trade from a SolanaLaser-managed wallet. Your app sends the trade intent as JSON. SolanaLaser selects the managed wallet, builds the transaction, signs it server-side, sends it through Helius Sender, and returns the Solana signature.
You never send a private key to this endpoint. To choose a wallet, pass its
public key in wallet. If wallet is omitted, SolanaLaser uses the default
managed wallet for that API key.
Execution Model
The endpoint has one job: turn a trading intent into one submitted Solana transaction.
For a new Pump token, the trade routes through the Pump bonding curve. When the
bonding curve is complete, SolanaLaser derives the PumpSwap pool_v2 address
for the mint and routes through PumpSwap. You can also pass an explicit
PumpSwap pool when you already know which pool you want to trade against.
Before submission, SolanaLaser quotes the trade, applies your slippage settings, builds the Pump or PumpSwap instruction, adds priority-fee compute budget instructions, adds the Sender tip, signs with the managed wallet, and sends the transaction. By default it also simulates before sending and waits for confirmation after sending.
Request
This is the full request shape:
const response = await fetch("https://api.solanalaser.xyz/v1/trades/execute", {
method: "POST",
headers: {
"content-type": "application/json",
"x-api-key": "sl_your_key",
},
body: JSON.stringify({
action: "buy",
mint: "G282Uu6G6QV8VBrQgzi3DAwV5CvcMkTz9rDgpvBBpump",
amount: 0.01,
denominated_in_sol: true,
slippage: 5,
simulate: true,
confirm: true,
measure_timing: false,
}),
});
const trade = await response.json();
Request Fields
| Field | Type | Required | Meaning |
|---|---|---|---|
action | "buy" or "sell" | Yes | Trade direction. side is accepted as an alias. |
mint | string | Yes | Token mint address. token_mint is accepted as an alias. |
pool | string | No | Explicit PumpSwap pool address. If present, the trade routes to this pool. Keep mint equal to the pool base mint. |
amount | number or string | Yes | Amount to trade. Interpretation depends on action and denominated_in_sol. |
denominated_in_sol | boolean or boolean string | No | Defaults to true for buys and false for sells. denominatedInSol is accepted as an alias. |
slippage | number or string | No | Percentage slippage. Default is 2, maximum is 50, and up to 2 decimals are accepted. |
slippage_bps | integer | No | Backward-compatible basis-points field. 500 means 5%. Do not send it together with slippage. |
simulate | boolean | No | Defaults to true. If true, the transaction is simulated before submission. |
confirm | boolean | No | Defaults to true. If true, SolanaLaser waits for signature confirmation before responding. |
measure_timing | boolean | No | Defaults to false. If true, the response includes timing_ms. |
wallet | string | No | Managed wallet public key. If omitted, the default wallet is used. |
Amount Rules
amount is intentionally flexible, but it must match the type of trade.
For a SOL-denominated buy, amount is SOL. It can be a number or string and
can have up to 9 decimal places.
body: JSON.stringify({
action: "buy",
mint: "G282Uu6G6QV8VBrQgzi3DAwV5CvcMkTz9rDgpvBBpump",
amount: "0.01",
})
For a token-denominated buy, amount is token atomic units and
denominated_in_sol must be false. This asks for an exact token amount, and
SolanaLaser calculates the maximum SOL input after slippage. This works for
bonding-curve trades and PumpSwap trades.
body: JSON.stringify({
action: "buy",
mint: "G282Uu6G6QV8VBrQgzi3DAwV5CvcMkTz9rDgpvBBpump",
amount: "1000000000",
denominated_in_sol: false,
})
For a sell, amount is token atomic units by default. A SOL-denominated sell
is rejected because the chain instruction sells tokens, not a target SOL
amount.
body: JSON.stringify({
action: "sell",
mint: "G282Uu6G6QV8VBrQgzi3DAwV5CvcMkTz9rDgpvBBpump",
amount: "250000000",
})
For a percentage sell, use a string ending in %. SolanaLaser reads the
selected wallet's token account balance at execution time and converts the
percentage into token atomic units.
body: JSON.stringify({
action: "sell",
mint: "G282Uu6G6QV8VBrQgzi3DAwV5CvcMkTz9rDgpvBBpump",
amount: "50%",
})
Accepted percentage values are greater than 0% and up to 100%, with up to
2 decimal places.
Slippage
Use slippage for normal integrations. It is a percentage, so 5 means 5%.
body: JSON.stringify({
action: "buy",
mint: "G282Uu6G6QV8VBrQgzi3DAwV5CvcMkTz9rDgpvBBpump",
amount: 0.01,
slippage: 5,
})
You can also pass a string:
body: JSON.stringify({
action: "sell",
mint: "G282Uu6G6QV8VBrQgzi3DAwV5CvcMkTz9rDgpvBBpump",
amount: "100%",
slippage: "7.5",
})
slippage_bps exists for older clients. Prefer slippage because it matches
how traders think about slippage.
Routing
If pool is omitted, SolanaLaser auto-routes:
- Fetch the Pump bonding curve for
mint. - If the curve is not complete, trade on
bonding_curve. - If the curve is complete, derive the PumpSwap pool and trade on
pumpswap.
If pool is provided, SolanaLaser uses that PumpSwap pool directly. Only
SOL-quoted PumpSwap pools are supported.
The response always tells you where the trade actually went:
{
"venue": "bonding_curve",
"pool": null
}
or:
{
"venue": "pumpswap",
"pool": "PUMPSWAP_POOL_ADDRESS"
}
Response
Successful responses return the submitted signature plus the normalized trade details used by the server.
{
"wallet": "MANAGED_WALLET_PUBLIC_KEY",
"action": "buy",
"mint": "G282Uu6G6QV8VBrQgzi3DAwV5CvcMkTz9rDgpvBBpump",
"amount": "0.01",
"amount_units": 10000000,
"denominated_in_sol": true,
"signature": "5h6QxYvDk1vK7pR5n9wQeX9oYxL6WvX9PpVb7bZf9mHjV8u9A3f7nY6x2r4b1a2c3d4e5f6g7h8i9j",
"confirmed": true,
"confirmation_status": "confirmed",
"venue": "bonding_curve",
"pool": null,
"expected_output": "348912340",
"timing_ms": {
"wallet": 8,
"amount": 0,
"build": 430,
"sender": 210,
"confirmation": 820,
"database": 4,
"total": 1472
}
}
Response Fields
| Field | Meaning |
|---|---|
wallet | Managed wallet that signed the transaction and paid network fees, priority fee, and Sender tip. |
action | Normalized action, always buy or sell. |
mint | Token mint that was traded. For explicit PumpSwap pools, this is resolved from the pool base mint. |
amount | Original request amount as text. |
amount_units | Parsed base-unit amount. SOL buys return lamports. Token buys and sells return token atomic units. Percentage sells return the resolved token amount. |
denominated_in_sol | Final denomination used by the server after applying defaults. |
signature | Solana transaction signature returned after submission. |
confirmed | true only when confirmation polling observed the transaction. With confirm: false, this is false even if the transaction lands later. |
confirmation_status | RPC confirmation status such as processed, confirmed, or finalized. It is null when confirm: false. |
venue | Actual route used: bonding_curve or pumpswap. |
pool | PumpSwap pool address when venue is pumpswap; otherwise null. |
expected_output | Legacy response name for the slippage threshold used in the transaction. See the table below. |
timing_ms | Optional timings returned only with measure_timing: true. |
expected_output depends on the trade type:
| Trade | What expected_output means |
|---|---|
| Bonding-curve SOL buy | Minimum token atomic units out after slippage. |
| Bonding-curve exact-token buy | Maximum lamports in after slippage. |
| Bonding-curve sell | Minimum lamports out after slippage. |
| PumpSwap SOL buy | Maximum lamports threshold after slippage. |
| PumpSwap exact-token buy | Maximum lamports threshold after slippage. |
| PumpSwap sell | Minimum lamports out after slippage. |
Examples
Buy With SOL, Auto-Routed
Use this for the normal buy flow. The server decides whether the mint is still on the bonding curve or has moved to PumpSwap.
Request
const response = await fetch("https://api.solanalaser.xyz/v1/trades/execute", {
method: "POST",
headers: {
"content-type": "application/json",
"x-api-key": "sl_your_key",
},
body: JSON.stringify({
action: "buy",
mint: "G282Uu6G6QV8VBrQgzi3DAwV5CvcMkTz9rDgpvBBpump",
amount: 0.01,
slippage: 5,
}),
});
const trade = await response.json();
Response: 200
{
"wallet": "DEFAULT_WALLET_PUBLIC_KEY",
"action": "buy",
"mint": "G282Uu6G6QV8VBrQgzi3DAwV5CvcMkTz9rDgpvBBpump",
"amount": "0.01",
"amount_units": 10000000,
"denominated_in_sol": true,
"signature": "TRANSACTION_SIGNATURE",
"confirmed": true,
"confirmation_status": "confirmed",
"venue": "bonding_curve",
"pool": null,
"expected_output": "TOKEN_UNITS_THRESHOLD"
}
Sell 100 Percent From a Specific Wallet
Use this when your API key has multiple managed wallets and you want to sell a position from one non-default wallet.
Request
const response = await fetch("https://api.solanalaser.xyz/v1/trades/execute", {
method: "POST",
headers: {
"content-type": "application/json",
"x-api-key": "sl_your_key",
},
body: JSON.stringify({
action: "sell",
mint: "G282Uu6G6QV8VBrQgzi3DAwV5CvcMkTz9rDgpvBBpump",
amount: "100%",
wallet: "MANAGED_WALLET_PUBLIC_KEY",
slippage: 10,
}),
});
const trade = await response.json();
Response: 200
{
"wallet": "MANAGED_WALLET_PUBLIC_KEY",
"action": "sell",
"mint": "G282Uu6G6QV8VBrQgzi3DAwV5CvcMkTz9rDgpvBBpump",
"amount": "100%",
"amount_units": 4389123401,
"denominated_in_sol": false,
"signature": "TRANSACTION_SIGNATURE",
"confirmed": true,
"confirmation_status": "confirmed",
"venue": "pumpswap",
"pool": "PUMPSWAP_POOL_ADDRESS",
"expected_output": "MIN_LAMPORTS_OUT"
}
Submit Fast and Check Later
Set confirm: false when you want the API to return after submission instead
of waiting for RPC confirmation. Set simulate: false only when you accept
that a bad transaction can be submitted and fail on-chain.
Request
const startedAt = performance.now();
const response = await fetch("https://api.solanalaser.xyz/v1/trades/execute", {
method: "POST",
headers: {
"content-type": "application/json",
"x-api-key": "sl_your_key",
},
body: JSON.stringify({
action: "buy",
mint: "G282Uu6G6QV8VBrQgzi3DAwV5CvcMkTz9rDgpvBBpump",
amount: "0.005",
slippage: 8,
simulate: false,
confirm: false,
measure_timing: true,
}),
});
const trade = await response.json();
const elapsedMs = Math.round(performance.now() - startedAt);
console.log(trade.signature);
console.log(`HTTP round trip: ${elapsedMs}ms`);
console.log(trade.timing_ms);
Response: 200
{
"wallet": "DEFAULT_WALLET_PUBLIC_KEY",
"action": "buy",
"mint": "G282Uu6G6QV8VBrQgzi3DAwV5CvcMkTz9rDgpvBBpump",
"amount": "0.005",
"amount_units": 5000000,
"denominated_in_sol": true,
"signature": "TRANSACTION_SIGNATURE",
"confirmed": false,
"confirmation_status": null,
"venue": "bonding_curve",
"pool": null,
"expected_output": "TOKEN_UNITS_THRESHOLD",
"timing_ms": {
"wallet": 9,
"amount": 0,
"build": 280,
"sender": 190,
"confirmation": 0,
"database": 3,
"total": 482
}
}
Use an Explicit PumpSwap Pool
Use pool when your system already has a PumpSwap pool address and you do not
want auto-routing. The request still includes mint, and it should match the
pool base mint.
Request
const response = await fetch("https://api.solanalaser.xyz/v1/trades/execute", {
method: "POST",
headers: {
"content-type": "application/json",
"x-api-key": "sl_your_key",
},
body: JSON.stringify({
action: "buy",
mint: "G282Uu6G6QV8VBrQgzi3DAwV5CvcMkTz9rDgpvBBpump",
pool: "PUMPSWAP_POOL_ADDRESS",
amount: "0.01",
slippage: 5,
}),
});
const trade = await response.json();
Response: 200
{
"wallet": "DEFAULT_WALLET_PUBLIC_KEY",
"action": "buy",
"mint": "PUMPSWAP_POOL_BASE_MINT",
"amount": "0.01",
"amount_units": 10000000,
"denominated_in_sol": true,
"signature": "TRANSACTION_SIGNATURE",
"confirmed": true,
"confirmation_status": "confirmed",
"venue": "pumpswap",
"pool": "PUMPSWAP_POOL_ADDRESS",
"expected_output": "MAX_LAMPORTS_THRESHOLD"
}
Buy an Exact Token Amount
This asks for an exact token amount and lets SolanaLaser calculate the maximum SOL input after slippage. It works on the bonding curve and on PumpSwap.
Request
const response = await fetch("https://api.solanalaser.xyz/v1/trades/execute", {
method: "POST",
headers: {
"content-type": "application/json",
"x-api-key": "sl_your_key",
},
body: JSON.stringify({
action: "buy",
mint: "G282Uu6G6QV8VBrQgzi3DAwV5CvcMkTz9rDgpvBBpump",
amount: "1000000000",
denominated_in_sol: false,
slippage: 5,
}),
});
const trade = await response.json();
Response: 200
{
"wallet": "DEFAULT_WALLET_PUBLIC_KEY",
"action": "buy",
"mint": "G282Uu6G6QV8VBrQgzi3DAwV5CvcMkTz9rDgpvBBpump",
"amount": "1000000000",
"amount_units": 1000000000,
"denominated_in_sol": false,
"signature": "TRANSACTION_SIGNATURE",
"confirmed": true,
"confirmation_status": "confirmed",
"venue": "bonding_curve",
"pool": null,
"expected_output": "MAX_LAMPORTS_IN"
}
Common Errors
| HTTP | Detail | Meaning |
|---|---|---|
400 | action must be buy or sell | action was not buy or sell. |
400 | amount must be a number or string | amount was not a JSON number or string. |
400 | SOL amounts cannot have more than 9 decimal places | SOL values map to lamports, so only 9 decimals are valid. |
400 | sell amount must be denominated in token units | Sells cannot use denominated_in_sol: true. |
400 | use either slippage or slippage_bps, not both | Send one slippage format. Prefer slippage. |
400 | trade simulation failed | The transaction failed pre-submit simulation and was not sent. |
502 | Jito, RPC, or Sender detail | Upstream submission, RPC, or confirmation infrastructure failed. Check the signature if one was returned. |
Operational Notes
confirm: trueis safer for normal integrations because the response tells you whether RPC observed the transaction.confirm: falseis faster, but the API cannot tell you whether the transaction landed. Store the returned signature and check it later.simulate: truecatches many bad trades before submission, but it adds RPC latency.simulate: falseskips that protection.measure_timing: trueis for diagnostics. It reports server-side timing for wallet lookup, amount parsing, transaction build, Sender submission, confirmation, database recording, and total request time.- A confirmation timeout does not prove the transaction failed. It means the API stopped waiting. Check the returned signature when available.