Skip to main content

API Reference

Orderflow​

BuilderNet provides these APIs to send orderflow:

Market data is available from the read-only quote stream.


eth_sendBundle​

You can use eth_sendBundle to send a bundle of transactions to BuilderNet. You can also use it to replace or cancel past bundles.

Transactions sent with eth_sendBundle are eligible for refunds.

What is a bundle

A bundle is a list of signed transactions that are executed atomically. If any transaction in the bundle fails, the entire bundle fails. This is useful for sending multiple transactions that depend on each other.

Request ​

{
"id": 1,
"jsonrpc": "2.0",
"method": "eth_sendBundle",
"params": [{
txs // Array[String], A list of signed transactions to execute in an atomic bundle.
blockNumber // String, A hex encoded block number for which this bundle is valid on.

// Optional fields
replacementUuid // String, UUID that can be used to cancel/replace this bundle.
replacementNonce // Number, Used to order bundles sharing the same replacementUuid. Bundles received with a lower replacementNonce than the latest accepted one are ignored.

revertingTxHashes // Array[String], A list of tx hashes that are allowed to revert.
droppingTxHashes // Array[String], A list of tx hashes that can be removed from the bundle if it's deemed useful (but not revert).
refundTxHashes // Array[String], A list of tx hashes (max 1) that should be considered for MEV refunds. If empty, defaults to the last transaction in the bundle.

minTimestamp // Number, The minimum timestamp for which this bundle is valid, in seconds since the unix epoch.
maxTimestamp // Number, The maximum timestamp for which this bundle is valid, in seconds since the unix epoch.

refundPercent // Number (integer between 1-99), How much of the total priority fee + coinbase payment you want to be refunded for.
refundRecipient // String, The address that the funds from refundPercent will be sent to. If not specified, they will be sent to the from address of the first transaction.
delayedRefund // Boolean, If true, `refundPercent` refund is processed asynchronously via BuilderNet refund pipeline rather than in the same block.

refundIdentity // String, Address that BuilderNet refunds should be sent to instead of the bundle signer.

// Target pools (requires "version": "v2")
version // String, Bundle format version. Set to "v2" to use the target pool fields below.
desiredState // String, Desired placement of the bundle. Set to either "BottomOfBlock" for consideration at only the bottom of the block or "AnyPosition" for consideration intrablock and bottom of the block.
targetAddresses // Array[String], A list of contract addresses (e.g., AMM pools) whose state this bundle targets.
targetSlots // Array[Array[String]], Hex encoded storage slots to target per address, index-aligned with targetAddresses. An empty array targets all slots of that address.
}]
}

Notes:

  • blockNumber can be:
    1. A specific block number, hex encoded (e.g. 0x1361bd3)
    2. For next block only: "0x" or null or missing field
  • uuid is supported as alias for replacementUuid.

Compatibility methods:

For compatibility with other builders, BuilderNet also accepts eth_sendEndOfBlockBundle (alias eth_sendBobBundle). It takes the same bundle object as eth_sendBundle, with targetPools as an alias for targetAddresses:

{
"id": 1,
"jsonrpc": "2.0",
"method": "eth_sendEndOfBlockBundle",
"params": [{
txs // Array[String], A list of signed transactions to execute in an atomic bundle.
blockNumber // String, A hex encoded block number for which this bundle is valid on.
targetPools // Array[String], (Optional) A list of pool addresses this bundle targets.
}]
}
  • With targetPools, the bundle is considered at any position in the block, equivalent to desiredState: "AnyPosition".
  • Without targetPools, the bundle is only considered at the bottom of the block.
  • targetPools must be set inside the bundle object. If it is passed as a separate positional parameter, it is ignored and the bundle is only considered at the bottom of the block.

We recommend eth_sendBundle with "version": "v2" instead, which lets you choose desiredState and target specific storage slots with targetSlots.

