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

# Apex Tips

> Every Apex transaction carries one SystemProgram transfer to a published tip account. Learn the tip rule, the 0.001 SOL standard floor, and how tips are used.

## The Tip Rule

Every transaction you send through Apex must contain **exactly one** tip that meets all of these conditions:

<Steps>
  <Step title="A SystemProgram transfer">
    The tip is a plain `SystemProgram::Transfer` instruction to one of the published Apex tip accounts.
  </Step>

  <Step title="Top level">
    The transfer is a top-level instruction of the transaction. A transfer made from inside your program through CPI does not count.
  </Step>

  <Step title="Funded by a signer">
    The account that pays the tip signs the transaction. It does not have to be the fee payer.
  </Step>

  <Step title="Tip account in the static keys">
    The tip account appears in the transaction's static account keys. Do not load it through an address lookup table.
  </Step>

  <Step title="At or above your tier's floor">
    The standard tier floor is **0.001 SOL (1,000,000 lamports)**. Your key's tier may set a different floor.
  </Step>
</Steps>

A transaction with no tip, more than one tip, or a tip below your floor is rejected before it is sent anywhere. The rejection tells you which rule failed, and a below-floor message states your floor. See [Errors and rate limits](/apex/errors-and-rate-limits).

## You Only Pay When You Land

The tip is inside your transaction. If the transaction does not land, the transfer never executes and you pay nothing. A rejected, expired, or dropped transaction costs you no tip.

## Get the Tip Accounts

Call JSON-RPC `getTipAccounts` on any Apex endpoint. It needs no API key.

<CodeGroup>
  ```bash cURL theme={null}
  curl -s http://fra.apex.orbitflare.com \
    -H "Content-Type: application/json" \
    -d '{"jsonrpc":"2.0","id":1,"method":"getTipAccounts","params":[]}'
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch("http://fra.apex.orbitflare.com", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "getTipAccounts", params: [] }),
  });
  const { result: tipAccounts } = await res.json();
  const tipAccount = tipAccounts[Math.floor(Math.random() * tipAccounts.length)];
  console.log(tipAccount);
  ```

  ```python Python theme={null}
  import random
  import requests

  res = requests.post(
      "http://fra.apex.orbitflare.com",
      json={"jsonrpc": "2.0", "id": 1, "method": "getTipAccounts", "params": []},
      timeout=5,
  )
  tip_accounts = res.json()["result"]
  tip_account = random.choice(tip_accounts)
  print(tip_account)
  ```

  ```rust Rust theme={null}
  use apex_sender_client::rpc::RpcClient;
  use apex_sender_client::{tip, Region};

  #[tokio::main]
  async fn main() -> Result<(), Box<dyn std::error::Error>> {
      let api_key = std::env::var("APEX_API_KEY")?;
      let tip_accounts = RpcClient::new(Region::Frankfurt, &api_key)
          .get_tip_accounts()
          .await?;
      let tip_account = tip::pick_tip_account(&tip_accounts).ok_or("no tip accounts")?;
      println!("{tip_account}");
      Ok(())
  }
  ```
</CodeGroup>

