> ## 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 ile İşlem Gönderme

> Solana işlemlerini OrbitFlare Apex'e JSON-RPC sendTransaction, ikili HTTP rotaları /send-bin ve /send-batch veya kalıcı QUIC akışları üzerinden gönderin.

## Bir Taşıma Yöntemi Seçin

|                       | JSON-RPC                    | `POST /send`           | `POST /send-bin`      | `POST /send-batch`              | QUIC tek yönlü              | QUIC çift yönlü                  |
| --------------------- | --------------------------- | ---------------------- | --------------------- | ------------------------------- | --------------------------- | -------------------------------- |
| **Gövde**             | JSON içinde base64          | JSON içinde base64     | ham baytlar           | en fazla 16 ham çerçeve         | akış başına bir veri paketi | akış başına bir veri paketi      |
| **Yanıt**             | imza veya JSON-RPC hatası   | imza veya JSON hatası  | imza veya JSON hatası | çerçeve başına sonuçlar         | yok                         | kabul kodu                       |
| **En uygun kullanım** | mevcut koda doğrudan ekleme | basit JSON istemcileri | en düşük HTTP ek yükü | tek istekte çok sayıda gönderim | en hızlı yol                | ret nedenini satır içinde görmek |

Tüm taşıma yöntemleri aynı [bahşiş kuralını](/tr/apex/tips), aynı doğrulamayı ve aynı yönlendirmeyi uygular. Taşıma yöntemi yalnızca baytların Apex uç noktasına nasıl ulaştığını değiştirir.

İşlem boyutu sınırları her yerde aynıdır: legacy ve v0 işlemler 1232 bayta kadar, [transaction v1](/tr/apex/transaction-v1) 4096 bayta kadar.

## Bahşişli ve imzalı bir işlem oluşturun

Bu sayfadaki örnekler dil başına tek bir yardımcıyı paylaşır. Yardımcı, hesaplama bütçesi ve bahşiş içeren bir memo işlemi oluşturur, onu imzalar ve bir imzayı onaylayabilir. İmzalı bir işlemi base64 olarak yazdırmak için doğrudan çalıştırın. cURL örnekleri bunu kullanır.

Önce ortamı ayarlayın:

```bash theme={null}
export APEX_API_KEY="YOUR_API_KEY"
export APEX_RPC="http://fra.apex.orbitflare.com"
export SOLANA_RPC_URL="https://api.mainnet-beta.solana.com"
export KEYPAIR_PATH="payer.json"
```