Bundle replacement and cancellation:

  • Replacing bundles: Send another bundle with the same replacementUuid , and it will override any previous one.
  • Cancelling bundles: Send another bundle with the same replacementUuid and an empty list of transactions.

MEV Refunds:

When a searcher makes money by using some user tx, it pays the builder to be included in the block. Part of that payment is refunded to the user. To determine how much the searcher paid the builder, we check the delta in the builder's balance before and after executing a particular tx in the bundle. By checking this delta, we are considering gas payments and also explicit transfers from the searcher to the builder.

These refunds should not be confused with redistributions.

  • refundTxHashes field (optional): Specifies which transaction in the bundle should be analyzed to measure the payment to the builder.

    • If present, specifies which transactions in the bundle should be considered for refund calculations.
    • If empty or not specified, defaults to the last transaction in the bundle.
    • Currently limited to a maximum of 1 transaction hash.
  • refundPercent field:

    • (Optional) An integer between 1-99 which defines how much of the total priority fee + coinbase payment you want to be refunded for.
    • Example: If a bundle pays 0.2 ETH of priority fee plus 1 ETH to coinbase, a refundPercent set to 50 will result in a transaction being appended after the bundle, paying 0.59 ETH back to the EOA. This is assuming the payout tx will cost BuilderNet 0.01 ETH in fees, which are deducted from the 0.6 ETH payout.

Response ​

The response always contains the bundles unique hash which can then be used to query refunds. It also contains receivedTimestampMs, a Unix timestamp in milliseconds indicating when BuilderNet received the bundle. The value is a number and may include fractional milliseconds for microsecond precision.

{
"id": 1,
"jsonrpc": "2.0",
"result": {
"bundleHash": "0x...",
"receivedTimestampMs": 1718030000123.456
}
}

Example request ​

curl https://rpc.buildernet.org \
--header 'Content-Type: application/json' \
--header 'X-Flashbots-Signature: <public key address>:<signature>' \
--data '{
"id": 1,
"jsonrpc": "2.0",
"method": "eth_sendBundle",
"params": [{
"blockNumber": "0x1361bd3",
"txs": [
"0x100000...",
"0x200000..."
]
}]
}'

See this example Golang code for sending a transaction with a signed request.

Request signature and authentication ​

eth_sendBundle requests require a X-Flashbots-Signature header for authentication and for the signer to receive refunds:

X-Flashbots-Signature: <public_key_address>:<signature>

The signature is calculated by taking the EIP-191 hash of the json body encoded as UTF-8 bytes. Any valid ECDSA secp256k1 key (i.e. any Ethereum key) can be used to sign the payload. The address associated with this key will be used for Redistribution. For more details and examples on signing the payload, see the documentation here.

Example Golang code ​

See this example Golang code for sending a signed transaction to a builder node.

Bundle Hash​

"bundle hash" is a unique identifier for a specific bundle of transactions sent to BuilderNet. It is returned as response of the eth_sendBundle RPC call.

You can use this hash to look up refunds for a specific bundle by using the buildernet_getFeeRefundsByBundle API.

See the reference implementation in FlowProxy. Note that the implementation may change over time, and we recommend to use the hash returned by the eth_sendBundle RPC call directly.


eth_sendRawTransaction​

You can use eth_sendRawTransaction to send a single signed transaction to BuilderNet.

Transactions sent with eth_sendRawTransaction are NOT eligible for refunds.

Transactions sent this way are:

  • not sent to the mempool.
  • propagated to other BuilderNet builder nodes.
  • tried to include for up to 5 blocks.
Request ​
{
"id": 1,
"jsonrpc": "2.0",
"method": "eth_sendRawTransaction",
"params": ["0x000000..."]
}
Response ​

The response contains the transaction hash:

{
"id": 1,
"jsonrpc": "2.0",
"result": "0x000000..."
}
Request signature and authentication ​

eth_sendRawTransaction requests also require a X-Flashbots-Signature header for authentication. For more details, see the relevant section for eth_sendBundle.


