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

# Setup

> Set up the Vanish Core client, request signing, and the helpers used by every flow.

Every Vanish flow shares the same foundation: an authenticated HTTP client, a signing helper, and one pair of helpers for broadcasting and committing. Set these up once and both the trading and lending walkthroughs build straight on top of them.

<Info>
  You'll need an API key to follow this guide. Contact the Vanish team via [Discord](https://discord.gg/vanishtrade) to get one during onboarding.
</Info>

***

## Environment Setup

<CodeGroup>
  ```bash TypeScript theme={null}
  npm install @solana/web3.js tweetnacl
  ```

  ```toml Rust theme={null}
  [dependencies]
  solana-sdk    = "1.18"
  solana-client = "1.18"
  base64        = "0.22"
  bincode       = "1"
  reqwest       = { version = "0.12", features = ["json"] }
  serde_json    = "1"
  tokio         = { version = "1", features = ["full"] }
  chrono        = "0.4"
  ```
</CodeGroup>

Before starting, make sure you have the following available:

* **Vanish API key** - provisioned during onboarding
* **Solana RPC endpoint** - any standard Solana RPC URL
* **User keypair** - the Ed25519 keypair for the wallet you're trading from
* **Solana balance** - enough SOL to cover the deposit and transaction fees

Store sensitive values - your API key and keypair - in environment variables. Never expose them in source code or client-side bundles.

***

## Set Up the Client

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { Connection, Keypair } from '@solana/web3.js';

  const VANISH_URL  = 'https://core-api.vanish.trade';
  const connection  = new Connection(process.env.SOLANA_RPC_URL!);
  const userKeypair = Keypair.fromSecretKey(
    Uint8Array.from(JSON.parse(process.env.SOLANA_KEYPAIR!))
  );

  async function vanish(path: string, options?: RequestInit) {
    const res = await fetch(`${VANISH_URL}${path}`, {
      ...options,
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': process.env.VANISH_API_KEY!,
        ...options?.headers,
      },
    });
    if (!res.ok) {
      throw new Error(`Vanish ${res.status}: ${await res.text()}`);
    }
    return res.json();
  }
  ```

  ```rust Rust theme={null}
  use reqwest::Client;
  use solana_client::rpc_client::RpcClient;
  use solana_sdk::signature::Keypair;
  use serde_json::Value;

  const VANISH_URL: &str = "https://core-api.vanish.trade";

  // initialise once and pass through your application
  let client   = Client::new();
  let rpc      = RpcClient::new(std::env::var("SOLANA_RPC_URL").unwrap());
  let api_key  = std::env::var("VANISH_API_KEY").unwrap();
  let keypair_bytes: Vec<u8> = serde_json::from_str(
      &std::env::var("SOLANA_KEYPAIR").unwrap()
  ).unwrap();
  let user_keypair = Keypair::from_bytes(&keypair_bytes).unwrap();

  async fn vanish(
      client: &Client,
      api_key: &str,
      path: &str,
      body: Option<&Value>,
  ) -> Result<Value, reqwest::Error> {
      let mut req = client
          .request(
              if body.is_some() { reqwest::Method::POST } else { reqwest::Method::GET },
              format!("{}{}", VANISH_URL, path),
          )
          .header("x-api-key", api_key)
          .header("Content-Type", "application/json");

      if let Some(b) = body {
          req = req.json(b);
      }

      req.send().await?.json().await
  }
  ```
</CodeGroup>

***

## Sign Requests

Most endpoints require a signed message proving ownership of `user_address`. Every message shares the same prefix and differs only in its `Details:` line - see [Signing Requests](/guide/integration/signing#signing-requests) for the line each endpoint expects.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import * as nacl from 'tweetnacl';

  const TOS = "By signing, I hereby agree to Vanish's Terms of Service and agree to be bound by them (docs.vanish.trade/legal/TOS)";

  function signMessage(details: string, keypair: Keypair): string {
    const message = [TOS, "", `Details: ${details}`].join('\n');
    const sig = nacl.sign.detached(new TextEncoder().encode(message), keypair.secretKey);
    return Buffer.from(sig).toString('base64');
  }
  ```

  ```rust Rust theme={null}
  use solana_sdk::signature::Signer;
  use base64::{engine::general_purpose, Engine as _};

  const TOS: &str = "By signing, I hereby agree to Vanish's Terms of Service and agree to be bound by them (docs.vanish.trade/legal/TOS)";

  fn sign_message(details: &str, keypair: &Keypair) -> String {
      let message = format!("{TOS}\n\nDetails: {details}");
      let sig = keypair.sign_message(message.as_bytes());
      general_purpose::STANDARD.encode(sig.as_ref())
  }
  ```
</CodeGroup>

<Warning>
  Timestamps must be Unix time in **milliseconds** - `Date.now()` in TypeScript, `timestamp_millis()` in Rust - and every value you sign must match the value you send in the request body.
</Warning>

***

## Broadcast and Commit

Vanish signs transactions; you submit them. These two helpers are used by both walkthroughs - `broadcast` is a no-op when Vanish has already submitted the transaction itself, and `commit` polls until the action reaches a terminal status.

<CodeGroup>
  ```typescript TypeScript theme={null}
  // Vanish signs the transaction; you submit it. Nothing to do on the Jito route.
  async function broadcast(action: { transaction: string | null }) {
    if (!action.transaction) return;
    const txId = await connection.sendRawTransaction(
      Buffer.from(action.transaction, 'base64'), { maxRetries: 3 }
    );
    await connection.confirmTransaction(txId, 'confirmed');
    return txId;
  }

  // poll until the action reaches a terminal status
  async function commit(path: '/commit' | '/borrow/commit', txId: string) {
    for (;;) {
      const res = await vanish(path, { method: 'POST', body: JSON.stringify({ tx_id: txId }) });
      if (res.status !== 'pending') return res;
      await new Promise((r) => setTimeout(r, 2000));
    }
  }
  ```

  ```rust Rust theme={null}
  use solana_sdk::transaction::VersionedTransaction;

  // Vanish signs the transaction; you submit it. Nothing to do on the Jito route.
  async fn broadcast(rpc: &RpcClient, action: &Value) -> Result<Option<String>, Box<dyn std::error::Error>> {
      let Some(encoded) = action["transaction"].as_str() else { return Ok(None) };
      let tx_bytes = general_purpose::STANDARD.decode(encoded)?;
      let tx: VersionedTransaction = bincode::deserialize(&tx_bytes)?;
      Ok(Some(rpc.send_and_confirm_transaction(&tx)?.to_string()))
  }

  // poll until the action reaches a terminal status
  async fn commit(
      client: &Client, api_key: &str, path: &str, tx_id: &str,
  ) -> Result<Value, reqwest::Error> {
      loop {
          let res = vanish(client, api_key, path, Some(&serde_json::json!({ "tx_id": tx_id }))).await?;
          if res["status"] != "pending" {
              return Ok(res);
          }
          tokio::time::sleep(std::time::Duration::from_secs(2)).await;
      }
  }
  ```
</CodeGroup>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Trade" color="#00dae9" icon="arrow-right-arrow-left" iconType="duotone" href="/guide/quickstart/trade">
    Fund a Vanish balance and execute your first private trade.
  </Card>

  <Card title="Lend" color="#00dae9" icon="building-columns" iconType="duotone" href="/guide/quickstart/lend">
    Open a position, then settle it and close the wallet.
  </Card>
</CardGroup>