<CodeGroup>
  ```javascript apex-tx.mjs theme={null}
  // npm install @solana/web3.js
  // Print a signed, tipped transaction as base64: node apex-tx.mjs
  import {
    ComputeBudgetProgram, Connection, Keypair, PublicKey, SystemProgram,
    TransactionInstruction, TransactionMessage, VersionedTransaction,
  } from "@solana/web3.js";
  import { readFileSync } from "node:fs";
  import { fileURLToPath } from "node:url";

  export const APEX_RPC = process.env.APEX_RPC ?? "http://fra.apex.orbitflare.com";
  export const API_KEY = process.env.APEX_API_KEY ?? "";
  const SOLANA_RPC = process.env.SOLANA_RPC_URL ?? "https://api.mainnet-beta.solana.com";
  const TIP_LAMPORTS = Number(process.env.TIP_LAMPORTS ?? 1_000_000);
  const MEMO_PROGRAM = new PublicKey("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr");

  export const payer = Keypair.fromSecretKey(
    Uint8Array.from(JSON.parse(readFileSync(process.env.KEYPAIR_PATH ?? "payer.json", "utf8"))),
  );
  export const connection = new Connection(SOLANA_RPC, "confirmed");

  export async function apexRpc(method, params) {
    const res = await fetch(APEX_RPC, {
      method: "POST",
      headers: { "Content-Type": "application/json", "x-api-key": API_KEY },
      body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params }),
    });
    const body = await res.json();
    if (body.error) throw new Error(`${method} failed ${body.error.code}: ${body.error.message}`);
    return body.result;
  }

  let tipAccounts;
  let counter = 0;

  // Returns a signed VersionedTransaction. Pass { tip: false } for a bundle member without a tip.
  export async function buildTx({ tip = true, label = "apex" } = {}) {
    tipAccounts ??= await apexRpc("getTipAccounts", []);
    const tipAccount = new PublicKey(tipAccounts[Math.floor(Math.random() * tipAccounts.length)]);
    const { blockhash } = await connection.getLatestBlockhash("confirmed");
    const instructions = [
      ComputeBudgetProgram.setComputeUnitLimit({ units: 100_000 }),
      ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 10_000 }),
      new TransactionInstruction({
        programId: MEMO_PROGRAM,
        keys: [{ pubkey: payer.publicKey, isSigner: true, isWritable: true }],
        data: Buffer.from(`${label} ${Date.now()} ${counter++}`),
      }),
    ];
    if (tip) {
      instructions.push(
        SystemProgram.transfer({ fromPubkey: payer.publicKey, toPubkey: tipAccount, lamports: TIP_LAMPORTS }),
      );
    }
    const message = new TransactionMessage({
      payerKey: payer.publicKey,
      recentBlockhash: blockhash,
      instructions,
    }).compileToV0Message();
    const tx = new VersionedTransaction(message);
    tx.sign([payer]);
    return tx;
  }

  // Poll getSignatureStatuses on the Solana RPC. Returns the slot, or null on timeout.
  export async function confirm(signature, timeoutMs = 30_000) {
    const deadline = Date.now() + timeoutMs;
    while (Date.now() < deadline) {
      const { value } = await connection.getSignatureStatuses([signature]);
      const status = value[0];
      if (status?.err) throw new Error(`failed on chain: ${JSON.stringify(status.err)}`);
      if (status?.confirmationStatus === "confirmed" || status?.confirmationStatus === "finalized") {
        return status.slot;
      }
      await new Promise((resolve) => setTimeout(resolve, 500));
    }
    return null;
  }

  if (process.argv[1] === fileURLToPath(import.meta.url)) {
    const tx = await buildTx();
    console.log(Buffer.from(tx.serialize()).toString("base64"));
  }
  ```

  ```python apex_tx.py theme={null}
  # pip install solders requests
  # Print a signed, tipped transaction as base64: python apex_tx.py
  import base64
  import itertools
  import json
  import os
  import random
  import time

  import requests
  from solders.compute_budget import set_compute_unit_limit, set_compute_unit_price
  from solders.hash import Hash
  from solders.instruction import AccountMeta, Instruction
  from solders.keypair import Keypair
  from solders.message import Message
  from solders.pubkey import Pubkey
  from solders.system_program import TransferParams, transfer
  from solders.transaction import Transaction

  APEX_RPC = os.environ.get("APEX_RPC", "http://fra.apex.orbitflare.com")
  API_KEY = os.environ.get("APEX_API_KEY", "")
  SOLANA_RPC = os.environ.get("SOLANA_RPC_URL", "https://api.mainnet-beta.solana.com")
  TIP_LAMPORTS = int(os.environ.get("TIP_LAMPORTS", "1000000"))
  MEMO_PROGRAM = Pubkey.from_string("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr")

  # One session keeps the HTTP connection to the Apex endpoint open between sends.
  session = requests.Session()
  session.headers.update({"x-api-key": API_KEY})

  with open(os.environ.get("KEYPAIR_PATH", "payer.json")) as f:
      payer = Keypair.from_bytes(bytes(json.load(f)))

  _tip_accounts = None
  _counter = itertools.count()


  def apex_rpc(method, params):
      r = session.post(APEX_RPC, json={"jsonrpc": "2.0", "id": 1, "method": method, "params": params}, timeout=5)
      body = r.json()
      if "error" in body:
          raise RuntimeError(f"{method} failed {body['error']['code']}: {body['error']['message']}")
      return body["result"]


  def solana_rpc(method, params):
      r = requests.post(SOLANA_RPC, json={"jsonrpc": "2.0", "id": 1, "method": method, "params": params}, timeout=10)
      return r.json()["result"]


  def build_tx(tip=True, label="apex"):
      """Returns a signed Transaction. Pass tip=False for a bundle member without a tip."""
      global _tip_accounts
      if _tip_accounts is None:
          _tip_accounts = apex_rpc("getTipAccounts", [])
      tip_account = Pubkey.from_string(random.choice(_tip_accounts))
      blockhash = Hash.from_string(
          solana_rpc("getLatestBlockhash", [{"commitment": "confirmed"}])["value"]["blockhash"])
      instructions = [
          set_compute_unit_limit(100_000),
          set_compute_unit_price(10_000),
          Instruction(MEMO_PROGRAM, f"{label} {time.time_ns()} {next(_counter)}".encode(),
                      [AccountMeta(payer.pubkey(), is_signer=True, is_writable=True)]),
      ]
      if tip:
          instructions.append(
              transfer(TransferParams(from_pubkey=payer.pubkey(), to_pubkey=tip_account, lamports=TIP_LAMPORTS)))
      return Transaction([payer], Message.new_with_blockhash(instructions, payer.pubkey(), blockhash), blockhash)


  def confirm(signature, timeout_s=30.0):
      """Poll getSignatureStatuses on the Solana RPC. Returns the slot, or None on timeout."""
      deadline = time.time() + timeout_s
      while time.time() < deadline:
          status = solana_rpc("getSignatureStatuses", [[signature]])["value"][0]
          if status and status.get("err"):
              raise RuntimeError(f"failed on chain: {status['err']}")
          if status and status.get("confirmationStatus") in ("confirmed", "finalized"):
              return status["slot"]
          time.sleep(0.5)
      return None


  if __name__ == "__main__":
      print(base64.b64encode(bytes(build_tx())).decode())
  ```