Priority updates​

A priority update is a transaction that BuilderNet includes ahead of other transactions accessing the same state. Market makers use priority updates to run propAMMs (proprietary AMMs): onchain pools whose quotes are refreshed offchain many times per slot. The builder guarantees that takers trade against the freshest posted quote.

Priority update transactions must post data through the Priority Update Registry, which scopes the state an update can write.

These updates can be configured in one of two modes:

  • Conditional: the update lands only if a transaction consuming it is also included in the same block, so the maker pays gas only on fills. Conditional updates are not guaranteed to be at the top of the block. This is the main way to use priority updates.
  • Top-of-Block: the update lands at the top of the next block, unconditionally. The maker pays gas every block the update lands.

The implementation is new and exact behaviour is subject to change. Feedback welcome.

When multiple updates for the same state are available at the time a block is built, the builder will prioritise the latest update.

The mode is set per API key. This requirement may be dropped in future. Updaters needing both modes can request multiple keys.

Reach out to get API keys (see How to participate).

Pricing ​

Priority update transactions pay no priority fees. Makers are charged a volume-based fee on filled trades. Reach out for pricing.

Taker speed bump ​

A taker transaction that touches priority-update state is only eligible for inclusion once the builder has held it for at least 50 ms. This protects makers from takers attempting to snipe stale quotes.

How conditional inclusion works ​

Each maker registers one or more event signatures (a contract address and an event topic) that identify the event their pool emits when a swap consumes a quote. A conditional update is included only when a transaction in the block emits a matching log.

What this means for integrators:

  • Makers: register your consumption events when your conditional API key is provisioned. Without a registered event, conditional updates never land. We plan to upgrade the event registration flow soon.
  • Pool authors: emit a distinct event on the fill path, not in view or quote paths.
  • Takers and routers: nothing. Consumption is detected from the fill's logs automatically.

The optional asset_pairs, quote_address and pool_addresses request fields are recorded as metadata and do not currently affect inclusion.

Endpoints ​

Priority updates are submitted over WebSocket on the same hosts as the JSON-RPC endpoints (see BuilderNet endpoints) at the path /ws/sendquoteupdate, e.g. wss://rpc.buildernet.org/ws/sendquoteupdate.

Request ​

Messages are protobuf-encoded:

message PWebsocketQuoteUpdateV1Args {
bytes tx = 1; // RLP-encoded quote tx (empty for cancellation)
uint64 block_number = 2; // Target block
bytes replacement_uuid = 3; // 16-byte quote identifier
uint64 replacement_seq_number = 4; // Monotonic sequence (>0)
bool disable_cross_region_sharing = 5;
// Optional PropAMM metadata.
// Pairs affected by this update. Each entry is 40 bytes: token0 || token1.
repeated bytes asset_pairs = 6;
// 20-byte address a taker must touch to receive a quote.
bytes quote_address = 7;
// Pool addresses whose swaps require this update. Each entry is 20 bytes.
repeated bytes pool_addresses = 8;
}

Replacement and cancellation:

  • Replace: send a new message with the same replacement_uuid and a higher replacement_seq_number.
  • Cancel: same as replace, but with an empty tx.

Response ​

message PWebsocketQuoteUpdateV1Response {
bytes replacement_uuid = 1;
uint64 replacement_seq_number = 2;
uint64 timestamp = 3; // RPC receive time (UNIX nanos)
string error = 4; // Error details on failure
}

Authentication ​

Set the API key in the Authorization header when establishing the WebSocket connection.

Submission best practices ​

  • Use one replacement_uuid per quoted instrument and increase replacement_seq_number monotonically. The builder keeps only the highest sequence number for each uuid, so refresh a quote by replacing it rather than creating a new uuid.
  • Target the next block in block_number and resend on each new head. Updates for past blocks are dropped.

State stream ​

