Corvus Labs

Falcon quick start

Verify your Falcon key, submit a signed Solana transaction over JSON-RPC or QUIC, then confirm the signature on a normal Solana RPC.

From a fresh API key to a confirmed signature. Everything below uses region fra; swap in any of the nine Falcon metros.

You needWhere it comes from
UUID API keyOnboarding
A tip accountFalcon tips & transaction requirements
A region codeFalcon regions & endpoints
A normal Solana RPC: blockhash, optional simulation, confirmationCorvus Solana RPC, or whichever you already use
export FALCON_HTTP='http://fra.falcon.wtf'
export FALCON_API_KEY='00000000-0000-0000-0000-000000000000'

Check your API key with getVersion

It takes no transaction and no tip, so a failure here can only be an access problem.

curl -sS -X POST "${FALCON_HTTP}?api-key=${FALCON_API_KEY}" \
  -H 'Content-Type: application/json' \
  --data '{"jsonrpc":"2.0","id":1,"method":"getVersion"}'
{"jsonrpc":"2.0","result":{"solana-core":"falcon/VERSION","feature-set":null},"id":1}

HTTP 401 with {"code":-32000,"message":"unauthorized"} means the api-key query parameter is missing, isn't a valid UUID, or isn't a live key. Falcon authenticates before it reads the body.

Build and sign a transaction that pays the tip

Add a System Program transfer to a tip account for at least 1,000,000 lamports, then set the fee payer and a fresh blockhash and sign. What comes out has to serialize to 1,232 bytes or less, tip included.

Full rules and a TypeScript example: Falcon tips & transaction requirements.

Submit it

export TX_BASE64='YOUR_SIGNED_TRANSACTION_BASE64'

curl -sS -X POST "${FALCON_HTTP}?api-key=${FALCON_API_KEY}" \
  -H 'Content-Type: application/json' \
  --data "{
    \"jsonrpc\": \"2.0\",
    \"id\": 1,
    \"method\": \"sendTransaction\",
    \"params\": [
      \"${TX_BASE64}\",
      {\"encoding\": \"base64\", \"skipPreflight\": true}
    ]
  }"
{"jsonrpc":"2.0","result":"5Yv...signature...","id":1}

encoding defaults to base58. The whole request body has to stay at or under 3,072 bytes.

Post the raw serialized transaction: no envelope, no length prefix, no API key in the body.

curl -sS -X POST "${FALCON_HTTP}/binary?api-key=${FALCON_API_KEY}" \
  -H 'Content-Type: application/octet-stream' \
  --data-binary @transaction.bin

You get back 200 and the base58 signature as plain text.

[dependencies]
anyhow             = "1"
falcon-client      = "0.1"
solana-transaction = "3"
tokio              = { version = "1", features = ["rt-multi-thread", "macros"] }
uuid               = "1"
use {falcon_client::FalconClient, solana_transaction::versioned::VersionedTransaction, uuid::Uuid};

async fn submit(transaction: &VersionedTransaction) -> anyhow::Result<()> {
    let api_key = Uuid::parse_str(&std::env::var("FALCON_API_KEY")?)?;
    let client = FalconClient::connect("fra.falcon.wtf:5000", api_key).await?;

    client.send_transaction(transaction).await?;
    Ok(())
}

The client holds one persistent QUIC connection and reconnects on its own, so connect once and keep it.

Confirm the signature on a normal Solana RPC

HTTP hands you the signature in the response body. QUIC and native UDP hand you nothing, so use the first signature of the transaction you signed; same value.

curl -sS 'http://fra.corvus-labs.io:8899' \
  -H 'Content-Type: application/json' \
  --data '{"jsonrpc":"2.0","id":1,"method":"getSignatureStatuses",
           "params":[["5Yv...signature..."],{"searchTransactionHistory":false}]}'

Poll until the status reaches the commitment you need, or until the blockhash expires.

Handle the outcome

OutcomeDo this
Signature landsDone. Stop retrying.
No status yet, blockhash still validResend the same signed bytes. Falcon suppresses a duplicate only once that signature has already been delivered, so a landing-retry isn't wasted.
Blockhash expired without landingRebuild with a fresh blockhash and re-sign. That's a new signature; track it separately.
-32602, or HTTP 400 on a raw routeThe transaction is invalid (size, signatures, encoding or tip). Fix and re-sign.
HTTP 429 or SubmitError::RateLimitedYou're over your per-second allowance. The same signed bytes are fine to send later.

Next

On this page