</CodeGroup>

cURL örnekleri için her gönderimden önce yeni bir işlem imzalayın:

```bash theme={null}
TX_BASE64=$(node apex-tx.mjs)      # or: TX_BASE64=$(python apex_tx.py)
```

Bir işlem yalnızca blockhash'i geçerli olduğu sürece, yani kabaca 60 ila 90 saniye boyunca geçerlidir, bu yüzden göndermeden hemen önce imzalayın.

## JSON-RPC sendTransaction

Apex uç noktasının köküne `POST` yapın. Bu, standart Solana `sendTransaction` biçimidir, dolayısıyla mevcut kod URL'yi değiştirip API anahtarını ekleyerek taşınır.

| Parametre              | Tür                   | Açıklama                                                                                                                           |
| ---------------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `params[0]`            | string                | base64 ile kodlanmış imzalı işlem                                                                                                  |
| `params[1].encoding`   | string                | `"base64"`                                                                                                                         |
| `params[1].maxRetries` | number, isteğe bağlı  | Bu işlem için yeniden deneme bütçesi. Uç noktanın varsayılanını kullanmak için atlayın                                             |
| `params[2]`            | boolean, isteğe bağlı | `mevProtect`. `true` değeri Shield engelleme listesindeki liderleri atlar. [MEV koruması](/tr/apex/mev-protection) sayfasına bakın |