You can subscribe to a read-only stream of the priority update state the builder would apply to the next block. Only priority updates that opt in to publishing are included in the stream. Appearing in the stream does not guarantee inclusion: conditional updates still land only when a matching consumption event is emitted.

The stream is exposed over WebSocket on the same hosts as the JSON-RPC endpoints (see BuilderNet endpoints) at the path /ws/pamm_quote_stream. No API key is required, e.g. wss://rpc.buildernet.org/ws/pamm_quote_stream.

Each message is a JSON snapshot describing the aggregated state overrides for the next block:

{
"slot": 14372440,
"blockNumber": 25137544,
"timestamp": 1779293304512809332,
"0x0000000000000000000000000000000000000000": {
"stateOverride": {
"0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640": {
"stateDiff": {
"0x0000000000000000000000000000000000000000000000000000000000000000": "0x00014402d302d301f2030bdf000000000000547eda875f9cf4410635a0b28154",
"0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000170574a8b2439b6436f669cd2f061bd02bc2",
"0x0000000000000000000000000000000000000000000000000000000000000003": "0x00000000000000000012ed16f4d0744000000000000000000000000001f1ab12"
}
}
}
}
}
FieldDescription
slotTarget slot for the snapshot.
blockNumberTarget block number.
timestampSnapshot time (UNIX nanoseconds).
0x… (address keys)A venue's stream address (see the table below); most venues have one key, Metric has one per oracle. Each maps to a stateOverride object describing the storage the builder would apply for that venue's priority updates.

The addresses in a message play different roles:

  • Top-level keys are stream addresses: a stable identifier each venue's overrides are published under (see the table below). Use them to select which venue's state to consume.
  • Keys inside stateOverride are the contract accounts whose storage the pending updates modify. The object uses the standard Ethereum state-override format: each account maps to a stateDiff, which maps 32-byte storage slots to their 32-byte values. It can be passed directly as the state-override parameter to eth_call or eth_simulateV1 to quote against next-block state.

propAMM stream addresses ​

Venues that use the shared Priority Update Registry write 0xDa7AfEeD021EAFC1c1Af9C362dE477DaD0396B81, which replaced 0xda7afeed01fe625cf15d187a19f94b45f00b8c5f on 2026-09-15; the others write their own pricing contract. buildernet_getPammStateOverrides on https://rpc.buildernet.org/pamm/rpc returns the current snapshot on demand.

Venues (as of 2026-09-29):

VenueStream address (top-level key)State override target
FermiSwap0x5979458912F80B96d30D4220af8E2e4925A33320 (pool and router)0x0109AA912B58508886a2a707204B0F8C8b164CCc (pricing engine)
Tempest (Flowdesk)0x00000003f1EC2379e79F58E12eC6c4F51ee921490xDa7AfEeD021EAFC1c1Af9C362dE477DaD0396B81 (Priority Update Registry)
Bebop0xB09999A44e3240193193Be9dD99CC73c8cc945A6 (pricing contract; swaps on 0xB09AAA8933626d7E4C48D65dAd2D77021CFBCA9a)0xDa7AfEeD021EAFC1c1Af9C362dE477DaD0396B81 (Priority Update Registry)
Kipseli0xC9A956b5196DFe110DEBE8781857Bc8B97d32091 (price oracle; router 0x342b8458161137d0203605Fa51E4363c1445ADCD)0xDa7AfEeD021EAFC1c1Af9C362dE477DaD0396B81 (Priority Update Registry)
El Zorro0xcf211b4dd0d2be5c173ea57bcf938fc61d1d3bd3 (pool and router)0xDa7AfEeD021EAFC1c1Af9C362dE477DaD0396B81 (Priority Update Registry)
TaurusFi0x217d58931a8549ca539426aa8152e33dafc3d95a0xDa7AfEeD021EAFC1c1Af9C362dE477DaD0396B81 (Priority Update Registry)
Metricone key per oracle: 0xe844701934d9c6085b292e428f41b911cc0b3872 (CompressedOracleV1) and 0x30a88bf894d1b806125a23ebf23d715496fd7102 (PythOracle)the same oracle

