Send Bundle API

Send multiple transactions as an atomic bundle through Lunar Lander. All transactions in a bundle are executed sequentially and atomically — they all land or none are committed.

What this does

This document describes Lunar Lander's /sendBundle endpoint for atomic bundle submission. The endpoint supports the following use case:

  • You submit multiple signed transactions as a single atomic bundle via JSON-RPC
  • All transactions in the bundle are executed sequentially — they all land or none are committed
  • Lunar Lander fans out the bundle to multiple block-engine relays for best landing probability

Endpoints

  • POST /sendBundle

Available at all regional endpoints by using the /sendBundle endpoint

Requires Content-Type: application/json.

Note: This method is not enabled by default for all API keys. Contact us to activate bundle sending on your key.

Request Format

Use the sendBundle JSON-RPC method. The first parameter is an array of base64-encoded signed transactions.

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "sendBundle",
  "params": [
    [
      "<base64_encoded_signed_tx_1>",
      "<base64_encoded_signed_tx_2>"
    ],
    {
      "encoding": "base64"
    }
  ]
}
  • params[0] — array of signed, serialized transactions encoded in base64
  • params[1].encoding — transaction encoding (use base64)

Validation And Limits

  • Maximum transactions per bundle: 4
  • Each transaction must be fully signed before submission
  • At least one transaction must include a tip to a Lunar Lander tip account
  • Tip minimum: 1,000,000 lamports (0.001 SOL)
  • All transactions must pass simulation — if any fails, the entire bundle will not land on chain

Response Contract

A successful response confirms the bundle was received, validated, and relay submission was started locally. It does not guarantee relay acceptance or on-chain landing.

{
  "jsonrpc": "2.0",
  "result": [
    "38GSYbRqgStBi1t7EnCuxhcWK5gqoRDvMzqouZUz7HuXvCn2zZGeA94qrnCUkoqfqdYGmrXhEouQNNfPMUdiXWBm",
    "65YXFi1ytULbugsBhc9PLE13hsFU24KuvS3NAbxZyt5tS6ossQz3QoYbhdCa2nSaTYNpTyLRjnbVmgZvbEU9ZsX"
  ],
  "id": 1
}

result is the ordered list of base58 transaction signatures from the customer-supplied bundle payloads.

Status codes:

  • 200 OK — bundle validated and accepted for asynchronous relay submission
  • 400 Bad Request — malformed transactions, missing tip, bundle too large, or other invalid request data
  • 403 Forbidden — API key does not have sendBundle scope enabled
  • 429 Too Many Requests — rate limited
  • 503 Service Unavailable — no eligible bundle relay is configured for the request, or the endpoint is shutting down

How /sendBundle differs from other send methods

/send/sendBatch/sendBundle
Transactions per request1Up to 16Up to 4
ExecutionIndividualIndividual (no atomicity)Sequential and atomic
Wire formatJSON-RPC or binaryBinary (length-prefixed frames)JSON-RPC
Tip required inThe transactionThe transactionAt least one transaction in the bundle

For details on /sendBatch, see the Batch Send API page.

Example

import requests
import base64

# Assume tx1 and tx2 are already signed Transaction objects
tx1_bytes = bytes(tx1.serialize())
tx2_bytes = bytes(tx2.serialize())

payload = {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "sendBundle",
    "params": [
        [
            base64.b64encode(tx1_bytes).decode("utf-8"),
            base64.b64encode(tx2_bytes).decode("utf-8"),
        ],
        {"encoding": "base64"}
    ]
}

response = requests.post(
    "http://fra.lunar-lander.hellomoon.io/sendBundle?api-key=YOUR_KEY",
    json=payload,
)

print(response.json())
const tx1Base64 = Buffer.from(tx1.serialize()).toString("base64");
const tx2Base64 = Buffer.from(tx2.serialize()).toString("base64");

const response = await fetch(
  "http://fra.lunar-lander.hellomoon.io/sendBundle?api-key=YOUR_KEY",
  {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      jsonrpc: "2.0",
      id: 1,
      method: "sendBundle",
      params: [[tx1Base64, tx2Base64], { encoding: "base64" }],
    }),
  }
);

const result = await response.json();
console.log(result);

Frequently Asked Questions

Do I pay if my bundle doesn't land?

No. Tips are paid via transfer instructions within the bundle transactions. If the bundle doesn't land, no transactions execute and you pay nothing.

Can I check the status of my bundle?

Bundle status tracking is not currently available through Lunar Lander. We recommend confirming your transactions landed by checking the signatures on-chain via your preferred RPC endpoint.

What happens if one transaction in my bundle fails simulation?

The entire bundle is rejected. All transactions must pass simulation for the bundle to be submitted.