<CodeGroup>
  ```bash cURL theme={null}
  curl -s "$APEX_RPC" \
    -H "Content-Type: application/json" \
    -H "x-api-key: $APEX_API_KEY" \
    -d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"sendTransaction\",\"params\":[\"$TX_BASE64\",{\"encoding\":\"base64\",\"maxRetries\":30},false]}"
  ```

  ```javascript JavaScript theme={null}
  import { apexRpc, buildTx, confirm } from "./apex-tx.mjs";

  const tx = await buildTx({ label: "apex json-rpc" });
  const signature = await apexRpc("sendTransaction", [
    Buffer.from(tx.serialize()).toString("base64"),
    { encoding: "base64", maxRetries: 30 },
    false, // mevProtect
  ]);
  console.log("accepted:", signature);
  console.log("landed in slot", await confirm(signature));
  ```

  ```python Python theme={null}
  import base64

  from apex_tx import apex_rpc, build_tx, confirm

  tx = build_tx(label="apex json-rpc")
  signature = apex_rpc("sendTransaction", [
      base64.b64encode(bytes(tx)).decode(),
      {"encoding": "base64", "maxRetries": 30},
      False,  # mevProtect
  ])
  print("accepted:", signature)
  print("landed in slot", confirm(signature))
  ```

  ```rust Rust theme={null}
  // `tx` is a signed, tipped VersionedTransaction, built as in the Quickstart.
  use apex_sender_client::rpc::RpcClient;
  use apex_sender_client::{serialize_transaction, Region};

  let rpc = RpcClient::new(Region::Frankfurt, &api_key);
  let wire = serialize_transaction(&tx)?;
  // mev_protect = false, max_retries = Some(30)
  let signature = rpc.send_transaction(&wire, false, Some(30)).await?;
  println!("accepted: {signature}");
  ```
</CodeGroup>

Yanıt:

```json theme={null}
{ "jsonrpc": "2.0", "id": 1, "result": "<signature>" }
```

Apex simülasyon yapmaz ve preflight kontrolleri çalıştırmaz. `skipPreflight` ve `preflightCommitment` etkisizdir. Simülasyon istiyorsanız göndermeden önce normal RPC'nizde `simulateTransaction` yöntemini çağırın.

## Düz HTTP Rotaları

Bu rotalar aynı ana makine ve portta JSON-RPC'nin yanında yer alır ve JSON-RPC zarfını atlar.

| Rota                | İstek gövdesi                                                                              | Başarı yanıtı                                    |
| ------------------- | ------------------------------------------------------------------------------------------ | ------------------------------------------------ |
| `POST /send`        | JSON: `{"transaction": "<base64>", "mevProtect"?: bool, "maxRetries"?: n}`                 | `{"signature": "..."}`                           |
| `POST /send-bin`    | Ham işlem baytları, `Content-Type: application/octet-stream`                               | `{"signature": "..."}`                           |
| `POST /send-batch`  | En fazla 16 çerçeve. Her biri big-endian u16 uzunluk ve ardından işlem baytlarından oluşur | `attempted`, `accepted`, `rejected` ve `results` |
| `POST /send-bundle` | 1 ila 4 çerçeve, aynı çerçeveleme. [Paketler](/tr/apex/bundles) sayfasına bakın            | `{"bundle_id": "...", "signatures": [...]}`      |
| `GET /ping`         | Yok, API anahtarı da gerekmez                                                              | `pong`                                           |

İkili rotalarda seçenekler sorgu bayrakları olarak iletilir: `?mev_protect=1` ve `&max_retries=N`.