Superseded addresses, no longer used: Bebop 0xB0999914B3DE1be58Ef2416af09Bd2E7F8AaD03C, Kipseli 0xfe3d12b21d2602868223e83149bdbbfb5d11e185, and the previous registry instance 0xda7afeed01fe625cf15d187a19f94b45f00b8c5f.

Routing against propAMMs ​

propAMM liquidity is ordinary onchain liquidity, and any contract can fill against it. The IPropAMM interface provides a common way to discover, quote, and swap against propAMMs. The Lambda Class PropAMMRouter is a reference integration: a single-hop router that quotes and executes against a propAMM and falls back to Uniswap V3 when the propAMM can't fill.

We are also building just-in-time routing: route selection at block building time, so takers get filled against the freshest propAMM quotes and onchain state. This leads to tighter spreads and lower revert rates. Reach out if you want to integrate early.


Refunds​

note

Refund APIs should be queried at https://relay.flashbots.net.

BuilderNet provides these APIs to check refunds data:


buildernet_getFeeRefundTotalsByRecipient​

The buildernet_getFeeRefundTotalsByRecipient JSON-RPC method returns the total amount of fee refunds that have been earned by a specific address.

{
"jsonrpc": "2.0",
"id": 1,
"method": "buildernet_getFeeRefundTotalsByRecipient",
"params": [
recipient, // String, the address to query for fee refunds
]
}

The response contains three fields:

{
"pending":"0x17812ea4fbbe314",
"received":"0x108d1b27b63a213",
"maxBlockNumber":"0x13ddb08"
}
  • pending: the total amount of fee refunds that have been earned but not yet received by the recipient
  • received: the total amount of fee refunds that have been received by the recipient
  • maxBlockNumber: the highest block number for which fee refunds have been processed

buildernet_getFeeRefundsByRecipient​

The buildernet_getFeeRefundsByRecipient JSON-RPC method returns detailed information about fee refunds that have been earned by a specific address. Our refund process usually calculates these values with a 4 hour delay.

{
"jsonrpc": "2.0",
"id": 1,
"method": "buildernet_getFeeRefundsByRecipient",
"params": [
recipient, // String, the address to query for fee refunds
cursor, // [optional] String, the cursor to continue from
]
}

Responses are paginated and contain the following fields:

{
"refunds": [
{
"hash": "0x...",
"amount": "0x...",
"blockNumber": "0x13ddaa4",
"status": "sent",
"recipient": "0x...",
"refundTxHash": "0x...",
"refundTxBlockNumber": "0x...",
"refundTxStatus": "confirmed"
},
...
],
"cursor": "0x..."
}

The "refunds" field contains an array of per-order fee refunds, each with the following fields:

  • hash: the bundle hash or transaction hash associated with the fee refund
  • amount: the amount of the fee refund, in wei
  • blockNumber: the block number the order was contained in
  • status: the status of the fee refund, either "pending" or "sent"
  • recipient: the address the fee refund is credited to, either the bundle signer or transaction sender
  • refundTxHash, refundTxBlockNumber, refundTxStatus: the payout transaction, once the fee refund has been sent

The "cursor" field is only included if there are more fee refunds to fetch. To continue fetching fee refunds, include the cursor as the second argument in the next request.

NOTE: This API currently only returns details for bundles included in block 20802497 and later. To see total fee refunds processed for a specific address since inception, use the buildernet_getFeeRefundTotalsByRecipient method.

buildernet_getFeeRefundsByBundle​

The buildernet_getFeeRefundsByBundle is similar to buildernet_getFeeRefundsByRecipient but returns result for the given bundle.

{
"jsonrpc": "2.0",
"id": 1,
"method": "buildernet_getFeeRefundsByBundle",
"params": [
bundle_hash, // String, the hash of the bundle
]
}