The response is an array of base58 addresses:

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": ["APeX2oLtjYehgTMUCA971L8htM7tGNqsXHDz5NrivhhX", "APeXAKT6spXSmU3uRv2MoEgQ7ckhAS4nexTgaxwLEfJ9", "..."]
}
```

Fetch the list at startup and cache it. Pick an account **at random for each transaction**. Spreading tips across the accounts keeps your transactions from contending for a write lock on the same account.

### The Published Accounts

The mainnet tip accounts, all vaults of the tip program `9ig7pd4gqe2m16ACGPbPo4HfMGD3ba38poDhXEayx7EF`. `getTipAccounts` is the authoritative list: it is what the endpoint accepts, and it is where a change would appear first. Every address starts with `APeX`, so a substituted account is easy to spot.

```
APeX2oLtjYehgTMUCA971L8htM7tGNqsXHDz5NrivhhX
APeXAKT6spXSmU3uRv2MoEgQ7ckhAS4nexTgaxwLEfJ9
APeXB4mu1X7BSjwyPtiNUnKyhvc4wrq5SKEdmnPKWR95
APeXJTSGoxLWmwb9o1tiiEL5RXVUakazYgjLmZdDc2Ef
APeXUUaKFfPXjPxKHEdwCsJ4BfTuGg4qnVQyJE9K37PU
APeXVWXKDRAAujckMjmMsV61a4DQiXa98MPUAkL46sim
APeXW6PKFZRDz7WXBBybBMcoJaQo97UtLa5TAQnchNBY
APeXZuKaKuqouyfU8fFL1woeWvSEVFkY4EMrmkvbfhhD
APeXbYdbmrYWsastf6GurexGe3dwnuWKLD2mcsDoEuBU
APeXn29deoxpsZz6r7n63Ymmv2skBr3WhKYLB1mB2fR7
```

## Add the Tip Instruction

<CodeGroup>
  ```javascript JavaScript theme={null}
  import { PublicKey, SystemProgram } from "@solana/web3.js";

  const tipInstruction = SystemProgram.transfer({
    fromPubkey: payer.publicKey,
    toPubkey: new PublicKey(tipAccount),
    lamports: 1_000_000, // 0.001 SOL, the standard tier floor
  });
  ```

  ```python Python theme={null}
  from solders.pubkey import Pubkey
  from solders.system_program import TransferParams, transfer

  tip_instruction = transfer(TransferParams(
      from_pubkey=payer.pubkey(),
      to_pubkey=Pubkey.from_string(tip_account),
      lamports=1_000_000,  # 0.001 SOL, the standard tier floor
  ))
  ```

  ```rust Rust theme={null}
  use apex_sender_client::{tip_instruction, MIN_TIP_LAMPORTS};

  let tip_ix = tip_instruction(&payer.pubkey(), &tip_account, MIN_TIP_LAMPORTS);
  ```
</CodeGroup>

Add it to the instruction list of the transaction alongside your own instructions. The [Quickstart](/apex/quickstart) shows complete programs.

## Where the Tip Goes

The tip accounts are vaults of OrbitFlare's on-chain tip program. Only the program can debit them.

When the **Jito path** is the one that lands your transaction, the tip minus the 5,000 lamport base fee is bid to Jito in the same bundle as your transaction. You do not add a separate Jito tip. One Apex tip covers all three paths.

| Your tip           | Base fee       | Jito bid when the Jito path wins |
| ------------------ | -------------- | -------------------------------- |
| 1,000,000 lamports | 5,000 lamports | 995,000 lamports                 |
| 5,000,000 lamports | 5,000 lamports | 4,995,000 lamports               |

A larger tip therefore means a larger bid in the Jito auction. It costs you the same amount whichever path lands the transaction, because the tip is the transfer you signed.

## Tip and Priority Fee Are Different Things

Apex gets your transaction to the leader. The leader's scheduler still orders transactions by **priority fee**, which is your compute unit price multiplied by your compute unit limit. Set both on every transaction:

* A **compute unit limit** close to what the transaction really uses. An oversized limit lowers your effective priority per unit and wastes block space.
* A **compute unit price** that fits the current market for the accounts you touch.

<CodeGroup>
  ```javascript JavaScript theme={null}
  import { ComputeBudgetProgram } from "@solana/web3.js";

  const computeBudget = [
    ComputeBudgetProgram.setComputeUnitLimit({ units: 100_000 }),
    ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 10_000 }),
  ];
  ```

  ```python Python theme={null}
  from solders.compute_budget import set_compute_unit_limit, set_compute_unit_price

  compute_budget = [
      set_compute_unit_limit(100_000),
      set_compute_unit_price(10_000),  # micro-lamports per compute unit
  ]
  ```

  ```rust Rust theme={null}
  use solana_compute_budget_interface::ComputeBudgetInstruction;

  let compute_budget = [
      ComputeBudgetInstruction::set_compute_unit_limit(100_000),
      ComputeBudgetInstruction::set_compute_unit_price(10_000), // micro-lamports per compute unit
  ];
  ```
</CodeGroup>

These instructions are for legacy and v0 transactions. A [transaction v1](/apex/transaction-v1) sets its compute budget in the message's `TransactionConfig` instead.

See [Best practices](/apex/best-practices#size-the-tip-to-the-trade) for guidance on sizing both.