Hatalar, bir HTTP durumuyla birlikte JSON olarak gelir: `{"error": "<label>", "message": "..."}`. [Hatalar ve hız sınırları](/tr/apex/errors-and-rate-limits#düz-http-hataları) sayfasına bakın.

### POST /send

<CodeGroup>
  ```bash cURL theme={null}
  curl -s "$APEX_RPC/send" \
    -H "Content-Type: application/json" \
    -H "x-api-key: $APEX_API_KEY" \
    -d "{\"transaction\":\"$TX_BASE64\",\"mevProtect\":false,\"maxRetries\":30}"
  ```

  ```javascript JavaScript theme={null}
  import { APEX_RPC, API_KEY, buildTx, confirm } from "./apex-tx.mjs";

  const tx = await buildTx({ label: "apex send" });
  const res = await fetch(`${APEX_RPC}/send`, {
    method: "POST",
    headers: { "Content-Type": "application/json", "x-api-key": API_KEY },
    body: JSON.stringify({ transaction: Buffer.from(tx.serialize()).toString("base64"), mevProtect: false }),
  });
  const body = await res.json();
  if (!body.signature) throw new Error(`rejected ${res.status} ${body.error}: ${body.message}`);
  console.log("accepted:", body.signature);
  console.log("landed in slot", await confirm(body.signature));
  ```

  ```python Python theme={null}
  import base64

  from apex_tx import APEX_RPC, build_tx, confirm, session

  tx = build_tx(label="apex send")
  r = session.post(f"{APEX_RPC}/send",
                   json={"transaction": base64.b64encode(bytes(tx)).decode(), "mevProtect": False}, timeout=5)
  body = r.json()
  if "signature" not in body:
      raise RuntimeError(f"rejected {r.status_code} {body['error']}: {body['message']}")
  print("accepted:", body["signature"])
  print("landed in slot", confirm(body["signature"]))
  ```
</CodeGroup>

### POST /send-bin

En ucuz HTTP yolu: girişte base64 ve JSON yoktur. Gövde, bayt bayt serileştirilmiş işlemin kendisidir.

<CodeGroup>
  ```bash cURL theme={null}
  echo "$TX_BASE64" | base64 --decode | curl -s "$APEX_RPC/send-bin?mev_protect=0" \
    -H "Content-Type: application/octet-stream" \
    -H "x-api-key: $APEX_API_KEY" \
    --data-binary @-
  ```

  ```javascript JavaScript theme={null}
  import { APEX_RPC, API_KEY, buildTx, confirm } from "./apex-tx.mjs";

  const tx = await buildTx({ label: "apex send-bin" });
  const res = await fetch(`${APEX_RPC}/send-bin`, {
    method: "POST",
    headers: { "Content-Type": "application/octet-stream", "x-api-key": API_KEY },
    body: tx.serialize(),
  });
  const body = await res.json();
  if (!body.signature) throw new Error(`rejected ${res.status} ${body.error}: ${body.message}`);
  console.log("accepted:", body.signature);
  console.log("landed in slot", await confirm(body.signature));
  ```

  ```python Python theme={null}
  from apex_tx import APEX_RPC, build_tx, confirm, session

  tx = build_tx(label="apex send-bin")
  r = session.post(f"{APEX_RPC}/send-bin", headers={"Content-Type": "application/octet-stream"},
                   data=bytes(tx), timeout=5)
  body = r.json()
  if "signature" not in body:
      raise RuntimeError(f"rejected {r.status_code} {body['error']}: {body['message']}")
  print("accepted:", body["signature"])
  print("landed in slot", confirm(body["signature"]))
  ```

  ```rust Rust theme={null}
  // `tx` is a signed, tipped VersionedTransaction, built as in the Quickstart.
  use apex_sender_client::rpc::RpcClient;
  use apex_sender_client::{serialize_transaction, Region};

  let rpc = RpcClient::new(Region::Frankfurt, &api_key);
  let wire = serialize_transaction(&tx)?;
  let signature = rpc.send_transaction_binary(&wire, false, None).await?;
  println!("accepted: {signature}");
  ```
</CodeGroup>

### POST /send-batch

Tek bir istekte en fazla 16 bağımsız işlem gönderin. Gövde bir çerçeve dizisidir:

```text theme={null}
u16 big-endian   length of the transaction bytes
bytes            the serialized transaction
... repeated, up to 16 frames
```

Her işlem kendi başına kabul edilir. Toplu gönderim **atomik değildir**: bazı çerçeveler kabul edilirken diğerleri reddedilebilir. Ya hep ya hiç yürütme için [Paketler](/tr/apex/bundles) kullanın.

<CodeGroup>
  ```bash cURL theme={null}
  : > batch.bin
  for i in 1 2 3; do
    node apex-tx.mjs | base64 --decode > tx.bin
    printf '%04x' $(($(wc -c < tx.bin))) | xxd -r -p >> batch.bin   # u16 big-endian length
    cat tx.bin >> batch.bin
  done

  curl -s "$APEX_RPC/send-batch" \
    -H "Content-Type: application/octet-stream" \
    -H "x-api-key: $APEX_API_KEY" \
    --data-binary @batch.bin
  ```

  ```javascript JavaScript theme={null}
  import { APEX_RPC, API_KEY, buildTx, confirm } from "./apex-tx.mjs";

  const txs = [];
  for (let i = 0; i < 3; i++) txs.push(await buildTx({ label: `apex batch ${i}` }));

  // Each frame: u16 big-endian length, then the transaction bytes.
  const frames = txs.map((tx) => {
    const wire = Buffer.from(tx.serialize());
    const length = Buffer.alloc(2);
    length.writeUInt16BE(wire.length);
    return Buffer.concat([length, wire]);
  });

  const res = await fetch(`${APEX_RPC}/send-batch`, {
    method: "POST",
    headers: { "Content-Type": "application/octet-stream", "x-api-key": API_KEY },
    body: Buffer.concat(frames),
  });
  const body = await res.json();
  if (!body.results) throw new Error(`rejected ${res.status} ${body.error}: ${body.message}`);
  console.log(`accepted ${body.accepted} of ${body.attempted}`);
  for (const result of body.results) {
    if (result.signature) console.log(result.signature, "landed in slot", await confirm(result.signature));
    else console.log("rejected:", result.error, result.message);
  }
  ```

  ```python Python theme={null}
  import struct

  from apex_tx import APEX_RPC, build_tx, confirm, session

  txs = [bytes(build_tx(label=f"apex batch {i}")) for i in range(3)]
  # Each frame: u16 big-endian length, then the transaction bytes.
  payload = b"".join(struct.pack(">H", len(wire)) + wire for wire in txs)

  r = session.post(f"{APEX_RPC}/send-batch", headers={"Content-Type": "application/octet-stream"},
                   data=payload, timeout=5)
  body = r.json()
  if "results" not in body:
      raise RuntimeError(f"rejected {r.status_code} {body['error']}: {body['message']}")
  print(f"accepted {body['accepted']} of {body['attempted']}")
  for result in body["results"]:
      if "signature" in result:
          print(result["signature"], "landed in slot", confirm(result["signature"]))
      else:
          print("rejected:", result["error"], result["message"])
  ```

  ```rust Rust theme={null}
  // `txs` is a Vec of signed, tipped VersionedTransaction values.
  use apex_sender_client::rpc::{BatchItem, RpcClient};
  use apex_sender_client::{serialize_transaction, Region};

  let rpc = RpcClient::new(Region::Frankfurt, &api_key);
  let wires: Vec<Vec<u8>> = txs.iter().map(serialize_transaction).collect::<Result<_, _>>()?;
  let refs: Vec<&[u8]> = wires.iter().map(Vec::as_slice).collect();

  let batch = rpc.send_batch(&refs, false, None).await?;
  println!("accepted {} of {}", batch.accepted, batch.attempted);
  for item in &batch.results {
      match item {
          BatchItem::Accepted(signature) => println!("accepted: {signature}"),
          BatchItem::Rejected { error, message } => println!("rejected: {error}: {message}"),
      }
  }
  ```
</CodeGroup>

İsteğin kendisi geçerli olduğunda yanıt her zaman HTTP 200'dür ve çerçeve sırasıyla, çerçeve başına bir sonuç içerir:

```json theme={null}
{
  "attempted": 3,
  "accepted": 2,
  "rejected": 1,
  "results": [
    { "signature": "<signature 1>" },
    { "signature": "<signature 2>" },
    { "error": "below_floor", "message": "..." }
  ]
}
```

### GET /ping

`pong` döndürür. API anahtarı gerektirmez. Bir HTTP bağlantısını ihtiyaç duymadan önce açıp ısıtmak ve boşta kalan bir bağlantıyı canlı tutmak için kullanın. [En iyi uygulamalar](/tr/apex/best-practices#bağlantıları-sıcak-tutun) sayfasına bakın.

```bash theme={null}
curl -s "$APEX_RPC/ping"
```

### CORS

Her HTTP yanıtı `Access-Control-Allow-Origin: *` taşır ve `OPTIONS` ön kontrol istekleri yanıtlanır, dolayısıyla yukarıdaki tüm rotalar tarayıcı kodundan çalışır. Bir anahtarı bir ön yüze koymadan önce [tarayıcı notlarına](/tr/apex/authentication#tarayıcılar) bakın.

## QUIC

QUIC, içeri girmenin en hızlı yoludur. Apex uç noktasına, [API anahtarınızdan türetilen bir istemci sertifikasıyla](/tr/apex/authentication#quic-istemci-sertifikası) bir kez doğrulanan tek bir kalıcı bağlantı tutar ve işlem başına bir akış açarsınız. Sıcak bir bağlantıda bir gönderim, bir akış açma ve bir yazmadan ibarettir, yani istemci tarafında birkaç mikrosaniye sürer.

İki tür akış vardır:

| Akış           | Geri aldığınız şey                                             | Kullanım amacı                                                           |
| -------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------ |
| **Tek yönlü**  | Hiçbir şey. Gönder ve unut                                     | En hızlı yolda üretim gönderimleri                                       |
| **Çift yönlü** | Tek bir kabul yanıtı: kabul edildi veya bir ret kodu ve mesajı | Entegrasyon, hata ayıklama ve nedeni satır içinde görmek isteyen araçlar |

### Rust

[`apex-sender-client`](/tr/apex/rust-client) crate'i taşıma yönteminin tamamını uygular: sertifika, canlı tutma, 0-RTT ile devam ettirme ve yeniden bağlanmalar. Bu program her akış türünde bir işlem gönderir. [Hızlı başlangıç](/tr/apex/quickstart#rust-bağımlılıkları) ile aynı `Cargo.toml` dosyasını kullanır.

```rust theme={null}
use std::str::FromStr;
use std::time::Duration;

use apex_sender_client::rpc::{RpcClient, SolanaRpc};
use apex_sender_client::{tip, tip_instruction, ApexSenderClient, Error, Region, MIN_TIP_LAMPORTS};
use solana_compute_budget_interface::ComputeBudgetInstruction;
use solana_instruction::{AccountMeta, Instruction};
use solana_keypair::{read_keypair_file, Keypair};
use solana_pubkey::Pubkey;
use solana_signer::Signer;
use solana_transaction::versioned::VersionedTransaction;
use solana_transaction::Transaction;

async fn tipped_memo(
    payer: &Keypair,
    tip_accounts: &[Pubkey],
    solana: &SolanaRpc,
    label: &str,
) -> Result<VersionedTransaction, Box<dyn std::error::Error>> {
    let nonce = std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)?
        .as_nanos();
    let tip_account = tip::pick_tip_account(tip_accounts).ok_or("no tip accounts")?;
    let instructions = [
        ComputeBudgetInstruction::set_compute_unit_limit(100_000),
        ComputeBudgetInstruction::set_compute_unit_price(10_000),
        Instruction::new_with_bytes(
            Pubkey::from_str("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr")?,
            format!("{label} {nonce}").as_bytes(),
            vec![AccountMeta::new(payer.pubkey(), true)],
        ),
        tip_instruction(&payer.pubkey(), &tip_account, MIN_TIP_LAMPORTS),
    ];
    let blockhash = solana.latest_blockhash().await?;
    Ok(VersionedTransaction::from(Transaction::new_signed_with_payer(
        &instructions,
        Some(&payer.pubkey()),
        &[payer],
        blockhash,
    )))
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api_key = std::env::var("APEX_API_KEY")?;
    let solana = SolanaRpc::new(
        std::env::var("SOLANA_RPC_URL").unwrap_or_else(|_| "https://api.mainnet-beta.solana.com".into()),
    );
    let payer = read_keypair_file(std::env::var("KEYPAIR_PATH").unwrap_or_else(|_| "payer.json".into()))?;
    let region = Region::Frankfurt;

    let client = ApexSenderClient::connect(region, &api_key).await?;
    let tip_accounts = RpcClient::new(region, &api_key).get_tip_accounts().await?;

    // Unidirectional stream: fire and forget. Returns the signature, reads nothing back.
    let tx = tipped_memo(&payer, &tip_accounts, &solana, "apex quic uni").await?;
    let signature = client.send_transaction(&tx).await?;
    println!("sent: {signature}");
    println!("slot: {:?}", solana.confirm(&signature.to_string(), Duration::from_secs(30)).await?);

    // Bidirectional stream: the endpoint answers accepted or rejected before racing it.
    let tx = tipped_memo(&payer, &tip_accounts, &solana, "apex quic bidi").await?;
    match client.send_transaction_with_response(&tx).await {
        Ok(signature) => {
            println!("accepted: {signature}");
            println!("slot: {:?}", solana.confirm(&signature.to_string(), Duration::from_secs(30)).await?);
        }
        // Fix the transaction, not the client. The message names the floor when the tip is short.
        Err(Error::Rejected { code, message }) => println!("rejected: {code:?}: {message}"),
        Err(e) => return Err(e.into()),
    }
    Ok(())
}
```

### Kabul Kodları

Çift yönlü bir akış şunlardan biriyle yanıt verir:

| Kod | Ad               | Anlamı                                                                |
| --- | ---------------- | --------------------------------------------------------------------- |
| `0` | ok               | Kabul edildi. İşlem izleniyor ve liderlere yarıştırılıyor             |
| `1` | unauthorized     | Bağlantının anahtarı geçerli değil                                    |
| `2` | rate limited     | Anahtarınız saniyelik sınırını aştı                                   |
| `3` | invalid          | İşlem sanitizasyondan geçemedi. Mesaj neyin başarısız olduğunu söyler |
| `4` | no tip           | Bir Apex bahşiş hesabına yapılan transfer bulunamadı                  |
| `5` | below floor      | Bahşiş katmanınızın tabanının altında. Mesaj tabanı belirtir          |
| `6` | busy             | Uç nokta yük atıyor. Kısa süre sonra yeniden deneyin                  |
| `7` | malformed packet | Veri paketinin çerçevelemesi yanlış                                   |

Bir ret, o veri paketi için kesindir. Yanıt gelmeden önce oluşan bir taşıma hatasını yeniden denemek güvenlidir, çünkü uç nokta imzaya göre tekilleştirir.

### Diğer Dillerden QUIC

Taşıma yöntemini, istemci sertifikalarını destekleyen bir QUIC kütüphanesi olan herhangi bir dilde uygulayabilirsiniz.

**Bağlantı**

* TLS 1.3 ve ALPN `solana-tpu` ile QUIC (RFC 9000).
* Sunucu sertifikası, kendinden imzalı bir yer tutucudur. Onu doğrulamayın.
* İstemci, [API anahtarınızdan türetilen sertifikayı](/tr/apex/authentication#quic-istemci-sertifikası) sunmalıdır.
* Apex uç noktası başına tek bir bağlantıyı açık tutun. Düzenli olarak QUIC PING gönderin (Rust istemcisi her saniye ping atar). Uç noktanın boşta kalma zaman aşımı 30 saniyedir. 0-RTT etkindir.

**İşlem veri paketi**

Bir akış açın, tam olarak bir veri paketi yazın ve akışı sonlandırın:

```text theme={null}
u64 LE   length of the transaction bytes
bytes    the serialized transaction: legacy or v0 at most 1232 bytes, v1 at most 4096
u8       mev_protect: 1 to skip Shield-blocklisted leaders, else 0
u8       max_retries present: 0 or 1
u16 LE   max_retries, only if present
```

Bu, bincode'un varsayılan sabit tamsayı little-endian seçenekleriyle `{ wire_transaction: Vec<u8>, mev_protect: bool, max_retry: Option<u16> }` yapısının tam olarak bincode karşılığıdır. Veri paketinin tamamı en fazla 4160 bayt olmalıdır.

**Kabul çerçevesi** (yalnızca çift yönlü akışlar)

```text theme={null}
u8       status: one of the admission codes above
[64]     status 0 only: the transaction's first signature
u16 LE   status != 0: message length
bytes    status != 0: UTF-8 message
```

Rust'ta `wire::encode_packet` ve `wire::decode_admission` her iki çerçevenin referans uygulamasıdır.