buildernet_getFeeRefundsByBlock​

The buildernet_getFeeRefundsByBlock is similar to buildernet_getFeeRefundsByRecipient but returns result for the given block.

{
"jsonrpc": "2.0",
"id": 1,
"method": "buildernet_getFeeRefundsByBlock",
"params": [
block_number, // String, hex-encoded block number (e.g. 0x15d0280)
]
}

buildernet_setFeeRefundRecipient​

The buildernet_setFeeRefundRecipient JSON-RPC method allows a user to "delegate" their fee refunds to a specific wallet address. Two addresses must be provided, the first is the address associated with the signing key used to authenticate your request, while the second is the address to send refunds to.

{
"jsonrpc": "2.0",
"id": 1,
"method": "buildernet_setFeeRefundRecipient",
"params": [
"0xD2824D2D7D6399a4b9A47F258B870D2AFb213948",
"0xa273A268CE96E54cF6a7D879B7d016F57E396F48"
]
}

If the first address matches the authentication signature, then a response with from and to fields in the result will be returned:

{
"jsonrpc": "2.0",
"id": 1,
"result": {
"from":"0xd2824d2d7d6399a4b9a47f258b870d2afb213948",
"to":"0xa273a268ce96e54cf6a7d879b7d016f57e396f48"
}
}

If the signature is invalid or does not match the first address, an appropriate error will be returned instead.

buildernet_getDelayedRefunds​

The buildernet_getDelayedRefunds JSON-RPC method returns detailed information about delayed refunds.

{
"jsonrpc": "2.0",
"id": 1,
"method": "buildernet_getDelayedRefunds",
"params": [
{
recipient, // String, the address that receives delayed refunds
blockRangeFrom, // [optional] String, hex-encoded block number for the start of the range (inclusive)
blockRangeTo, // [optional] String, hex-encoded block number for the end of the range (inclusive)
cursor, // [optional] String, the cursor to continue from
hash, // [optional] String, bundle hash; if provided, you must also set both blockRangeFrom and blockRangeTo
}
]
}

Responses are paginated and contain the following fields:

{
"refunds": [
{
"amount": "0x...",
"blockNumber": "0x13ddaa4",
"hash": "0x...",
"recipient": "0x...",
"status": "pending"
},
...
],
"nextCursor": "0x...",
"indexedUpTo": "0x..."
}

The "refunds" field contains an array of per-order fee refunds, each with the following fields:

  • amount: the amount of the delayed refund, in wei
  • blockNumber: the block number the order was contained in
  • hash: the bundle hash that generated delayed refund
  • status: the status of the delayed refund, either "pending" or "received"
  • recipient: the address the delayed refund is credited to

The "nextCursor" field is only included if there are more delayed refunds to fetch, or if more data might become available in the future. To continue fetching, pass its value as the cursor field in the next request. If the response is empty but contains nextCursor, retry later.

"indexedUpTo" contains maximum block number for which delayed refunds are indexed

buildernet_getDelayedRefundTotalsByRecipient​

The buildernet_getDelayedRefundTotalsByRecipient JSON-RPC method returns the total amount of delayed refunds that have been earned by a specific address.

{
"jsonrpc": "2.0",
"id": 1,
"method": "buildernet_getDelayedRefundTotalsByRecipient",
"params": [
{
recipient, // String, the address to query for delayed refunds
blockRangeFrom, // [optional] String, hex-encoded block number for the start of the range (inclusive)
blockRangeTo, // [optional] String, hex-encoded block number for the end of the range (inclusive)
}
]
}

The response contains three fields:

{
"indexedUpTo":"0x13ddb08",
"pending":"0x17812ea4fbbe314",
"received":"0x108d1b27b63a213"
}
  • indexedUpTo: the highest block number for which delayed refunds have been processed
  • pending: the total amount of fee refunds that have been earned but not yet received by the recipient
  • received: the total amount of fee refunds that have been received by the recipient