# Welcome to Pod

The network for high-performance, MEV-free, global markets

Pod Network is a purpose-built network for high-performance, MEV-free markets. It has no blocks or chains - transactions are streamed to a geo-distributed validator set, which independently validates them and streams attestations back. Once a quorum of attestations is collected, the transaction is final. Confirmation takes a single network round trip (\~150ms) and the network can sustain 300k+ transactions per second.

Trades are matched via frequent batch auctions at a uniform clearing price, which structurally prevents MEV. The protocol exposes a set of asset-agnostic, composable primitives - including the order book, matching engine, liquidation engine, and oracle system. Pod provides an Ethereum-compatible interface - developers use standard JSON-RPC, wallets, and EVM tooling out of the box.

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Network Architecture</strong></td><td>Learn how Pod's streaming, consensus-less protocol works under the hood.</td><td><a href="https://docs.v2.pod.network/documentation">https://docs.v2.pod.network/documentation</a></td></tr><tr><td><strong>Markets</strong></td><td>Enshrined market primitives, batch auction matching, and MEV elimination.</td><td><a href="https://docs.v2.pod.network/documentation/markets/markets-overview">https://docs.v2.pod.network/documentation/markets/markets-overview</a></td></tr><tr><td><strong>Getting Started</strong></td><td>Devnet config, JSON-RPC endpoints, precompiles, and developer guides.</td><td><a href="https://github.com/podnetwork/pod-sdk/blob/main/doc/api-reference/README.md">https://github.com/podnetwork/pod-sdk/blob/main/doc/api-reference/README.md</a></td></tr></tbody></table>


# Trading Competition

A three-week trading competition hosted at [**test.pod.network**](https://test.pod.network). Highest absolute P\&L at the end wins a **Rolex Submariner Ref: 124060**.

|                  |                                                       |
| ---------------- | ----------------------------------------------------- |
| **Starts**       | Wednesday, June 3, 2026, 12PM UTC                     |
| **Ends**         | Wednesday, June 24, 2026, 12PM UTC                    |
| **Site**         | [test.pod.network](https://test.pod.network)          |
| **Prize**        | Rolex Submariner Ref: 124060                          |
| **Registration** | Open to anyone meeting the eligibility criteria below |

{% hint style="warning" %}
**Testnet reset at start.** At the start of the competition the Pod testnet will be reset. All balances and positions from before the start will be wiped.
{% endhint %}

## Eligibility

To register, your X (Twitter) account must satisfy at least one of:

* X premium account, **or**
* More than 100 followers

One person may register **one account only**. Any sybil behavior (multiple registrations by the same person, coordinated accounts, etc.) will be disqualified.

One X account can be linked to **one wallet** only.

## Starting balance

Every registered participant gets paper testnet USD to trade with. The starting balance depends on when and how you joined:

| Participant                              | Starting balance |
| ---------------------------------------- | ---------------- |
| Registered and deposited on the waitlist | **$10,500 USD**  |
| Registered but no waitlist deposit       | **$10,000 USD**  |

{% hint style="info" %}
**Paper money only.** Competition balances cannot be withdrawn from the network or transferred between accounts. They exist purely for the duration of the competition.
{% endhint %}

## How winners are decided

At the end of the three weeks, each registered account is scored by **absolute P\&L** — the change in total account value (cash + open positions, marked to market) from the participant's starting balance.

The highest absolute P\&L wins the Rolex Submariner Ref: 124060. The winner will be contacted by **DM from the official Pod X account** to their verified X account to arrange delivery of the prize.

## Rules summary

* One person, one account. Sybil entries are disqualified.
* One X account is linked to one wallet for the duration of the competition.
* Paper testnet balances are non-withdrawable and non-transferable.
* The testnet resets at the start — there is no carryover from prior testnet activity.

## Legal

By registering, participants agree to the [Official Rules](https://app.pod.network/terms?tab=challenge), the [Terms of Use](https://pod.network/terms), and the [Privacy Policy](https://pod.network/terms?tab=privacy). The Official Rules govern the competition and prevail in case of any conflict with the summary above.

## Next steps


# Support

Help with common issues you may run into while using Pod.

* [Reset your wallet after a testnet reset](https://github.com/podnetwork/pod-sdk/blob/main/doc/support/reset-wallet.md) — fix nonce mismatches and stuck transactions after the Pod testnet is reset.


# Support

Help with common issues you may run into while using Pod.

* [Reset your wallet after a testnet reset](/home/support/reset-wallet) — fix nonce mismatches and stuck transactions after the Pod testnet is reset.


# Reset your wallet after a testnet reset

Pod's testnet is periodically reset — for example, at the start of the [Trading Competition](broken://pages/295Ewm0Vl7WJ8NPEqcJC). When a reset happens, all on-chain state is wiped: balances, positions, and account nonces are cleared and start fresh.

Your wallet itself (your private key / seed phrase) is not affected, but your wallet's local view of the network can become out of sync with the freshly reset testnet. The most common symptom is a **nonce mismatch** — your wallet still remembers the transaction count from before the reset, so new transactions are rejected or stuck pending.

To fix this you need to reset your wallet's account data so it re-reads the nonce and balances from the reset network.

## Steps (Rabby)

1. Open **Settings**.
2. Select **Clear Pending Locally**.
3. Check the box **"Also reset my local nonce data and signature record"**.
4. Click **Confirm**.

Rabby will clear its cached nonce and re-read your account state from the reset network.

{% hint style="info" %}
Clearing pending data only removes Rabby's local transaction history and cached nonce. It does not delete your account or private key.
{% endhint %}

The video below walks through the same steps:

{% embed url="<https://www.youtube.com/shorts/t5gkDYd19VI>" %}
How to reset your wallet for Pod after a testnet reset
{% endembed %}


# Protocol Overview

Pod uses a Byzantine fault-tolerant protocol that can tolerate up to 1/5 of validators acting adversarially. Unlike traditional blockchains, Pod's core protocol does not totally order transactions. This relaxation is what allows Pod to confirm transactions in a single network round trip, achieving latencies of \~150ms, bounded only by network propagation delay.

Pod does not have blocks or chains. Clients send transactions directly to the validator set. Each validator independently validates, timestamps, and signs the transaction, streaming attestations back to the client. Once attestations from a sufficient quorum are collected, the transaction is final. This entire flow completes in one round trip. See [Transaction Flow](/documentation/core/transaction-flow) for a detailed walkthrough.

## Why Pod is Fast

Consensus protocols totally order transactions, which requires a leader to propose blocks and multiple rounds of communication between validators to commit them. This coordination is expensive - every additional round adds at least one network hop of latency, and the leader becomes a throughput bottleneck since all transactions must flow through it. Pod avoids this by being coordination-free: validators do not communicate with each other to process a transaction. Instead, application-level invariants - double-spend prevention, balance checks, auction deadlines - are designed so they can be verified independently by each validator without requiring a shared global order. This is possible because Pod's core primitives (payments, token transfers, order submissions) are commutative or deadline-bound, so their correctness does not depend on the order in which validators see them. The result is that confirmation takes a single network round trip, bounded only by propagation delay.

Not every application can be built fully coordination-free. This is a new paradigm, and applications must be carefully designed to exploit it. Pod's enshrined primitives are built this way from the ground up. Applications that require strict global ordering can use [ordering gadgets](https://youtu.be/1aCiPb266Uw?si=AMAfRAOw6Y5WD5PK) - sequencers that transactions pass through before reaching validators. The sequencer is trusted only for liveness, not for equivocation - it can go offline but it cannot reorder or censor without detection.

## Design Principles

**Streaming** - Pod uses a publish/subscribe model over persistent connections. Validators stream attestations, state updates, and events to clients as they become available, rather than batching them into blocks at fixed intervals.

**Enshrined Market Primitives** - The protocol includes a built-in [order book](/documentation/markets/orderbook) with batch auction matching, [perpetuals](/documentation/markets/perpetuals), [optimistic auctions](/documentation/markets/optimistic-auctions), liquidation and margin engines, pricing oracles, and a [token](/documentation/markets/fungible-tokens) model. All expose standard Ethereum interfaces.

**MEV-Free** - Transactions are finalized without going through a centralized entity (e.g. leader or sequencer). All validators receive transactions simultaneously. The matching engine uses batch auctions where orders compete on price alone, independent of submission time or latency. This [eliminates MEV](/documentation/markets/markets-overview#why-pod-has-no-mev) structurally.

## Navigating the Docs

**Network** - the core consensus and infrastructure layer:

* [Network Architecture](/documentation/core/network-architecture) - entities in the network and how they interact
  * [Transaction Flow](/documentation/core/transaction-flow) - submission, attestation, finality, and recovery
  * [Local Ordering](/documentation/core/local-ordering) - per-account ordering, nonces, and the partial order model
  * [Censorship Resistance](/documentation/core/censorship-resistance) - how the leaderless design guarantees liveness
* [Native Bridge](/documentation/core/native-bridge) - deposit and withdrawal flows between Ethereum and Pod

**Markets** - the enshrined market primitives:

* [Overview](/documentation/markets/markets-overview) - enshrined market infrastructure and MEV elimination
* [Orderbook](/documentation/markets/orderbook) - the enshrined CLOB, order types, and batch auction matching
* [Perpetuals](/documentation/markets/perpetuals) - mark price and funding
* [Margin](/documentation/markets/margin) - cross margin, margin requirements, liquidation, and ADL
* [Optimistic Auctions](/documentation/markets/optimistic-auctions) - censorship-resistant auctions with off-Pod settlement
* [Tokens](/documentation/markets/fungible-tokens) - the native token model


# Network Architecture

Pod Network consists of four types of entities: **clients**, **full nodes**, **validators**, and the **native bridge** on Ethereum.

```mermaid
sequenceDiagram
    actor C as Client
    participant F as Full Node
    participant V@{ type: "collections", alias: "Validators" }
    participant B as Bridge Contract (Ethereum)

    V->>B: subscribe to deposit events
    F->>V: subscribe to votes

    C->>B: deposit ERC-20
    B->>V: deposit event
    V->>V: credit balance

    C->>+F: send transaction (JSON RPC)
    F->>V: broadcast transaction
    V->>F: broadcast attestations
    F->>-C: transaction confirmed

    

    C->>F: get claim proof
    C->>B: claim tokens
```

## Clients

Clients submit transactions to full nodes via JSON-RPC using standard Ethereum tooling (`ethers.js`, `viem`, `web3.py`, `alloy`). After submission, the client receives a stream of attestations from the validator set. Once a quorum of attestations is collected, the transaction is final.

## Full Nodes

Full nodes are the entry point to the network. They accept JSON-RPC requests from clients, broadcast transactions to the validator set, and relay attestations back. Full nodes maintain a local view of the current state but do not participate in validation.

## Validators

Validators form the core of Pod's protocol. Each validator independently receives transactions, validates them, timestamps them, and signs an attestation. Validators do not coordinate with each other before attesting - they respond directly and in parallel. A transaction is final once the client collects attestations from a supermajority (4/5) of the validator set by stake.

Validators also observe deposit events from the native bridge contract on Ethereum and credit balances accordingly.

## Native Bridge

The Pod native bridge is a smart contract deployed on Ethereum. Users deposit ETH or ERC-20 tokens into the bridge contract, which emits deposit events. Validators observe these events and increase the user's balance on Pod. Withdrawals follow the reverse flow - the user initiates a withdrawal on Pod, and once finalized, can claim their tokens from the bridge contract on Ethereum.

See [Native Bridge](/documentation/core/native-bridge) for the full deposit and withdrawal flow.


# Transaction Flow

In traditional blockchains, a transaction is sent to a mempool, picked up by a leader or sequencer, included in a block, and the block must then be confirmed through consensus. Pod skips all of this. A client sends a signed transaction to a full node, which broadcasts it to all validators. Each validator independently validates the transaction, appends it to its local log, and signs an attestation. The full node streams attestations back to the client. Once enough attestations are collected, the transaction is final.

This gives Pod two properties:

1. **Single round-trip confirmation** - a transaction is final after one network round trip (client → validators → client), with no multi-round coordination between validators.
2. **Responsiveness** - confirmation latency depends only on actual network delay, not on block intervals or timeout parameters. The client sends a transaction and receives a response, similar to querying an HTTP API.

```mermaid
sequenceDiagram
    actor C as Client
    participant F as Full Node
    participant V1 as Validator 1
    participant V2 as Validator 2
    participant Vn as Validator n

    C->>+F: send transaction (JSON-RPC)
    par broadcast to all validators
        F->>V1: transaction
        F->>V2: transaction
        F->>Vn: transaction
    end
    par each validator attests independently
        V1->>F: attestation (seq, timestamp, sig)
        V2->>F: attestation (seq, timestamp, sig)
        Vn->>F: attestation (seq, timestamp, sig)
    end
    F->>-C: transaction final (n - f attestations)
```

## 1. Submission

The client signs a transaction and sends it to a full node via JSON-RPC. The full node broadcasts the transaction to all validators in the network simultaneously.

## 2. Validation and Attestation

Each validator independently receives the transaction and:

1. **Validates** the transaction - this includes verifying the client's signature, checking the nonce, ensuring sufficient balance, and any application-specific validation (e.g. order book rules).
2. Appends it to its local **temporal log** - a per-validator, totally ordered sequence of transactions.
3. Signs an **attestation** containing:
   * The transaction hash
   * A **sequence number** - the position of the transaction in this validator's temporal log
   * A **timestamp** - the validator's local time when the transaction was appended

The validator broadcasts its attestation to all other validators and full nodes. No validator waits for or communicates with other validators before attesting.

## 3. Finality

The full node streams attestations back to the client as they arrive. A transaction is **final** once it has collected **n - f** attestations from the validator set, where **n** is the total number of validators and **f** is the maximum number of Byzantine validators the network tolerates.

With a 5f + 1 validator set, this means a supermajority of 4/5 of validators by stake must attest for finality. Once this threshold is reached, the transaction cannot be reverted - even if the remaining validators are adversarial.

The collection of n - f attestations forms a **finality certificate** that is verifiable outside Pod. Any external system (a smart contract on Ethereum, a TEE enclave, a ZK circuit) can check the certificate to confirm a transaction was finalized on Pod without trusting a relay or intermediary.


# Local Ordering

Pod uses the transaction nonce to locally order transactions per account. The nonce serves two purposes:

1. **Per-account sequencing** - since there is no global ordering of transactions, the nonce establishes a sequence within each account, ensuring transactions execute in the order the user intended.
2. **Consistency** - the network maintains a single chain of transactions per account. This prevents double-spending and maintains consistency for single-writer state.

Because ordering is local to each account, validators do not need to coordinate with each other to agree on a global order. This is what enables single round-trip confirmation.

## Nonce Check

When a validator receives a transaction, it checks that the transaction's nonce matches the account's current expected nonce. If it doesn't match, the transaction is rejected. If it matches, the validator proceeds with the additional checks.

This ensures that for any given account and nonce, at most one transaction can collect n - f attestations. If a client submits two conflicting transactions at the same nonce, different validators may vote for different ones, but no two conflicting transactions can reach the finality threshold simultaneously.

## Account Locking and Recovery

If a client submits conflicting transactions at the same nonce - whether intentionally or due to a crash (e.g. restarting without persisting client state) - the account may become **locked**. The nonce cannot advance and no future transactions can be processed.

The existing consensusless literature addresses this by falling back to a consensus protocol to resolve the conflict. Pod follows a different approach; Pod utilizes a built-in recovery protocol that resolves account locking in **one network round trip**, without invoking consensus or relying on a centralized party.

To recover, the client:

1. Calls `pod_getRecoveryTargetTx(account)` on the full node to fetch a valid target transaction to recover to.
2. Sends a transaction to the **recovery precompile** at `0x0000000000000000000000000000000004EC0EE4`, calling `recover(txHash, nonce)`.

The target transaction points to the valid tip of a chain of transactions that can all be finalized. The protocol executes this chain, recovers the account state to the state after executing the target transaction, and increments the nonce. The client can then sign a new transaction with the next nonce (stuck nonce + 1) and continue transacting normally.

Note that recovery itself is a transaction, so a client can get locked again if it submits multiple conflicting recovery transactions and none of them reach quorum. The protocol handles this - the client simply initiates recovery again, and the new target transaction will account for the full chain including prior recovery attempts.

See [Recover a locked account](https://docs.v2.pod.network/guides-references/guides/recover-locked-account) for a step-by-step guide with code examples.

## References

The local ordering model and recovery protocol build on a line of research in consensusless Byzantine fault-tolerant protocols:

* **FastPay** - M. Baudet, G. Danezis, A. Sonnino. *FastPay: High-Performance Byzantine Fault Tolerant Settlement.* 2020. [arXiv:2003.11506](https://arxiv.org/abs/2003.11506)
* **ABC** - J. Sliwinski, R. Wattenhofer. *ABC: Proof-of-Stake Without Consensus.* 2019. [arXiv:1909.10926](https://arxiv.org/abs/1909.10926)
* **Sui Lutris** - S. Blackshear, A. Chursin, G. Danezis et al. *Sui Lutris: A Blockchain Combining Broadcast and Consensus.* 2024. [arXiv:2310.18042](https://arxiv.org/abs/2310.18042)
* **Pod** - O. Alpos, B. David, J. Mitrovski, O. Sofikitis, D. Zindros. *Pod: An Optimal-Latency, Censorship-Free, and Accountable Generalized Consensus Layer.* 2025. [arXiv:2501.14931](https://arxiv.org/abs/2501.14931)
* **Fast-Path Recovery** - S. Agrawal. *Fast-Path Recovery for Consensusless Protocols.* Master's Thesis, TU Munich, 2026. Pod's recovery precompile is based on this construction, which extends FastPay with a recovery mechanism inspired by Simplex-style view change in the 5f + 1 fault model.


# Timestamping

Timestamping allows applications to make progress based on a global time reference - for example, terminating an auction at a deadline or pricing gas based on network congestion over a given interval.

Pod provides two sources of timestamps, both with microsecond precision:

1. **Transaction timestamps** - each validator signs a local microsecond timestamp when attesting to a transaction.
2. **Heartbeat timestamps** - each validator signs a heartbeat message every \~20ms. Heartbeats are sequenced in the validator's temporal log alongside transactions.

Both timestamps, combined with the sequence numbers in each validator's temporal log, allow the network to make time-based arguments about transactions.

## Past Perfection

Applications can subscribe to a **time of interest** - for example, an auction deadline - using `pod_subscribe`. The time of interest is reached when a quorum (n - f) of validators have signed heartbeats with timestamps beyond it. At that point, the full node returns a **past perfect set** associated with that timestamp.

The past perfect set provides four properties:

1. **The time has passed** - the network has moved beyond the subscribed timestamp. Applications that need to trigger an action after a certain time (e.g. closing an auction) can rely on this.
2. **Completeness** - the past perfect set contains all transactions that could have received n - f attestations with a timestamp less than the subscribed timestamp. No additional transactions can appear (as finalized) with an earlier timestamp after the set is returned.
3. **Authenticity** - every transaction in the past perfect set was attested by at least f + 1 honest validators with a timestamp before the subscribed time. This guarantees the set only contains transactions that were genuinely submitted in time.
4. **Censorship resistance** - if a transaction was submitted sufficiently before the time of interest, it is guaranteed to be included in the past perfect set. This ensures that validators cannot selectively exclude timely transactions from the set.

## Past Perfect Certificate

The quorum of heartbeat signatures that establishes past perfection forms a **past perfect certificate**. This certificate is verifiable outside Pod - a smart contract on Ethereum, a TEE enclave, or a ZK circuit can check the n - f heartbeat signatures to independently confirm the set is final. See [Optimistic Auctions](/documentation/markets/optimistic-auctions) for how this is used in practice.


# Censorship Resistance

Censorship resistance is a critical ingredient of Pod's design. Many applications - auctions, liquidations, voting, dispute periods - require that transactions cannot be selectively excluded.

## Existing Systems

Most existing systems have a single party (the block proposer, sequencer, or leader) that decides which transactions to include in the next block. This creates a single point of censorship - the leader can delay or exclude transactions at will, and users have no recourse until the leader rotates. Depending on the protocol and network configuration, censorship can persist for seconds to minutes.

Layer-2s face a worse version of this problem. Most L2s today rely on centralized sequencers to propose all blocks. A compromised sequencer can censor transactions indefinitely. Some L2s allow force-inclusion through the L1, but with significant delays (e.g. Arbitrum: \~1 day).

## Pod's Approach

Pod has no leader. Clients broadcast transactions to all validators simultaneously, and each validator independently decides whether to attest. A transaction only needs n - f attestations to be finalized, so up to f validators can refuse to attest and the transaction still confirms. To censor a transaction, an adversary would need to break the network's liveness, which requires controlling more than f validators - violating the protocol's fault assumption.

Transactions confirm within one network round trip (2 delta). For a detailed comparison of censorship resistance properties across different consensus protocols including Pod, see [this report by Common Prefix](https://www.commonprefix.com/static/clients/flashbots/flashbots_report.pdf).

## Censorship Resistance with Time

For time-sensitive applications (e.g. an auction with a deadline), censorship resistance needs a stronger guarantee: not just that a transaction will eventually be included, but that it will be included *before a specific time*.

Pod provides this through [past perfection](/documentation/core/timestamping#past-perfection). When an application subscribes to a time of interest, the full node returns a past perfect set once that time has been reached. If a transaction was submitted sufficiently before the time of interest (delta before the deadline, where delta is the network delay between the client and the slowest honest validator), it is guaranteed to be in the past perfect set. Validators cannot selectively exclude timely transactions from the set.

[Optimistic auctions](/documentation/markets/optimistic-auctions) are a concrete application of this property: bids submitted before the auction deadline are guaranteed to be in the finalized bid set, preventing bid suppression.


# Native Bridge

Pod has a native bridge for moving ERC20 tokens between Ethereum and Pod. The bridge consists of a smart contract deployed on Ethereum and a precompile on Pod.

## Architecture

* **Ethereum bridge contract** - holds deposited tokens on Ethereum. Users deposit here to bridge into Pod, and claim here when bridging out.
* **Pod bridge precompile** - at `0x50d0000000000000000000000000000000000001` on Pod. Users call this to initiate withdrawals to Ethereum.

## Ethereum → Pod

Tokens are deposited to the Ethereum bridge contract and locked. Pod validators run Ethereum full nodes, observe finalized deposits, and automatically credit the corresponding balance on Pod.

See [Bridge to Pod](https://docs.v2.pod.network/guides-references/guides/bridge-to-pod) for a step-by-step guide with code examples.

### Deposit and Call

The Ethereum bridge contract supports depositing tokens and calling a whitelisted contract on Pod in a single transaction. This is useful for bridging tokens and immediately depositing them into the market contract without a separate step.

When calling `deposit` on the Ethereum contract, the `callContract` and `reserveBalance` parameters control this behavior:

* **`callContract`**: Address of a whitelisted contract on Pod to call with the bridged funds (e.g. the market contract). Set to `address(0)` for a normal deposit.
* **`reserveBalance`**: Amount (in the Ethereum token's units) to keep in the user's EOA on Pod. The remainder is forwarded to `callContract` via `deposit(token, amount, to)`.

For example, to bridge 1000 USDC and deposit 900 USDC into the market contract while keeping 100 USDC in your account, set `amount = 1000e6`, `reserveBalance = 100e6`, and `callContract` to the market contract address.

The `callContract` must be whitelisted by the bridge admin via `setCallContractWhitelist`. If `callContract` is `address(0)`, `reserveBalance` must be `0`.

## Pod → Ethereum

Users call `withdraw` on the Pod bridge precompile, which burns the tokens on Pod. Validators sign the withdrawal using separate cold keys (KMS-backed) dedicated to bridge attestations, distinct from transaction attestation keys. These signatures are specially packed for efficient on-chain verification. The Ethereum bridge contract checks that at least `n - f` validators signed the withdrawal - the same threshold used for transaction finality.

The `withdraw` function takes a `chainId` parameter specifying the target chain where the tokens will be claimed. This prevents the same withdrawal proof from being replayed on multiple chains when the bridge is deployed across several networks.

The user obtains the claim proof via `pod_getBridgeClaimProof(txHash)` and submits it to the Ethereum bridge contract to release the tokens. Anyone can submit the claim - it does not need to come from the original depositor.

See [Bridge from Pod](https://docs.v2.pod.network/guides-references/guides/bridge-from-pod) for a step-by-step guide with code examples.

## Decimal Scaling

All tokens on Pod are represented with 18 decimals internally, regardless of their decimals on the source chain (e.g. USDC has 6 decimals on Ethereum but 18 on Pod). The bridge handles the conversion automatically:

* **Ethereum → Pod**: The bridge scales amounts up to 18 decimals when crediting balances on Pod.
* **Pod → Ethereum**: When calling `withdraw` on the Pod bridge precompile, the `amount` must be specified in the target chain token's native units (e.g. 1e6 for 1 USDC), not in Pod's 18-decimal representation. The Withdraw event also emits amounts in the target chain's decimals. For the **native token**, the coin is moved with the transaction, so `tx.value` must equal that `amount` scaled **up** to Pod's 18 decimals (ERC20 withdrawals send no value). Because the withdraw is then subject to the usual `native >= tx.value + gas` check, you cannot bridge your entire balance and leave nothing to pay for gas.

## Network Upgrades

When the network is upgraded (e.g. validator set changes), past certificates are invalidated because the signing domain changes. Claims from before the upgrade use a merkle inclusion proof instead - the admin commits a merkle root covering all pending claims from the previous version.

`pod_getBridgeClaimProof` handles this automatically - it returns the appropriate proof type based on the current network version. Users do not need to handle this distinction.

## Limits

The bridge contract enforces per-token daily limits on both deposits and claims. Tokens must be whitelisted by the admin before they can be bridged, with configurable minimum amounts and daily caps.

## Audit

The bridge contract has been [audited by Riley Holterhus](https://github.com/podnetwork/pod-sdk/blob/main/protocol/audits/audit-29-01-2026.pdf) (January 2026).


# Overview

Pod's protocol includes a set of asset-agnostic, fully on-chain, composable market primitives - the order book, matching engine, liquidation engine, and oracle system. These are enshrined as precompiles rather than deployed as user contracts. The primitives are general enough to support spot, perpetual futures, options, prediction markets, intent-based matching, and markets for exotic or illiquid assets.

## Why Pod Has No MEV

Transactions are added to the network without any central party - there is no leader or sequencer that controls which transactions are included or in what order. Confirmed transactions are batched and cleared at a single uniform price. Only transactions that were submitted in time can be part of a batch, and only transactions that were sufficiently early get to settle (i.e. claim funds if matched). This means competition happens on price alone - there are no timing or ordering advantages to exploit.

Pod supports two kinds of markets: native markets and external markets.

## Native Markets

Native markets are accessed through the Market precompile. Users deposit funds into the market contract and trade against a central limit order book (CLOB) with batch auction matching. Balances are unified across all native markets - a single deposit can be used for both spot and perpetual trading.

### Batch Settlement

Native markets settle in periodic batches. The batch duration is configurable per market and is expected to be 100-200ms. Within each batch, operations are processed in a fixed sequence:

1. **Deposits** - all deposit operations are processed first, ensuring funds are available before any trading activity.
2. **Order updates and cancellations** - modifications and cancellations are applied, updating the order book state.
3. **Liquidations** - liquidation checks and executions are performed against the updated book.
4. **Matching** - the matching engine runs the clearing algorithm over the resulting order book.
5. **Withdrawals** - withdrawal requests are processed last, after all trading and settlement is complete.

This ordering guarantees that deposited funds can be used for trading in the same batch, and that withdrawals only execute after all positions have been settled.

The batch duration defines a tradeoff between fairness and latency of market settlement. Longer batches allow users with slower internet connections to participate, but markets settle slower - better for more illiquid markets. Shorter batches mean faster settlement but require lower latency to participate.

### Fees

Maker, taker, and liquidation fees are currently set to zero. This is subject to change in the future.

## External Markets

External markets use the [Optimistic Auctions](/documentation/markets/optimistic-auctions) precompile. Pod collects bids in a censorship-resistant way, but settlement happens on a separate chain. Unlike native markets which match orders at a uniform clearing price on Pod, external markets let applications define their own winner selection and settlement logic. This supports use cases like solver auctions and priority fee auctions.

## Navigating the Docs

* [Order Book](/documentation/markets/orderbook) - the enshrined CLOB, order types, matching, and market data
* [Optimistic Auctions](/documentation/markets/optimistic-auctions) - censorship-resistant auctions with off-Pod settlement
* [JSON-RPC reference](https://docs.v2.pod.network/api-reference/json-rpc) - the `ob_*` methods (`ob_getMarkets`, `ob_getOrders`, `ob_getPositions`, …) used to read market state and order/position history


# Order Book

Pod has an enshrined central limit order book (CLOB) built into the protocol as a precompile.

{% hint style="info" %}
**Orderbook precompile address:** `0x50d0000000000000000000000000000000000002` (same on every Pod network). All `submitOrder` / `cancel` / `update` / `deposit` / `withdraw` calls target this address — see the [Orderbook precompile reference](https://docs.v2.pod.network/api-reference/applications-precompiles/orderbook) for the full ABI.
{% endhint %}

Orders are immediately added to the order book as soon as they are finalized through the standard attestation flow - they do not wait for the current batch to conclude. This means cancellations and modifications are also applied responsively, before the next matching round. This is better than systems that execute cancels and modifications at the top of a block, because in Pod the liquidity from cancels and updates can already be reflected in the book before waiting for batch confirmation.

## Order Types

The order book supports limit orders and market orders. The direction of a trade is determined by the sign of the volume parameter - positive for buy/bid, negative for sell/ask.

All markets use 1e18 tick sizes, matching the token decimal standard.

## Market Data

The full node includes a built-in indexer for both live and historical market data. This provides order book snapshots, OHLCV candles, account-level order history, and position data without requiring users to run their own indexer. See the [`ob_` endpoints](https://docs.v2.pod.network/guides-references/json-rpc) in the JSON-RPC reference.

## Matching

Pod uses frequent batch auctions to match orders. Instead of processing orders one at a time as they arrive (continuous trading), orders are collected over a short interval and matched together at a single uniform clearing price. This removes timing-based ordering advantages - competition is on price alone.

Each market has a fixed **batch interval** that defines how often matching rounds run. At the end of every interval the solver settles a batch covering all orders whose `deadline` lands at or before that interval. See [Market Configurations](https://docs.v2.pod.network/guides-references/market-configurations) for the per-market interval on live markets.

### Clearing

At the end of each batch interval, the matching engine runs a double auction using the average mechanism (for simplification, we describe a case where all orders have unit size):

1. Buy orders are sorted by price in descending order: b1 >= b2 >= ... >= bn.
2. Sell orders are sorted by price in ascending order: s1 <= s2 <= ... <= sn.
3. The breakeven index k is the largest index where bk >= sk.
4. The clearing price is set to the average of the kth values: p = (bk + sk) / 2.
5. The first k buyers and sellers trade at price p.

All matched orders execute at the same uniform price. No participant gets a better or worse price based on when their order arrived within the batch.

Market orders do not influence the clearing price — only limit orders at the margin determine it. If the marginal matched order on one side is a market order, the clearing price equals the limit price from the other side alone. If no limit orders were matched at all, the previous batch's clearing price carries over.

### Batch Deadline

The `deadline` parameter in `submitOrder` specifies the latest batch the user wants their order included in. The order can be included in any batch up to and including the deadline batch — so pushing `deadline` further into the future widens the window of batches the order can land in, it does not delay execution.

`deadline` must be **aligned to the market's `auction_interval`** (a multiple of it); intents whose deadline is not aligned are rejected by the validator with `"CLOB validation failed: Deadline is not aligned to auction interval"`. Compute it as:

```
deadline = ceil((now + LAG) / auction_interval) * auction_interval
```

`LAG` is the headroom you give for network and attestation propagation, capped at **10 minutes** in the future from `now_us`. Most integrators should aim for **at least 1 minute**; experts who want to target a specific upcoming batch can push it lower at the risk of missing the batch if the transaction doesn't reach enough validators in time. This 10-minute ceiling is the maximum last look duration and is expected to shorten as the network matures.

The protocol guarantees (via [past perfection](/documentation/core/timestamping#past-perfection)) that if an order receives n - f attestations within the deadline - which it will if it was sent sufficiently early - it will be part of a batch up to and including the latest batch specified by the deadline.

Transactions that do not receive a finality certificate may still be used for matching, but they do not get to settle - the user cannot withdraw funds even if their order is matched. This is by design, to prevent last look attacks.

Traders can set the deadline to be small to ensure they are matched quickly, but they open up the risk of not being able to claim funds if they do not receive sufficient attestations in time. Traders setting recent deadlines should estimate their network latency to honest validators.

### Solver

The solver is the service responsible for settling a batch. It can be a rotating set of solvers or a single entity, configurable per market. The solver waits for the auction deadline and then settles the batch.

The solver does not get any additional advantage. It cannot censor transactions or include transactions that were not submitted in time. It has some flexibility on whether to include out-of-time transactions - orders submitted after the batch timestamp, or orders that received some attestations but fewer than the required n − f. These orders always lose, because they cannot claim funds even if they get matched.

### Solution state commitment

A solution is built against the state the previous batch left behind. Every settlement carries `previousStateHash` - the solver's fingerprint of that state - and each validator compares it against a fingerprint it computes from its own state before attesting. A solution whose claim disagrees is rejected, so a node whose trading state has drifted from the solver's stops attesting rather than settling on state nobody else has.

A single settlement can cover several consecutive batches when the solver is catching up. They are all built from the same starting state, so one `previousStateHash` covers the whole call.

The fingerprint is a CRC-32 digest - fast, since every node recomputes it once per batch - right-aligned in the `bytes32`. It covers the deadline of the batch that produced it, which binds the fingerprint to that batch, followed by every orderbook in ascending `orderbookId` order. Each orderbook contributes:

* its last clearing price
* its last mark price and last oracle price - spot markets have neither
* its best ten resting orders per side, best first, as (price, remaining size) pairs - fewer if the side is thinner

A price the market does not have, and an empty book side, fold in as a `-` marker rather than as zero, so "never traded" stays distinguishable from "traded at zero".

A market with no price of any kind and an empty book contributes nothing at all. Market configuration reaches nodes one at a time, so a node that already knows about a new - and therefore still untraded - market has to agree with one that does not.

`bytes32(0)` means "no reference point yet": a chain that has not settled a batch, or a node restarted from state written before the commitment existed. When either side is zero the comparison is skipped, and both sides recover a real value from the next settled batch.

### References

* E. Budish, P. Cramton, J. Shim. *The High-Frequency Trading Arms Race: Frequent Batch Auctions as a Market Design Response.* Quarterly Journal of Economics, 2015.

## AMM Order Book

{% hint style="info" %}
Coming soon.
{% endhint %}

Pod's order book allows traders to attach custom EVM contracts that define pricing curves for their orders. This enables AMMs and limit orders to coexist natively on the same book. Markets can be bootstrapped using passive AMM curves and progressively transition to professional market maker liquidity for tighter spreads and better price discovery. Market makers can update orders across the entire pricing curve with minimal state changes.


# Key Delegation

Pod lets an account (the **master**) authorize a secondary key (the **delegate**) to trade on its behalf on the orderbook. The master signs a **single off-chain message** — it never signs a Pod transaction — and the delegate then signs and submits orders, cancels, updates, triggers, deposits, and withdrawals, while the funds and resting orders remain owned by the master.

{% hint style="info" %}
Delegation is **stateless**: the authorization travels inside every delegated transaction and is verified from the transaction alone. There is no registration transaction and no on-chain delegation state — see [How it works](#how-it-works) below.
{% endhint %}

## Why delegate a key

* **Embedded wallets / one-signature onboarding.** A user signs one message with their existing wallet (e.g. via `eth_signTypedData_v4`); an app-controlled ephemeral key transacts from then on, with no further wallet pop-ups. The external wallet never needs to sign a Pod transaction.
* **Bots and trading services.** Hand a service a hot key that can trade the account's balance but can never move funds anywhere except back to the master.
* **Hot/cold key separation.** The master can be a cold key that signs only the delegation message and remains the only key able to direct funds to an external address; the hot delegate trades.
* **Nonce isolation.** All delegated activity rides the *delegate's* nonce stream, so the master account never sends transactions and can never get [nonce-locked](/documentation/core/local-ordering). If a delegate's account gets stuck, mint a new delegate key and sign a new delegation.

## How it works

1. The master signs an EIP-712 `DelegationAuth { delegate, validUntil }` message off-chain, with domain `{ name: "pod delegation", version: "1", chainId }`. `delegate` is the address of the key being authorized; `validUntil` is a timestamp in **microseconds**. The result is a standard 65-byte `r ‖ s ‖ v` signature — the delegation certificate.
2. The delegate wraps each orderbook call in a `delegated(master, validUntil, signature, inner)` envelope — where `inner` is the ABI-encoded calldata of the call it is performing — and signs the transaction with its own key. The same certificate is reused on every delegated transaction until it expires.
3. Every validator verifies the certificate from the transaction alone: the signature must recover to `master`, and the certificate must still cover the wrapped intent — `validUntil >= deadline` of the inner intent (both in microseconds). No on-chain state is consulted, so verification is deterministic across validators.

See [Delegate a trading key](https://github.com/podnetwork/pod-sdk/tree/main/doc/api-reference/guides/delegate-a-trading-key.md) for a step-by-step guide with code examples, and the [Orderbook precompile reference](https://github.com/podnetwork/pod-sdk/tree/main/doc/api-reference/applications-precompiles/orderbook.md#delegation-envelope) for the `delegated` ABI.

## Ownership vs identity

A delegated intent is **owned by the master** but **signed by the delegate**:

| Aspect                                                | Value                                    |
| ----------------------------------------------------- | ---------------------------------------- |
| Resting-order owner, balances, cancel/withdraw target | master                                   |
| `order_id`                                            | keyed on the delegate (the tx signer)    |
| Transaction signer, nonce, account lock               | delegate                                 |
| `deposit` / `withdraw` recipient                      | forced to the master                     |
| Gas                                                   | exempt (the delegate needs no gas funds) |

Because `order_id` is derived from the delegate rather than the master, two delegates of the same master never collide on order ids. And because ownership resolves to the master, the master can always cancel a delegate-placed order directly with its own key.

## What can be delegated

| Inner call                                               | Delegated? | Notes                                                                                      |
| -------------------------------------------------------- | ---------- | ------------------------------------------------------------------------------------------ |
| `submitOrder`, `cancel`, `update`                        | ✅          | owned by the master; `order_id` keys on the delegate                                       |
| `submitTrigger`, `cancelTrigger`, `updateTrigger`        | ✅          | same                                                                                       |
| `deposit`, `withdraw`                                    | ✅          | `recipient` is **forced to the master** — a delegate can never send funds elsewhere        |
| `submitBatch`                                            | ✅          | every sub-intent is owned by the master; the certificate must cover the batch's `deadline` |
| `submitSolutions`, `createOrderBook`, nested `delegated` | ❌          | rejected at validation                                                                     |

The set of delegatable calls is fixed by the protocol — a delegation certificate cannot narrow it further. Scope a delegation in time instead, with a short `validUntil`.

## Security model

* **Expiry.** A delegated intent is honored only while `validUntil >= deadline` of the intent. Expired or malformed certificates make the transaction invalid.
* **No exfiltration.** A delegated `withdraw` or `deposit` can only move funds to the master, so a leaked delegate key can trade the master's balance but never steal it.
* **No revocation.** There is no explicit revoke: a certificate stays valid until its `validUntil`. Keep `validUntil` short and rotate — to replace a delegate, stop using the old key and sign a new `DelegationAuth` for a new one.


# Perpetuals

Pod supports perpetual futures as a native market type. Perpetual contracts track the price of an underlying asset without expiry, using a funding rate mechanism to keep the contract price aligned with the spot price.

Positions are collateralized under a single cross-margin account shared with spot markets - see [Margin](/documentation/markets/margin) for margin requirements, liquidation, and ADL.

## Mark price

Each perp market maintains a **mark price** - a smoothed reference price derived from the order book and the oracle. Mark price is the reference used for margin, liquidation, take-profit/stop-loss, and everything else related to leverage and PnL.

It is recomputed every batch:

```
price_diff_ema = clamp(ema(clearing_or_mid − oracle_price, 3 min), 0, oracle_price × max_premium)
mark_price     = clamp(oracle_price + price_diff_ema, last_mark_price, mark_clamp_pct × last_mark_price)
```

* `clamp(x, center, half_width)` - clips `x` to `[center − half_width, center + half_width]`.
* `clearing_or_mid` - the batch's uniform clearing price if it matched, otherwise the order book mid price.
* `ema(·, 3 min)` - a 3-minute exponential moving average of the gap between the book price and the oracle.
* `max_premium` - a per-market bound; `price_diff_ema` is clamped to `oracle_price × max_premium` so mark cannot drift arbitrarily far from the oracle.
* `mark_clamp_pct` - a per-market bound limiting how far `mark_price` can move from the previous batch's mark price in a single batch, expressed as a fraction of `last_mark_price`.

## Funding

Perpetuals use a funding mechanism to keep the mark price aligned with the underlying oracle price. The funding rate is recomputed and applied every batch - each open position pays or receives its share directly into cash, with no per-period lump payment.

### Funding rate

For each market, on every batch:

```
funding_rate = clamp(
    interest_rate
      + saturate((impact_bid − oracle_price) / oracle_price)
      − saturate((oracle_price − impact_ask) / oracle_price),
    −max_funding_rate,
    max_funding_rate,
)
```

* `oracle_price` - the spot price reported by the oracle for the underlying.
* `impact_bid` / `impact_ask` - the effective price a taker would get when opening a short / long position of size `impact_notional` (a per-market USD amount, defaulting to $10,000) against the current batch auction.
* `saturate(x)` - `max(x, 0)`: each term contributes only when it pushes the perp away from spot.
* `interest_rate` - a per-market constant, defaulting to 0.01% per 8 hours.
* `max_funding_rate` - a per-market cap on the rate's magnitude, defaulting to 4% per hour.
* `funding_rate` is signed: positive means longs pay shorts, negative means shorts pay longs.

When the perp trades at a premium (`impact_bid` above the oracle) the first `saturate` term is positive and longs pay; when it trades at a discount (`impact_ask` below the oracle) the second term dominates and shorts pay. The rate is computed and applied per batch - `interest_rate` and `max_funding_rate` are shown normalized to 8-hour and hourly figures only for readability.

### Per-position payment

Every batch, each open position settles funding into cash. Because `interest_rate` and `max_funding_rate` are expressed per `funding_window` (8 hours by default), the payment is prorated to the actual time elapsed since the last batch:

```
funding_payment = funding_rate × oracle_price × position.size × (elapsed / funding_window)
realized_pnl   −= funding_payment
```

`position.size` is signed (long positive, short negative), so a positive `funding_rate` charges longs and credits shorts, and vice versa. A position held for exactly one `funding_window` pays `funding_rate × oracle_price × position.size` in total. After settlement, the position's unrealized PnL is pure price drift: `(mark − entry) × size`.


# Margin

Pod uses cross margin. There is a single collateral asset, USD, shared between perpetual and spot markets, so there is no need to transfer between the two.

## Account state

Each account is summarized by a handful of quantities.

Start with **cash** - the part of the account not tied to any position's PnL. It accumulates deposits and incoming funding, and decreases on withdrawals and outgoing funding:

```
cash = deposits − withdrawals + funding_payments
```

(See [Per-position payment](/documentation/markets/perpetuals#per-position-payment) for how funding settles.)

**Equity** is the account's mark-to-market value: cash plus the PnL on every open position, where each position's PnL is `(mark_price − entry_price) × position.size`:

```
equity = cash + sum pnl over open positions
```

A position's **notional** is its mark-to-market size, and the account's **effective leverage** is total notional divided by equity:

```
notional           = sum over open positions: |position.size| × mark_price
effective_leverage = notional / equity
```

## Margin requirements

Every open position contributes to two margin levels for the account: **initial margin**, required to open or increase a position, and **maintenance margin**, required to keep it open. Each contributes a fraction of its notional:

```
locked_margin      = sum over open positions: |position.size| × mark_price × initial_margin_ratio
liquidation_margin = sum over open positions: |position.size| × mark_price × maintenance_margin_ratio
```

`initial_margin_ratio` and `maintenance_margin_ratio` are per-market parameters, with the maintenance ratio strictly smaller.

The headroom between equity and `locked_margin` is the **available margin** - new positions can be opened, or existing ones increased, only while it is non-negative:

```
available_margin = equity − locked_margin
```

The maximum cash that can be withdrawn at any time is capped both by available margin and by realized cash, since unrealized PnL is not withdrawable until the position closes:

```
withdrawable_cash = min(available_margin, cash)
```

When `equity < liquidation_margin`, positions become eligible for liquidation.

## Liquidation

* Liquidations are submitted as market orders into the order book. They contribute to liquidity and are matched like normal orders.
* If the account's equity falls below 2/3rd of `liquidation_margin`, the entire portfolio is transferred to the backstop vault.
* If equity goes negative, auto-deleveraging (ADL) is triggered.

## Auto-Deleveraging (ADL)

When an account's equity is negative, ADL closes positions on the profitable side of the market to cancel out the negative equity:

* Positions on the opposite side are sorted by leverage (highest first).
* These positions are closed at the last batch price until all negative equity is offset.
* The underwater position itself is also closed.


# Optimistic Auctions

Optimistic auctions are single-shot auctions where Pod acts as a censorship-resistant bulletin board for bid collection, and settlement happens on a separate chain (Ethereum, an L2, or any other chain with an on-chain consumer contract).

Auctions do not require total ordering of transactions - what matters is the *set* of bids, not their order. This makes them a natural fit for Pod's consensusless architecture, where transactions are finalized independently rather than sequenced into blocks.

## Bid Collection

Bidders submit bids to the [optimistic auctions precompile](https://docs.v2.pod.network/guides-references/references/precompiles/optimistic-auctions) on Pod. Each bid specifies an `auction_id`, a `deadline`, a `value`, and an opaque `data` payload (e.g. an encoded intent or order). Bids with the same `auction_id` compete together.

Once the deadline passes, the [past perfect certificate](/documentation/core/timestamping#past-perfect-certificate) guarantees that the bid set is complete. Under good network conditions, any bid submitted sufficiently before the deadline is guaranteed to be in the set. No bids can be added after this point.

Different parties observing the protocol are guaranteed to see all bids that were in time, but may disagree on bids that were not completely in time (i.e. bids that received some but not n - f attestations before the deadline). This is fine - the settlement mechanism handles this disagreement, as described below.

See the [bidding guide](https://docs.v2.pod.network/guides-references/guides/optimistic-auction) for code examples.

## Settlement

Settlement happens off-Pod, on the consumer chain. There are two approaches:

### Optimistic settlement with dispute resolution

The winner announces the result to the consumer contract on the settlement chain, along with a finality certificate from Pod proving the bid was part of the auction. The claim is accepted unless disputed within a challenge period.

There are exactly two cases during the dispute period:

1. **A higher honest bid exists** - any party can come online and submit the correct winning bid along with its finality certificate to the consumer contract. The contract verifies both certificates and resolves the dispute on-chain.
2. **No show** - if no bidder settles on time, any observer of the auction can blame the highest winner in their view by presenting the bid along with an n - 3f certificate. The blamed bidder is either slashed or must blame a higher winner in their own view. This blame chain resolves in at most 2 rounds.

For the complete pseudocode of the protocol and dispute resolution with proof sketches, see the [Octopod paper](https://drive.google.com/file/d/1uNVX4gBadHniYD9xKk1LzObFq8yzSmf7/view).

This approach is used in the [CowSwap solver auction](https://docs.v2.pod.network/guides-references/case-studies/cowswap-solver-auctions) integration, where the winning solver claims the right to settle a batch on Ethereum.

### Verified settlement with TEE or ZK

Instead of an optimistic claim, a single party (e.g. a sequencer or builder) verifies the past perfect certificate, determines the winner, and proves it was done correctly - either via a TEE attestation or a ZK proof. Its view of the set is considered the correct set because the proof binds the result to a specific verified certificate. There is no disagreement between readers and no dispute period needed.

This approach is demonstrated in the [RollupBoost priority auction](https://docs.v2.pod.network/guides-references/case-studies/rollupboost-priority-auctions) example, where a TEE builder fetches the verified bid set from Pod and constructs L2 blocks ordered by priority fee.

## Sealed-Bid Auctions with TEE

Bidders can encrypt bids to a TEE's public key so that no party - including validators - sees bid values before the auction concludes. The TEE only decrypts bids after verifying the past perfect certificate, which proves the deadline has passed and the bid set is final. This works like timelock encryption, with Pod acting as the time beacon: bids remain sealed until the network certifies the auction has closed. Sealed bids can be combined with either settlement approach above.

## References

* O. Alpos, B. David, J. Mitrovski, O. Sofikitis, D. Zindros. [*Octopod: Decentralized Sealed-Bid Auctions on Pod.*](https://drive.google.com/file/d/1uNVX4gBadHniYD9xKk1LzObFq8yzSmf7/view) 2025.
* O. Alpos, B. David, J. Mitrovski, O. Sofikitis, D. Zindros. *Pod: An Optimal-Latency, Censorship-Free, and Accountable Generalized Consensus Layer.* 2025. [arXiv:2501.14931](https://arxiv.org/abs/2501.14931)


# Tokens

Native transfers and token payments are order-independent - they do not need global ordering and leverage Pod's fast path to finalize in one network round trip. To take advantage of this correctly, tokens are built natively into the protocol rather than deployed as user contracts.

Tokens on Pod support standard ERC-20 transfers. Users can transfer tokens using the familiar `transfer(address to, uint256 amount)` interface.

There is currently no `approve` functionality. Only users themselves can transfer their tokens when interacting with an application - explicit approval to a third party is not required.

See the [Precompiles](https://docs.v2.pod.network/guides-references/applications-precompiles) page for the list of supported tokens and their addresses.


# Getting Started

Pod provides an Ethereum-like interface, so developers can use existing toolchains and wallets out of the box - `ethers.js`, `viem`, `web3.py`, `alloy`, `cast`, or any EVM-compatible library. No new SDKs or custom clients required.

```javascript
import { ethers } from "ethers";

const provider = new ethers.JsonRpcProvider("https://rpc.podtestnet.dev");
const balance = await provider.getBalance("0xYourAddress");
```

## Network Configuration

{% tabs %}
{% tab title="Testnet" %}

| Property        | Value                                                        |
| --------------- | ------------------------------------------------------------ |
| Name            | `pod`                                                        |
| RPC             | `https://rpc.podtestnet.dev`                                 |
| Chain ID        | `129301`                                                     |
| Explorer        | `https://explorer.pod.network`                               |
| Currency Symbol | `USD`                                                        |
| EVM Version     | `Prague` (Ethereum block 22,431,084, Released May 7th, 2025) |
| {% endtab %}    |                                                              |

{% tab title="Mainnet" %}
{% hint style="info" %}
**Mainnet is not live yet.** Network details will be published here once mainnet launches.
{% endhint %}
{% endtab %}
{% endtabs %}

## Next Steps

{% hint style="info" %}
**Transaction hashes as identifiers.** Pod often uses the **transaction hash** — the value returned by `eth_sendRawTransaction` when the transaction was submitted — as the identifier for the entity that transaction created. For example, a bridge withdrawal's claim proof is fetched by the withdrawal tx hash, and account recovery references its target transaction by tx hash.

**Exception — orderbook orders.** A resting order is identified by a computed `order_id = keccak256(abi.encode(signer, nonce, sequence))`, **not** its `submitOrder` tx hash. The orderbook precompile's `cancel(orderbookId, canceledOrder, …)`, `update(orderbookId, updatedOrder, …)`, and `getOrders(orderbookId, orderIds)` all take this `order_id`; `ob_getOrders` returns it as `order_id` (and the originating tx hash separately as `tx_hash`). See the [Orderbook precompile](/guides-references/references/applications-precompiles/orderbook) for details.
{% endhint %}

Pod supports standard Ethereum RPC methods under the `eth_` namespace, with a few differences due to Pod's blockless architecture. Pod also introduces additional namespaces for protocol-specific and orderbook functionality:

* [**JSON-RPC**](/guides-references/references/json-rpc) - Standard `eth_` methods, Pod-specific `pod_` extensions, and orderbook data via `ob_` endpoints.
* [**Precompiles**](/guides-references/references/applications-precompiles) - Enshrined applications and internal protocol operations exposed as precompile contracts, callable via `eth_call` and `eth_sendRawTransaction`.


# Place a spot order

This guide walks through placing a limit order on one of Pod's spot markets. For background, see [Orderbook](https://docs.v2.pod.network/documentation/markets/orderbook).

Spot orders use the same `submitOrder` call as perpetual orders. For spot, pass `reduceOnly = false` and `ioc = false` for a resting limit order. Deposit the quote token (USD) before submitting.

The example below trades the NVDAx-USD spot market — see [Market Configurations](/guides-references/references/market-configurations) for the full live list.

See the [Orderbook precompile reference](/guides-references/references/applications-precompiles/orderbook) for the timestamp unit, deadline-alignment, and TTL rules that apply to every call below.

## Steps

1. Deposit the quote token into the orderbook contract.
2. Submit a limit order with price, size, deadline, and TTL.

{% tabs %}
{% tab title="TypeScript (ethers.js)" %}

```typescript
import { ethers } from "ethers";

const provider = new ethers.JsonRpcProvider("https://rpc.podtestnet.dev");
const wallet = new ethers.Wallet(PRIVATE_KEY, provider);

const ORDERBOOK = "0x50d0000000000000000000000000000000000002";
const abi = [
  "function deposit(address token, address recipient, uint256 amount, uint128 deadline)",
  "function submitOrder(bytes32 orderbookId, int256 size, uint256 price, uint8 orderType, uint128 deadline, uint128 ttl, bool reduceOnly, bool ioc)",
];
const orderbook = new ethers.Contract(ORDERBOOK, abi, wallet);

// USD is the native token; NVDAx is the synthetic Nvidia base
const USD = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
const orderbookId = "0x0000000000000000000000000000000000000000000000000000000000000001"; // NVDAx-USD spot

// Deadlines must be an exact multiple of the market's auction interval
// (500 ms on every testnet market) or validators reject the intent.
const AUCTION_INTERVAL = 500_000n; // microseconds
const deadlineAfter = (lagUs: bigint): bigint =>
  ((BigInt(Date.now()) * 1000n + lagUs + AUCTION_INTERVAL - 1n) / AUCTION_INTERVAL) * AUCTION_INTERVAL;

// 1. Deposit USD (the quote token) into the orderbook
const depositAmount = ethers.parseEther("1000");
await (await orderbook.deposit(USD, wallet.address, depositAmount, deadlineAfter(60_000_000n))).wait();

// 2. Submit a buy limit order: 1 NVDAx at 200 USD
const size = ethers.parseEther("1");         // buy 1 NVDAx (positive = buy)
const price = ethers.parseEther("200");      // limit price in USD
const orderType = 0;                         // 0 = Limit, 1 = Market
const deadline = deadlineAfter(10_000_000n); // include in batches within the next ~10 seconds
const ttl = 60n * 1_000_000n;               // order lives for 60 seconds

const tx = await orderbook.submitOrder(
  orderbookId, size, price, orderType, deadline, ttl,
  false,    // reduceOnly (perp only)
  false,    // ioc — immediate-or-cancel
);
console.log("Order tx:", tx.hash);
```

{% endtab %}

{% tab title="Rust (alloy)" %}

```rust
use alloy::providers::ProviderBuilder;
use alloy::signers::local::PrivateKeySigner;
use alloy::sol;
use alloy::primitives::{U256, I256, FixedBytes};

sol! {
    #[sol(rpc)]
    contract Orderbook {
        function deposit(address token, address recipient, uint256 amount, uint128 deadline) public;
        enum OrderType { Limit, Market }
        function submitOrder(
            bytes32 orderbookId, int256 size, uint256 price,
            OrderType orderType, uint128 deadline, uint128 ttl,
            bool reduceOnly, bool ioc
        ) public;
    }
}

let signer: PrivateKeySigner = PRIVATE_KEY.parse()?;
let provider = ProviderBuilder::new()
    .wallet(signer.clone())
    .on_http("https://rpc.podtestnet.dev".parse()?);

let orderbook = Orderbook::new(
    "0x50d0000000000000000000000000000000000002".parse()?,
    &provider,
);

// USD is the native token; NVDAx is the synthetic Nvidia base
let pusd: Address = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE".parse()?;
let orderbook_id = FixedBytes::left_padding_from(&[1]); // NVDAx-USD spot

// Deadlines must be an exact multiple of the market's auction interval
// (500 ms on every testnet market) or validators reject the intent.
const AUCTION_INTERVAL_US: u128 = 500_000;
let now_us = std::time::SystemTime::now()
    .duration_since(std::time::UNIX_EPOCH)?
    .as_micros();
let deadline_after =
    |lag_us: u128| (now_us + lag_us).div_ceil(AUCTION_INTERVAL_US) * AUCTION_INTERVAL_US;

// 1. Deposit USD (the quote token) into the orderbook
let one_e18 = U256::from(10).pow(U256::from(18));
let deposit_amount = U256::from(1000) * one_e18;
orderbook
    .deposit(pusd, signer.address(), deposit_amount, deadline_after(60_000_000))
    .send().await?.watch().await?;

// 2. Submit a buy limit order: 1 NVDAx at 200 USD
let size = I256::from_raw(one_e18); // buy 1 NVDAx
let price = U256::from(200) * one_e18; // limit price in USD
let deadline = deadline_after(10_000_000); // include in batches within the next ~10 seconds
let ttl = 60 * 1_000_000; // order lives for 60 seconds

let tx = orderbook
    .submitOrder(
        orderbook_id, size, price, Orderbook::OrderType::Limit, deadline, ttl,
        false,        // reduceOnly (perp only)
        false,        // ioc — immediate-or-cancel
    )
    .send().await?;
println!("Order tx: {:?}", tx.tx_hash());
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
**Microseconds, not milliseconds.** Deadlines and TTLs are Unix timestamps in microseconds.
{% endhint %}


# Place a perpetual order

This guide walks through opening a leveraged perpetual position on one of Pod's perp markets. For background, see [Perpetuals](https://docs.v2.pod.network/documentation/markets/perpetuals) and [Market Configurations](/guides-references/references/market-configurations) for the live perp market list.

Perpetual markets are quoted in **USD** and use cross-margin: a single USD deposit serves as collateral for all open perp positions on the account. `size` is the order quantity in **base-asset units** and is signed — positive opens a long, negative opens a short. Margin is computed by the market from `|size| × price / maxLeverage`.

See the [Orderbook precompile reference](/guides-references/references/applications-precompiles/orderbook) for the timestamp unit, deadline-alignment, and TTL rules that apply to every call below.

## Steps

1. Deposit USD as margin into the orderbook contract.
2. Submit a limit order for the perp market (e.g. NVDA-USD).

{% tabs %}
{% tab title="TypeScript (ethers.js)" %}

```typescript
import { ethers } from "ethers";

const provider = new ethers.JsonRpcProvider("https://rpc.podtestnet.dev");
const wallet = new ethers.Wallet(PRIVATE_KEY, provider);

const ORDERBOOK = "0x50d0000000000000000000000000000000000002";
const abi = [
  "function deposit(address token, address recipient, uint256 amount, uint128 deadline)",
  "function submitOrder(bytes32 orderbookId, int256 size, uint256 price, uint8 orderType, uint128 deadline, uint128 ttl, bool reduceOnly, bool ioc)",
];
const orderbook = new ethers.Contract(ORDERBOOK, abi, wallet);

// USD is Pod's native token — use the canonical native-token sentinel address
const USD = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
const nvdaPerpId = "0x0000000000000000000000000000000000000000000000000000000000000007"; // NVDA-USD perp (max 20x)

// Deadlines must be an exact multiple of the market's auction interval
// (500 ms on every testnet market) or validators reject the intent.
const AUCTION_INTERVAL = 500_000n; // microseconds
const deadlineAfter = (lagUs: bigint): bigint =>
  ((BigInt(Date.now()) * 1000n + lagUs + AUCTION_INTERVAL - 1n) / AUCTION_INTERVAL) * AUCTION_INTERVAL;

// 1. Deposit USD margin
const margin = ethers.parseEther("1000"); // 1,000 USD
await (await orderbook.deposit(USD, wallet.address, margin, deadlineAfter(60_000_000n))).wait();

// 2. Open a long on NVDA-USD: 5 NVDA at $140 limit
const size = ethers.parseEther("5");          // +5 NVDA long (negative = short)
const price = ethers.parseEther("140");       // limit price in USD
const orderType = 0;                          // 0 = Limit
const deadline = deadlineAfter(10_000_000n); // include in batches within the next ~10 seconds
const ttl = 60n * 1_000_000n;

const tx = await orderbook.submitOrder(
  nvdaPerpId, size, price, orderType, deadline, ttl,
  false,    // reduceOnly — set true to only close existing positions
  false,    // ioc
);
console.log("Perp order tx:", tx.hash);
```

{% endtab %}

{% tab title="Rust (alloy)" %}

```rust
use alloy::providers::ProviderBuilder;
use alloy::signers::local::PrivateKeySigner;
use alloy::sol;
use alloy::primitives::{U256, I256, FixedBytes};

sol! {
    #[sol(rpc)]
    contract Orderbook {
        function deposit(address token, address recipient, uint256 amount, uint128 deadline) public;
        enum OrderType { Limit, Market }
        function submitOrder(
            bytes32 orderbookId, int256 size, uint256 price,
            OrderType orderType, uint128 deadline, uint128 ttl,
            bool reduceOnly, bool ioc
        ) public;
    }
}

let signer: PrivateKeySigner = PRIVATE_KEY.parse()?;
let provider = ProviderBuilder::new()
    .wallet(signer.clone())
    .on_http("https://rpc.podtestnet.dev".parse()?);

let orderbook = Orderbook::new(
    "0x50d0000000000000000000000000000000000002".parse()?,
    &provider,
);

// USD is Pod's native token — use the canonical native-token sentinel address
let pusd: Address = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE".parse()?;
let nvda_perp_id = FixedBytes::left_padding_from(&[7]); // NVDA-USD perp (max 20x)
let one_e18 = U256::from(10).pow(U256::from(18));

// Deadlines must be an exact multiple of the market's auction interval
// (500 ms on every testnet market) or validators reject the intent.
const AUCTION_INTERVAL_US: u128 = 500_000;
let now_us = std::time::SystemTime::now()
    .duration_since(std::time::UNIX_EPOCH)?
    .as_micros();
let deadline_after =
    |lag_us: u128| (now_us + lag_us).div_ceil(AUCTION_INTERVAL_US) * AUCTION_INTERVAL_US;

// 1. Deposit USD margin
let margin = U256::from(1000) * one_e18;
orderbook
    .deposit(pusd, signer.address(), margin, deadline_after(60_000_000))
    .send().await?.watch().await?;

// 2. Open a long on NVDA-USD: 5 NVDA at $140 limit
let size = I256::from_raw(U256::from(5) * one_e18);   // +5 NVDA long
let price = U256::from(140) * one_e18;                // limit price in USD
let deadline = deadline_after(10_000_000); // include in batches within the next ~10 seconds
let ttl = 60 * 1_000_000;

let tx = orderbook
    .submitOrder(
        nvda_perp_id, size, price, Orderbook::OrderType::Limit, deadline, ttl,
        false,        // reduceOnly — set true to only close existing positions
        false,        // ioc
    )
    .send().await?;
println!("Perp order tx: {:?}", tx.tx_hash());
```

{% endtab %}
{% endtabs %}

## Closing a position

Submit an opposite-sided order with `reduceOnly = true`. Reduce-only orders can only decrease your existing exposure — they will be rejected if matching them would flip your position direction or open a new one.

{% hint style="info" %}
**Market leverage.** Each perp market has a fixed `maxLeverage` set at creation (20x on every testnet perp). It determines the margin required per position — there's no per-order leverage to set.
{% endhint %}


# Submit a batch order

This guide shows how to send several intents in a single signed transaction using the orderbook's `submitBatch` envelope. A common use is to place an entry order together with its take-profit and stop-loss triggers atomically, so they all target the same auction tick.

For the envelope's rules and constraints, see [Batch envelope](/guides-references/references/applications-precompiles/orderbook#batch-envelope) in the Orderbook precompile reference. See the [Orderbook precompile reference](/guides-references/references/applications-precompiles/orderbook) for the timestamp unit, deadline-alignment, and TTL rules that apply to every call below.

Each entry in `inner` is the full ABI-encoded calldata of a single-intent call (`submitOrder`, `submitTrigger`, etc.), and **every sub-intent must carry the same `deadline`** so the whole envelope lands in one tick.

## Steps

1. ABI-encode each single-intent call (entry order, take-profit trigger, stop-loss trigger).
2. Pass them as the `inner` array to `submitBatch`.

The example opens a 5 NVDA long at $140 and arms two asset-grouped (position-bound), reduce-only triggers — a take-profit that sells at $160 and a stop-loss that sells at $120.

{% tabs %}
{% tab title="TypeScript (ethers.js)" %}

```typescript
import { ethers } from "ethers";

const provider = new ethers.JsonRpcProvider("https://rpc.podtestnet.dev");
const wallet = new ethers.Wallet(PRIVATE_KEY, provider);

const ORDERBOOK = "0x50d0000000000000000000000000000000000002";
const abi = [
  "function submitOrder(bytes32 orderbookId, int256 size, uint256 price, uint8 orderType, uint128 deadline, uint128 ttl, bool reduceOnly, bool ioc)",
  "function submitTrigger(bytes32 orderbookId, int256 size, uint256 limitPrice, uint256 triggerPrice, uint8 triggerType, uint8 grouping, uint128 deadline, uint128 ttl, bool reduceOnly, bool ioc)",
  "function submitBatch(bytes[] inner)",
];
const orderbook = new ethers.Contract(ORDERBOOK, abi, wallet);

const nvdaPerpId = "0x0000000000000000000000000000000000000000000000000000000000000007"; // NVDA-USD perp

// Deadlines must be an exact multiple of the market's auction interval
// (500 ms on every testnet market) or validators reject the intent.
const AUCTION_INTERVAL = 500_000n; // microseconds
const deadlineAfter = (lagUs: bigint): bigint =>
  ((BigInt(Date.now()) * 1000n + lagUs + AUCTION_INTERVAL - 1n) / AUCTION_INTERVAL) * AUCTION_INTERVAL;

// One shared deadline for the whole envelope — required by submitBatch.
const deadline = deadlineAfter(10_000_000n);
const ttl = 60n * 1_000_000n;
const size = ethers.parseEther("5"); // +5 NVDA long

// 1. Entry: 5 NVDA long at $140 limit
const entry = orderbook.interface.encodeFunctionData("submitOrder", [
  nvdaPerpId, size, ethers.parseEther("140"), 0 /* Limit */, deadline, ttl, false, false,
]);

// 2. Take-profit: sell 5 NVDA when price reaches $160 (reduceOnly, tied to the position)
const takeProfit = orderbook.interface.encodeFunctionData("submitTrigger", [
  nvdaPerpId, -size, ethers.parseEther("160"), ethers.parseEther("160"),
  0 /* TakeProfit */, 1 /* Asset */, deadline, ttl, true, false,
]);

// 3. Stop-loss: sell 5 NVDA when price drops to $120 (reduceOnly, tied to the position)
const stopLoss = orderbook.interface.encodeFunctionData("submitTrigger", [
  nvdaPerpId, -size, ethers.parseEther("120"), ethers.parseEther("120"),
  1 /* StopLoss */, 1 /* Asset */, deadline, ttl, true, false,
]);

// Submit all three as one atomic envelope
const tx = await orderbook.submitBatch([entry, takeProfit, stopLoss]);
console.log("Batch tx:", tx.hash);
```

{% endtab %}

{% tab title="Rust (alloy)" %}

```rust
use alloy::providers::ProviderBuilder;
use alloy::signers::local::PrivateKeySigner;
use alloy::sol;
use alloy::sol_types::SolCall;
use alloy::primitives::{U256, I256, FixedBytes};

sol! {
    #[sol(rpc)]
    contract Orderbook {
        enum OrderType { Limit, Market }
        enum TriggerType { TakeProfit, StopLoss }
        enum TriggerGrouping { None, Asset }
        function submitOrder(
            bytes32 orderbookId, int256 size, uint256 price,
            OrderType orderType, uint128 deadline, uint128 ttl,
            bool reduceOnly, bool ioc
        ) public;
        function submitTrigger(
            bytes32 orderbookId, int256 size, uint256 limitPrice, uint256 triggerPrice,
            TriggerType triggerType, TriggerGrouping grouping, uint128 deadline, uint128 ttl,
            bool reduceOnly, bool ioc
        ) public;
        function submitBatch(bytes[] inner) public;
    }
}

let signer: PrivateKeySigner = PRIVATE_KEY.parse()?;
let provider = ProviderBuilder::new()
    .wallet(signer.clone())
    .on_http("https://rpc.podtestnet.dev".parse()?);

let orderbook = Orderbook::new(
    "0x50d0000000000000000000000000000000000002".parse()?,
    &provider,
);

let nvda_perp_id = FixedBytes::left_padding_from(&[7]); // NVDA-USD perp
let one_e18 = U256::from(10).pow(U256::from(18));

// Deadlines must be an exact multiple of the market's auction interval
// (500 ms on every testnet market) or validators reject the intent.
const AUCTION_INTERVAL_US: u128 = 500_000;
let now_us = std::time::SystemTime::now()
    .duration_since(std::time::UNIX_EPOCH)?
    .as_micros();

// One shared deadline for the whole envelope — required by submitBatch.
let deadline = (now_us + 10_000_000).div_ceil(AUCTION_INTERVAL_US) * AUCTION_INTERVAL_US;
let ttl = 60 * 1_000_000;
let size = I256::from_raw(U256::from(5) * one_e18); // +5 NVDA long

// 1. Entry: 5 NVDA long at $140 limit
let entry = Orderbook::submitOrderCall {
    orderbookId: nvda_perp_id,
    size,
    price: U256::from(140) * one_e18,
    orderType: Orderbook::OrderType::Limit,
    deadline, ttl, reduceOnly: false, ioc: false,
}.abi_encode();

// 2. Take-profit: sell 5 NVDA when price reaches $160 (reduceOnly, tied to the position)
let take_profit = Orderbook::submitTriggerCall {
    orderbookId: nvda_perp_id,
    size: -size,
    limitPrice: U256::from(160) * one_e18,
    triggerPrice: U256::from(160) * one_e18,
    triggerType: Orderbook::TriggerType::TakeProfit,
    grouping: Orderbook::TriggerGrouping::Asset,
    deadline, ttl, reduceOnly: true, ioc: false,
}.abi_encode();

// 3. Stop-loss: sell 5 NVDA when price drops to $120 (reduceOnly, tied to the position)
let stop_loss = Orderbook::submitTriggerCall {
    orderbookId: nvda_perp_id,
    size: -size,
    limitPrice: U256::from(120) * one_e18,
    triggerPrice: U256::from(120) * one_e18,
    triggerType: Orderbook::TriggerType::StopLoss,
    grouping: Orderbook::TriggerGrouping::Asset,
    deadline, ttl, reduceOnly: true, ioc: false,
}.abi_encode();

// Submit all three as one atomic envelope
let tx = orderbook
    .submitBatch(vec![entry.into(), take_profit.into(), stop_loss.into()])
    .send().await?;
println!("Batch tx: {:?}", tx.tx_hash());
```

{% endtab %}
{% endtabs %}


# Delegate a trading key

This guide shows how a **master** account authorizes a secondary **delegate** key with one off-chain signature, and how the delegate then submits orderbook calls on the master's behalf using the `delegated` envelope. For background on ownership, expiry, and the security model, see [Key Delegation](https://github.com/podnetwork/pod-sdk/tree/main/doc/protocol/key-delegation.md); for the envelope's ABI and constraints, see [Delegation envelope](/guides-references/references/applications-precompiles/orderbook#delegation-envelope) in the Orderbook precompile reference.

The master signs a single EIP-712 `DelegationAuth { delegate, validUntil }` message — never a Pod transaction. The resulting 65-byte signature is the delegation certificate: the delegate attaches it to every delegated transaction and it stays valid until `validUntil`. A delegated intent is accepted only while `validUntil >= deadline` of the wrapped intent (both in **microseconds**).

## Steps

1. The master signs the `DelegationAuth` typed-data message authorizing the delegate (once, off-chain).
2. The delegate ABI-encodes the orderbook call it wants to perform, wraps it in `delegated(master, validUntil, signature, inner)`, and signs the transaction with its own key.

The example authorizes a fresh delegate key for one week, then has the delegate place a 5 NVDA long at $140 owned by the master. The order rests under the master and draws on the master's orderbook balance; the master can cancel it directly with its own key at any time. Delegated calls are gas-exempt, so the delegate key needs no funds.

{% tabs %}
{% tab title="TypeScript (ethers.js)" %}

```typescript
import { ethers } from "ethers";

const provider = new ethers.JsonRpcProvider("https://rpc.podtestnet.dev");
const master = new ethers.Wallet(MASTER_PRIVATE_KEY);
const delegate = new ethers.Wallet(DELEGATE_PRIVATE_KEY, provider); // fresh app-generated key
const { chainId } = await provider.getNetwork();

const now = BigInt(Date.now()) * 1000n; // microseconds

// 1. Master signs the delegation certificate (once, off-chain) — valid for one week.
const validUntil = now + 7n * 24n * 3600n * 1_000_000n;
const signature = await master.signTypedData(
  { name: "pod delegation", version: "1", chainId },
  {
    DelegationAuth: [
      { name: "delegate", type: "address" },
      { name: "validUntil", type: "uint64" },
    ],
  },
  { delegate: delegate.address, validUntil },
);

// 2. Delegate wraps an order in delegated(...) and submits it with its own key.
const ORDERBOOK = "0x50d0000000000000000000000000000000000002";
const abi = [
  "function submitOrder(bytes32 orderbookId, int256 size, uint256 price, uint8 orderType, uint128 deadline, uint128 ttl, bool reduceOnly, bool ioc)",
  "function delegated(address master, uint64 validUntil, bytes signature, bytes inner)",
];
const orderbook = new ethers.Contract(ORDERBOOK, abi, delegate);

const nvdaPerpId = "0x0000000000000000000000000000000000000000000000000000000000000007"; // NVDA-USD perp
// Aligned to the market's auction interval (500 ms) — see Notes below.
const AUCTION_INTERVAL = 500_000n;
const deadline = ((now + 10_000_000n + AUCTION_INTERVAL - 1n) / AUCTION_INTERVAL)
  * AUCTION_INTERVAL; // must be <= validUntil
const ttl = 60n * 1_000_000n;

// 5 NVDA long at $140 limit, owned by the master
const inner = orderbook.interface.encodeFunctionData("submitOrder", [
  nvdaPerpId, ethers.parseEther("5"), ethers.parseEther("140"),
  0 /* Limit */, deadline, ttl, false, false,
]);

const tx = await orderbook.delegated(master.address, validUntil, signature, inner);
console.log("Delegated order tx:", tx.hash);
```

{% endtab %}

{% tab title="Rust (alloy)" %}

```rust
use alloy::primitives::{FixedBytes, I256, U256};
use alloy::providers::{Provider, ProviderBuilder};
use alloy::signers::{Signer, local::PrivateKeySigner};
use alloy::sol;
use alloy::sol_types::{SolCall, eip712_domain};

sol! {
    /// The message the master signs to authorize a delegate.
    struct DelegationAuth {
        address delegate;
        uint64 validUntil;
    }

    #[sol(rpc)]
    contract Orderbook {
        enum OrderType { Limit, Market }
        function submitOrder(
            bytes32 orderbookId, int256 size, uint256 price,
            OrderType orderType, uint128 deadline, uint128 ttl,
            bool reduceOnly, bool ioc
        ) public;
        function delegated(address master, uint64 validUntil, bytes signature, bytes inner) public;
    }
}

let master: PrivateKeySigner = MASTER_PRIVATE_KEY.parse()?;
let delegate: PrivateKeySigner = DELEGATE_PRIVATE_KEY.parse()?; // fresh app-generated key

let provider = ProviderBuilder::new()
    .wallet(delegate.clone())
    .on_http("https://rpc.podtestnet.dev".parse()?);
let chain_id = provider.get_chain_id().await?;

let now_us = std::time::SystemTime::now()
    .duration_since(std::time::UNIX_EPOCH)?
    .as_micros() as u64; // microseconds

// 1. Master signs the delegation certificate (once, off-chain) — valid for one week.
let valid_until = now_us + 7 * 24 * 3600 * 1_000_000;
let domain = eip712_domain! {
    name: "pod delegation",
    version: "1",
    chain_id: chain_id,
};
let auth = DelegationAuth { delegate: delegate.address(), validUntil: valid_until };
let signature = master.sign_typed_data(&auth, &domain).await?;

// 2. Delegate wraps an order in delegated(...) and submits it with its own key.
let orderbook = Orderbook::new(
    "0x50d0000000000000000000000000000000000002".parse()?,
    &provider,
);

let nvda_perp_id = FixedBytes::left_padding_from(&[7]); // NVDA-USD perp
let one_e18 = U256::from(10).pow(U256::from(18));
// Aligned to the market's auction interval (500 ms) — see Notes below.
const AUCTION_INTERVAL_US: u128 = 500_000;
let deadline = (u128::from(now_us) + 10_000_000).div_ceil(AUCTION_INTERVAL_US)
    * AUCTION_INTERVAL_US; // must be <= valid_until
let ttl = 60 * 1_000_000;

// 5 NVDA long at $140 limit, owned by the master
let inner = Orderbook::submitOrderCall {
    orderbookId: nvda_perp_id,
    size: I256::from_raw(U256::from(5) * one_e18),
    price: U256::from(140) * one_e18,
    orderType: Orderbook::OrderType::Limit,
    deadline, ttl, reduceOnly: false, ioc: false,
}.abi_encode();

let tx = orderbook
    .delegated(master.address(), valid_until, signature.as_bytes().into(), inner.into())
    .send().await?;
println!("Delegated order tx: {:?}", tx.tx_hash());
```

{% endtab %}
{% endtabs %}

## Notes

* **Reuse the certificate.** Step 1 runs once; the delegate reuses the same `signature` and `validUntil` on every delegated call until expiry. Any single-intent call (`submitOrder`, `cancel`, `update`, triggers, `deposit`, `withdraw`) or a whole `submitBatch` can be wrapped the same way — see [What can be delegated](https://github.com/podnetwork/pod-sdk/tree/main/doc/protocol/key-delegation.md#what-can-be-delegated).
* **Deadlines.** The usual orderbook rules apply to the inner call unchanged (microsecond timestamps, `deadline` aligned to the market's `auction_interval` — see the [Orderbook precompile reference](/guides-references/references/applications-precompiles/orderbook)), plus one more: the certificate must satisfy `validUntil >= deadline`.
* **Funds stay with the master.** A delegated `deposit` or `withdraw` has its `recipient` overridden to the master, so the delegate can never direct funds elsewhere.
* **Rotation.** There is no on-chain revocation — to replace a delegate, stop using the old key and sign a new `DelegationAuth` for a new one. Keep `validUntil` short.


# Read market data

Pod's full node includes a built-in indexer that exposes live and historical market data via the `ob_` JSON-RPC endpoints. No external indexer is needed.

## List available markets

```javascript
const markets = await provider.send("ob_getMarkets", []);
// Returns: [{ id, name, base_token_symbol, quote_token_symbol, last_clearing_price, volume_24h, ... }]
```

## Get orderbook snapshot

```javascript
const orderbookId = "0x0000000000000000000000000000000000000000000000000000000000000001"; // NVDAx-USD spot
const depth = 20; // price levels per side

const snapshot = await provider.send("ob_getOrderbook", [orderbookId, depth]);
// Returns: { buys: { price: { volume } }, sells: { ... }, timestamp }
```

## Get OHLCV candles

```javascript
const candles = await provider.send("ob_getCandles", [
  orderbookId,
  startTimestamp,  // microseconds
  endTimestamp,    // microseconds
  interval,        // candle interval
]);
```

## Get order history

```javascript
const orders = await provider.send("ob_getOrders", [
  walletAddress,
  { clob_ids: [orderbookId] },
]);
// Returns: [{ hash, side, status, price, remainingBase, filledBase, filledQuote, ... }]
```

## Get positions

```javascript
const positions = await provider.send("ob_getPositions", [walletAddress]);
```

See the [JSON-RPC reference](/guides-references/references/json-rpc) for the full `ob_` API specification.


# Bridge to Pod

This guide walks through bridging ERC20 tokens from Ethereum to Pod. For background on how the bridge works, see [Native Bridge](https://docs.v2.pod.network/documentation/native-bridge).

## Simple Deposit

Deposit tokens to Pod with the full amount credited to your account.

### Steps

1. Call `deposit(token, amount, podRecipient, callContract, reserveBalance, permit)` on the Ethereum bridge contract. Set `callContract` to `address(0)` and `reserveBalance` to `0` for a simple deposit.
2. Once the deposit is finalized on Ethereum, Pod validators automatically credit the balance on Pod. No claim is needed.

{% tabs %}
{% tab title="TypeScript (ethers.js)" %}

```typescript
import { ethers } from "ethers";

const provider = new ethers.JsonRpcProvider("https://eth.llamarpc.com");
const wallet = new ethers.Wallet(PRIVATE_KEY, provider);

const BRIDGE = "ETHEREUM_BRIDGE_ADDRESS";
const TOKEN = "TOKEN_ADDRESS"; // use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token
const amount = ethers.parseUnits("100", 6);
const podRecipient = wallet.address;

// Sign an EIP-2612 permit for gasless approval.
// If the token does not support permit, set permit to "0x" and
// send a separate approval transaction:
//   const token = new ethers.Contract(TOKEN, ["function approve(address,uint256)"], wallet);
//   await (await token.approve(BRIDGE, amount)).wait();
const permit = "0x";

const bridge = new ethers.Contract(
  BRIDGE,
  ["function deposit(address token, uint256 amount, address to, address callContract, uint256 reserveBalance, bytes permit) returns (uint256)"],
  wallet
);
const tx = await bridge.deposit(TOKEN, amount, podRecipient, ethers.ZeroAddress, 0, permit);
await tx.wait();
// Tokens will be credited on Pod once the deposit is finalized on Ethereum
```

{% endtab %}

{% tab title="Rust (alloy)" %}

```rust
use alloy::providers::{Provider, ProviderBuilder};
use alloy::signers::local::PrivateKeySigner;
use alloy::sol;
use alloy::primitives::{Address, U256};

sol! {
    #[sol(rpc)]
    contract Bridge {
        function deposit(
            address token, uint256 amount, address to,
            address callContract, uint256 reserveBalance, bytes permit
        ) public returns (uint256);
    }
}

let signer: PrivateKeySigner = PRIVATE_KEY.parse()?;
let provider = ProviderBuilder::new()
    .wallet(signer.clone())
    .on_http("https://eth.llamarpc.com".parse()?);

let bridge_address = "ETHEREUM_BRIDGE_ADDRESS".parse()?;
let token_address = "TOKEN_ADDRESS".parse()?; // use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token
let amount = U256::from(100_000_000u64); // e.g. 100 USDC
let pod_recipient = signer.address();

// Sign an EIP-2612 permit for gasless approval.
// If the token does not support permit, set permit to empty bytes and
// send a separate approval transaction first.
let permit = vec![];

let bridge = Bridge::new(bridge_address, &provider);
bridge
    .deposit(token_address, amount, pod_recipient, Address::ZERO, U256::ZERO, permit.into())
    .send().await?.watch().await?;
// Tokens will be credited on Pod once the deposit is finalized on Ethereum
```

{% endtab %}
{% endtabs %}

## Deposit and Call (Bridge + Orderbook Deposit)

Bridge tokens from Ethereum and deposit them into a whitelisted contract (e.g. the orderbook) on Pod in one step. This avoids needing a separate transaction on Pod after bridging.

The `callContract` parameter specifies which contract on Pod to call with the bridged funds. The `reserveBalance` parameter controls how much to keep in your EOA — the rest is forwarded to the contract. The callee contract receives a `deposit(token, amount, to)` call.

### Steps

1. Call `deposit(token, amount, podRecipient, callContract, reserveBalance, permit)` on the Ethereum bridge contract with `callContract` set to the orderbook address and `reserveBalance` set to the amount you want to keep in your EOA.
2. Once finalized on Ethereum, Pod validators credit `reserveBalance` to your account and forward the remainder to the contract.

{% tabs %}
{% tab title="TypeScript (ethers.js)" %}

```typescript
import { ethers } from "ethers";

const provider = new ethers.JsonRpcProvider("https://eth.llamarpc.com");
const wallet = new ethers.Wallet(PRIVATE_KEY, provider);

const BRIDGE = "ETHEREUM_BRIDGE_ADDRESS";
const TOKEN = "TOKEN_ADDRESS";
const ORDERBOOK = "POD_ORDERBOOK_ADDRESS"; // must be whitelisted on the bridge
const amount = ethers.parseUnits("1000", 6); // 1000 USDC
const reserveBalance = ethers.parseUnits("100", 6); // keep 100 USDC in EOA, deposit 900 to orderbook

const permit = "0x";

const bridge = new ethers.Contract(
  BRIDGE,
  ["function deposit(address token, uint256 amount, address to, address callContract, uint256 reserveBalance, bytes permit) returns (uint256)"],
  wallet
);
const tx = await bridge.deposit(TOKEN, amount, wallet.address, ORDERBOOK, reserveBalance, permit);
await tx.wait();
// 100 USDC credited to your Pod account, 900 USDC deposited into the orderbook
```

{% endtab %}

{% tab title="Rust (alloy)" %}

```rust
use alloy::providers::{Provider, ProviderBuilder};
use alloy::signers::local::PrivateKeySigner;
use alloy::sol;
use alloy::primitives::U256;

sol! {
    #[sol(rpc)]
    contract Bridge {
        function deposit(
            address token, uint256 amount, address to,
            address callContract, uint256 reserveBalance, bytes permit
        ) public returns (uint256);
    }
}

let signer: PrivateKeySigner = PRIVATE_KEY.parse()?;
let provider = ProviderBuilder::new()
    .wallet(signer.clone())
    .on_http("https://eth.llamarpc.com".parse()?);

let bridge_address = "ETHEREUM_BRIDGE_ADDRESS".parse()?;
let token_address = "TOKEN_ADDRESS".parse()?;
let orderbook_address = "POD_ORDERBOOK_ADDRESS".parse()?; // must be whitelisted on the bridge
let amount = U256::from(1_000_000_000u64); // 1000 USDC
let reserve_balance = U256::from(100_000_000u64); // keep 100 USDC in EOA

let permit = vec![];

let bridge = Bridge::new(bridge_address, &provider);
bridge
    .deposit(token_address, amount, signer.address(), orderbook_address, reserve_balance, permit.into())
    .send().await?.watch().await?;
// 100 USDC credited to your Pod account, 900 USDC deposited into the orderbook
```

{% endtab %}
{% endtabs %}


# Bridge from Pod

This guide walks through bridging ERC20 tokens from Pod to Ethereum. For background on how the bridge works, see [Native Bridge](https://docs.v2.pod.network/documentation/native-bridge).

## Decimal Scaling

All tokens on Pod are represented with 18 decimals, regardless of their decimals on Ethereum. When calling `withdraw` on the Pod bridge precompile, the `amount` must be specified in the **Ethereum token's units**. For example, to bridge 1 USDC (6 decimals on Ethereum), pass `1000000` (1e6), not `1000000000000000000` (1e18).

{% hint style="warning" %}
**Setting `tx.value` depends on the token:**

* **Native token** (`0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`): the coin is sent with the transaction, so set `tx.value` to the `amount` **scaled up to Pod's 18 decimals**. For example, bridging 1 USDC uses `amount = 1000000` (1e6) and `tx.value = 1000000000000000000` (1e18). A native withdraw is rejected unless `tx.value` equals the scaled amount — this keeps gas accounting correct (`native >= tx.value + gas`), so you cannot bridge your whole balance and leave nothing to pay for gas.
* **ERC20 tokens**: set `tx.value` to `0`. The balance is deducted internally.
  {% endhint %}

## Steps

1. Call `withdraw(token, amount, ethRecipient, chainId)` on the Pod bridge precompile. The `chainId` is the chain ID of the target chain (e.g. `1` for Ethereum mainnet) — it prevents the withdrawal proof from being replayed on other chains.
2. Call `pod_getBridgeClaimProof(txHash)` on the full node to get the claim proof.
3. Call `claim(token, amount, ethRecipient, proof, auxTxSuffix)` on the Ethereum bridge contract.

## Examples for bridging 100 tokens (e.g. USDC) from Pod to Ethereum (assuming 6 decimals on Ethereum):

{% tabs %}
{% tab title="TypeScript (ethers.js)" %}

```typescript
import { ethers } from "ethers";

const podProvider = new ethers.JsonRpcProvider("https://rpc.podtestnet.dev");
const ethProvider = new ethers.JsonRpcProvider("https://eth.llamarpc.com");
const podWallet = new ethers.Wallet(PRIVATE_KEY, podProvider);
const ethWallet = new ethers.Wallet(PRIVATE_KEY, ethProvider);

const POD_BRIDGE = "0x50d0000000000000000000000000000000000001";
const ETH_BRIDGE = "ETHEREUM_BRIDGE_ADDRESS";
const NATIVE_TOKEN = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
const POD_TOKEN = "POD_TOKEN_ADDRESS"; // use NATIVE_TOKEN for the native token
const ETH_TOKEN = "ETH_TOKEN_ADDRESS";
const ETH_DECIMALS = 6; // token's decimals on Ethereum (e.g. 6 for USDC)
const amount = ethers.parseUnits("100", ETH_DECIMALS); // amount in Ethereum token units
const ethRecipient = ethWallet.address;
const ETH_CHAIN_ID = 1; // Ethereum mainnet chain ID

// 1. Withdraw on Pod bridge precompile.
// For the native token, tx.value must equal the amount scaled to Pod's 18
// decimals; for ERC20 tokens it must be 0.
const value =
  POD_TOKEN.toLowerCase() === NATIVE_TOKEN.toLowerCase()
    ? amount * 10n ** BigInt(18 - ETH_DECIMALS)
    : 0n;
const podBridge = new ethers.Contract(
  POD_BRIDGE,
  ["function withdraw(address token, uint256 amount, address to, uint256 chainId) returns (bytes32)"],
  podWallet
);
const withdrawTx = await podBridge.withdraw(POD_TOKEN, amount, ethRecipient, ETH_CHAIN_ID, { value });
const receipt = await withdrawTx.wait();

// 2. Get claim proof
const claimProof = await podProvider.send("pod_getBridgeClaimProof", [receipt.hash]);

// 3. Claim on Ethereum
const ethBridge = new ethers.Contract(
  ETH_BRIDGE,
  ["function claim(address token, uint256 amount, address to, bytes proof, bytes auxTxSuffix)"],
  ethWallet
);
const claimTx = await ethBridge.claim(
  ETH_TOKEN, amount, ethRecipient, claimProof.proof, claimProof.auxTxSuffix
);
await claimTx.wait();
```

{% endtab %}

{% tab title="Rust (alloy)" %}

```rust
use alloy::providers::{Provider, ProviderBuilder};
use alloy::signers::local::PrivateKeySigner;
use alloy::sol;
use alloy::primitives::U256;

sol! {
    #[sol(rpc)]
    contract PodBridge {
        function withdraw(
            address token, uint256 amount, address to, uint256 chainId
        ) public returns (bytes32);
    }

    #[sol(rpc)]
    contract EthBridge {
        function claim(
            address token, uint256 amount, address to, bytes proof, bytes auxTxSuffix
        ) public;
    }
}

let signer: PrivateKeySigner = PRIVATE_KEY.parse()?;

let pod_provider = ProviderBuilder::new()
    .wallet(signer.clone())
    .on_http("https://rpc.podtestnet.dev".parse()?);

let eth_provider = ProviderBuilder::new()
    .wallet(signer.clone())
    .on_http("https://eth.llamarpc.com".parse()?);

let native_token = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE".parse()?;
let pod_token = "POD_TOKEN_ADDRESS".parse()?; // use native_token for the native token
let eth_token = "ETH_TOKEN_ADDRESS".parse()?;
let eth_decimals = 6u32; // token's decimals on Ethereum (e.g. 6 for USDC)
let amount = U256::from(100_000_000u64); // amount in Ethereum token units (100 USDC = 100 * 1e6)
let eth_recipient = signer.address();
let eth_chain_id = U256::from(1u64); // Ethereum mainnet chain ID

// 1. Withdraw on Pod bridge precompile.
// For the native token, tx.value must equal the amount scaled to Pod's 18
// decimals; for ERC20 tokens it must be 0.
let value = if pod_token == native_token {
    amount * U256::from(10u64).pow(U256::from(18 - eth_decimals))
} else {
    U256::ZERO
};
let pod_bridge = PodBridge::new(
    "0x50d0000000000000000000000000000000000001".parse()?,
    &pod_provider,
);
let withdraw_receipt = pod_bridge
    .withdraw(pod_token, amount, eth_recipient, eth_chain_id)
    .value(value)
    .send().await?
    .get_receipt().await?;

// 2. Get claim proof
let claim_proof: serde_json::Value = pod_provider
    .raw_request(
        "pod_getBridgeClaimProof".into(),
        vec![withdraw_receipt.transaction_hash],
    )
    .await?;

// 3. Claim on Ethereum
let eth_bridge = EthBridge::new(
    "ETHEREUM_BRIDGE_ADDRESS".parse()?,
    &eth_provider,
);
eth_bridge
    .claim(
        eth_token,
        amount,
        eth_recipient,
        claim_proof["proof"].as_str().unwrap().parse()?,
        claim_proof["auxTxSuffix"].as_str().unwrap().parse()?,
    )
    .send().await?
    .watch().await?;
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
Anyone can submit the claim transaction on Ethereum - it does not need to come from the original depositor.
{% endhint %}


# Recover a locked account

If your account is locked due to conflicting transactions at the same nonce, you can recover it by calling the recovery precompile. For background on why accounts get locked and how the recovery protocol works, see [Local Ordering](https://docs.v2.pod.network/documentation/network-architecture/local-ordering#account-locking-and-recovery).

## Steps

1. Call `pod_getRecoveryTargetTx(account)` on the full node to get the target transaction to recover to.
2. Send a transaction to the recovery precompile at `0x50d0000000000000000000000000000000000003`, calling `recover(txHash, nonce)` with the values from step 1.

The protocol will finalize the target transaction chain, recover your account state, and increment the nonce. You can then send a new transaction with the next nonce.

{% tabs %}
{% tab title="TypeScript (ethers.js)" %}

```typescript
import { ethers } from "ethers";

const provider = new ethers.JsonRpcProvider("https://rpc.podtestnet.dev");
const wallet = new ethers.Wallet(PRIVATE_KEY, provider);

const RECOVERY = "0x50d0000000000000000000000000000000000003";
const abi = ["function recover(bytes32 txHash, uint64 nonce) public"];
const recovery = new ethers.Contract(RECOVERY, abi, wallet);

// 1. Get the recovery target for the locked account
const { txHash: targetTxHash, nonce } = await provider.send("pod_getRecoveryTargetTx", [wallet.address]);

// 2. Call the recovery precompile
const tx = await recovery.recover(targetTxHash, nonce);
await tx.wait();
```

{% endtab %}

{% tab title="Rust (alloy)" %}

```rust
use alloy::providers::{Provider, ProviderBuilder};
use alloy::signers::local::PrivateKeySigner;
use alloy::sol;

sol! {
    #[sol(rpc)]
    contract Recovery {
        function recover(bytes32 txHash, uint64 nonce) public;
    }
}

let signer: PrivateKeySigner = PRIVATE_KEY.parse()?;
let provider = ProviderBuilder::new()
    .wallet(signer)
    .on_http("https://rpc.podtestnet.dev".parse()?);

let recovery = Recovery::new(
    "0x50d0000000000000000000000000000000000003".parse()?,
    &provider,
);

// 1. Get the recovery target for the locked account
let target: TargetTx = provider
    .raw_request("pod_getRecoveryTargetTx".into(), vec![account_address])
    .await?;

// 2. Call the recovery precompile
let receipt = recovery
    .recover(target.tx_hash, target.nonce)
    .send()
    .await?
    .watch()
    .await?;
```

{% endtab %}
{% endtabs %}


# Bid in an optimistic auction

This guide walks through submitting a bid to the optimistic auctions precompile and waiting for the bid set to finalize. For background on how optimistic auctions work, see [Optimistic Auctions](https://docs.v2.pod.network/documentation/markets/optimistic-auctions).

## Submit a bid

A bid is a transaction to the `submitBid` function on the precompile. Each bid specifies an `auction_id` (which auction to join), a `deadline` (in microseconds), a `value` (application-defined score or price), and a `data` payload (e.g. an encoded intent or signed transaction).

{% tabs %}
{% tab title="TypeScript (ethers.js)" %}

```typescript
import { ethers } from "ethers";

const provider = new ethers.JsonRpcProvider("https://rpc.podtestnet.dev");
const wallet = new ethers.Wallet(PRIVATE_KEY, provider);

const AUCTION = "0x50d0000000000000000000000000000000000004";
const abi = [
  "function submitBid(uint256 auction_id, uint64 deadline, uint256 value, bytes data)",
  "event BidSubmitted(uint256 indexed auction_id, address indexed bidder, uint64 indexed deadline, uint256 value, bytes data)",
];
const auction = new ethers.Contract(AUCTION, abi, wallet);

const auctionId = 1n;
const deadline = BigInt(Date.now()) * 1000n + 10_000_000n; // 10 seconds from now, in microseconds
const value = ethers.parseEther("100");                     // application-defined bid value
const data = "0x";                                          // opaque payload

const tx = await auction.submitBid(auctionId, deadline, value, data);
console.log("Bid tx:", tx.hash);
```

{% endtab %}

{% tab title="Rust (pod-sdk)" %}

```rust
use pod_sdk::{
    auctions::client::AuctionClient,
    provider::PodProviderBuilder,
    U256,
};
use std::time::{Duration, SystemTime};

let provider = PodProviderBuilder::with_recommended_settings()
    .with_private_key(PRIVATE_KEY.parse()?)
    .on_url("wss://rpc.podtestnet.dev")
    .await?;

let auction = AuctionClient::new(
    provider,
    "0x50d0000000000000000000000000000000000004".parse()?,
);

let auction_id = U256::from(1);
let deadline = SystemTime::now() + Duration::from_secs(10);
let value = U256::from(100) * U256::from(10).pow(U256::from(18));
let data = vec![];

let receipt = auction
    .submit_bid(auction_id, deadline, value, data)
    .await?;
println!("Bid tx: {}", receipt.transaction_hash);
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
**Microseconds, not milliseconds.** Deadlines are Unix timestamps in microseconds.
{% endhint %}

## Wait for the bid set to finalize

After submitting a bid, call `pod_waitPastPerfectTime` to block until the past perfect certificate is available for the auction deadline. Once it returns, the bid set is complete.

{% tabs %}
{% tab title="TypeScript (ethers.js)" %}

```typescript
// Wait for past perfection at the deadline
const result = await provider.send("pod_waitPastPerfectTime", [Number(deadline)]);
console.log("Bid set is final");
```

{% endtab %}

{% tab title="Rust (pod-sdk)" %}

```rust
// Wait for past perfection at the deadline
auction.wait_for_auction_end(deadline).await?;
println!("Bid set is final");
```

{% endtab %}
{% endtabs %}

## Fetch the finalized bid set

Once past perfection is reached, query the `BidSubmitted` event logs to read all bids in the auction.

{% tabs %}
{% tab title="TypeScript (ethers.js)" %}

```typescript
const filter = auction.filters.BidSubmitted(auctionId);
const logs = await auction.queryFilter(filter);

for (const log of logs) {
  console.log(`Bidder: ${log.args.bidder}, Value: ${log.args.value}`);
}
```

{% endtab %}

{% tab title="Rust (pod-sdk)" %}

```rust
let bids = auction.fetch_bids(auction_id).await?;

for bid in &bids {
    println!("Bidder: {}, Value: {}", bid.bidder, bid.amount);
}
```

{% endtab %}
{% endtabs %}


# Market Configurations

Each market on Pod is created with a set of protocol-level parameters that govern trading, risk, and settlement behavior.

{% hint style="info" %}
**Orderbook precompile address:** `0x50d0000000000000000000000000000000000002` — all native markets (spot and perp) share this single precompile. See the [Orderbook precompile reference](/guides-references/references/applications-precompiles/orderbook) for the ABI.
{% endhint %}

## Common Parameters

| Parameter   | Description                                               |
| ----------- | --------------------------------------------------------- |
| Market ID   | Unique identifier (`bytes32`) for the market              |
| Base Asset  | The asset being traded (e.g. BTC, ETH)                    |
| Quote Asset | The settlement currency (e.g. USDC)                       |
| Market Type | `spot` or `perpetual`                                     |
| Tick Size   | Minimum price increment (1e18)                            |
| Solver      | Public key of the solver responsible for settling batches |

## Perpetual Parameters

| Parameter          | Description                                                                                                                                                          |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Max Leverage       | Maximum allowed leverage; set per market at creation                                                                                                                 |
| Initial Margin     | Required margin to open a position. Derived: `1 / Max Leverage`                                                                                                      |
| Maintenance Margin | Margin floor below which the position becomes eligible for liquidation. Derived: `Initial Margin / 2`                                                                |
| Interest Rate      | Per-market funding constant, defaulting to 0.01% per 8 hours. See [Perpetuals → Funding](https://github.com/podnetwork/pod-sdk/tree/main/doc/protocol/perpetuals.md) |
| Oracle             | Price feed source (Pyth asset)                                                                                                                                       |

## Live Markets

All markets are quoted in USD (the native token, address `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`). The `x` suffix on base symbols denotes synthetic representations of the underlying assets. Perpetual markets use [Pyth](https://pyth.network/) price feeds as the oracle. To discover markets at runtime, call [`ob_getMarkets`](https://docs.v2.pod.network/api-reference/json-rpc).

{% tabs %}
{% tab title="Testnet" %}

### Global

| Parameter          | Value                   |
| ------------------ | ----------------------- |
| Batch Interval     | 500ms                   |
| Initial Margin     | `1 / Max Leverage`      |
| Maintenance Margin | `0.5 × Initial Margin`  |
| Backstop           | `0.75 × Initial Margin` |

### Spot Markets

| Market     | Market ID (`bytes32`)                                                | Base Token Address                           |
| ---------- | -------------------------------------------------------------------- | -------------------------------------------- |
| NVDAx-USD  | `0x0000000000000000000000000000000000000000000000000000000000000001` | `0x0000000000000000000000000000000000000001` |
| AAPLx-USD  | `0x0000000000000000000000000000000000000000000000000000000000000002` | `0x0000000000000000000000000000000000000002` |
| GOOGLx-USD | `0x0000000000000000000000000000000000000000000000000000000000000003` | `0x0000000000000000000000000000000000000003` |
| QQQx-USD   | `0x0000000000000000000000000000000000000000000000000000000000000004` | `0x0000000000000000000000000000000000000004` |
| SPYx-USD   | `0x0000000000000000000000000000000000000000000000000000000000000005` | `0x0000000000000000000000000000000000000005` |
| GLDx-USD   | `0x0000000000000000000000000000000000000000000000000000000000000006` | `0x0000000000000000000000000000000000000006` |

### Perpetual Markets

| Market    | Market ID (`bytes32`)                                                | Base Token Address                           | Max Leverage | Oracle       |
| --------- | -------------------------------------------------------------------- | -------------------------------------------- | ------------ | ------------ |
| NVDA-USD  | `0x0000000000000000000000000000000000000000000000000000000000000007` | `0x0000000000000000000000000000000000000007` | 20x          | Pyth `Nvda`  |
| AAPL-USD  | `0x0000000000000000000000000000000000000000000000000000000000000008` | `0x0000000000000000000000000000000000000008` | 20x          | Pyth `Aapl`  |
| GOOGL-USD | `0x0000000000000000000000000000000000000000000000000000000000000009` | `0x0000000000000000000000000000000000000009` | 20x          | Pyth `Googl` |
| QQQ-USD   | `0x000000000000000000000000000000000000000000000000000000000000000a` | `0x000000000000000000000000000000000000000a` | 20x          | Pyth `Qqq`   |
| SPY-USD   | `0x000000000000000000000000000000000000000000000000000000000000000b` | `0x000000000000000000000000000000000000000b` | 20x          | Pyth `Spy`   |
| GLD-USD   | `0x000000000000000000000000000000000000000000000000000000000000000c` | `0x000000000000000000000000000000000000000c` | 20x          | Pyth `Gld`   |

{% hint style="info" %}
Market lists may change as we expand testnet coverage. To stay current, fetch the live list at runtime from [`ob_getMarkets`](https://docs.v2.pod.network/api-reference/json-rpc) rather than hard-coding ids.
{% endhint %}
{% endtab %}

{% tab title="Mainnet" %}
{% hint style="info" %}
**Mainnet is not live yet.** Market configurations will be published here once mainnet launches.
{% endhint %}
{% endtab %}
{% endtabs %}


# JSON-RPC

Pod exposes a **JSON-RPC 2.0 API** for markets, orderbook data, transaction execution, and network information. The API is organized into three groups:

* **Orderbook Data (`ob_`)** - Access markets and orderbook activity via a native protocol indexer, including live snapshots, historical OHLCV candles, and account-level order history.
* **Ethereum Interface (`eth_`)** - An Ethereum-compatible execution layer for balances, nonces, transactions, contract calls, logs, and real-time subscriptions using standard Ethereum tooling.
* **Network & Consensus (`pod_`)** - Pod-specific endpoints for inspecting validator committees and consensus data for monitoring and verification of the network's state.

The API is Ethereum-compatible - existing tooling and libraries work out of the box.

> **Note:** The request path is not semantically meaningful. All JSON-RPC requests go to `/`.

***

### Differences with Ethereum RPC

Pod is not a blockchain and has no blocks. Most `eth_` methods work as expected, but a few differ:

| RPC Method                | Ethereum                             | Pod                                                          |
| ------------------------- | ------------------------------------ | ------------------------------------------------------------ |
| **eth\_blockNumber**      | Returns the most recent block number | Returns the latest past perfection timestamp in microseconds |
| **eth\_getBlockByHash**   | Returns block information by hash    | Returns an empty block structure                             |
| **eth\_getBlockByNumber** | Returns block information by number  | Returns an empty block structure                             |

**Timestamps are in microseconds.** Pod uses microsecond-precision Unix timestamps wherever Ethereum uses block numbers - including `eth_blockNumber`, transaction deadlines, and TTLs.

**Block-related fields are zeroed.** Since Pod has no blocks, EVM opcodes that reference block properties (`block.number`, `block.coinbase`, `block.difficulty`, `block.basefee`) return 0. `block.timestamp` returns the local validator's timestamp at execution time.

**Transaction responses include `pod_metadata`.** Responses to `eth_getTransactionReceipt` and similar methods include an additional `pod_metadata` field containing the attestations and finality information for the transaction.

Pod also introduces new methods under the `pod_` namespace for network and consensus data, and the `ob_` namespace for real-time orderbook data.


# Orderbook Data (ob )

Orderbook Data (`ob_`) is a read-focused API surface that provides access to markets and orderbook activity without requiring clients to run their own indexer or interact with the orderbook contracts directly. It is powered by a native indexer built into the Pod protocol, ensuring fast, consistent, and up-to-date views of on-chain state.

The API exposes live orderbook snapshots, historical OHLCV candles, account-level order history and positions, making it ideal for trading interfaces, analytics, and monitoring services.

📝 This is a JSON-RPC 2.0 API. The request path is not important; the method to execute is defined by the method field in the request body. You can send all requests to /, and any path after / is optional and used only for documentation clarity.

&#x20;   &#x20;

## Get All Markets

> Retrieves a list of all available markets/orderbooks with their metadata\
> and statistics. Each market includes token information, current pricing,\
> 24-hour statistics, and fee structure.<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Orderbook Data (ob_)","description":"Orderbook Data (`ob_`) is a read-focused API surface that provides access to\nmarkets and orderbook activity without requiring clients to run their own\nindexer or interact with the orderbook contracts directly. It is powered\nby a native indexer built into the Pod protocol, ensuring fast, consistent,\nand up-to-date views of on-chain state.\n\nThe API exposes live orderbook snapshots, historical OHLCV candles,\naccount-level order history and positions, making it ideal for trading\ninterfaces, analytics, and monitoring services.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/ob_getMarkets":{"post":{"tags":["Orderbook Data (ob_)"],"summary":"Get All Markets","operationId":"ob_getMarkets","description":"Retrieves a list of all available markets/orderbooks with their metadata\nand statistics. Each market includes token information, current pricing,\n24-hour statistics, and fee structure.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"ob_getMarkets"},"id":{"type":"integer","default":1},"params":{"type":"array","default":[]}}}}}},"responses":{"200":{"description":"Array of market objects with metadata and statistics","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"type":"array","items":{"$ref":"#/components/schemas/Market"}},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Market":{"type":"object","description":"Market/orderbook metadata and 24-hour statistics","properties":{"id":{"$ref":"#/components/schemas/Bytes32","description":"Unique 32-byte orderbook identifier"},"name":{"type":"string","description":"Market name in format `{base_token}/{quote_token}` (e.g. \"NVDAx/USD\")"},"base_token_address":{"$ref":"#/components/schemas/Address","description":"Contract address of the base token"},"quote_token_address":{"$ref":"#/components/schemas/Address","description":"Contract address of the quote token"},"base_token_symbol":{"type":"string","description":"Symbol of the base token (e.g., \"NVDAx\")"},"quote_token_symbol":{"type":"string","description":"Symbol of the quote token (e.g., \"USD\")"},"base_token_name":{"type":"string","description":"Full name of the base token"},"quote_token_name":{"type":"string","description":"Full name of the quote token"},"market_type":{"$ref":"#/components/schemas/MarketType"},"last_clearing_price":{"$ref":"#/components/schemas/HexUint256","description":"Last auction clearing price (quote/base with 1e18 scale)"},"auction_interval":{"type":"integer","format":"int64","description":"Length of a matching round, in microseconds."},"volume_24h":{"$ref":"#/components/schemas/HexUint256","description":"24-hour trading volume"},"high_24h":{"$ref":"#/components/schemas/HexUint256","description":"24-hour highest price"},"low_24h":{"$ref":"#/components/schemas/HexUint256","description":"24-hour lowest price"},"price_change_24h":{"type":"integer","format":"int64","description":"24-hour price change (signed integer)"},"tick_precision":{"$ref":"#/components/schemas/HexUint256","description":"Minimum price tick size, hex-encoded with `1e18` scale (e.g. `0xde0b6b3a7640000` = `1e18` = one whole tick)."},"lot_size":{"$ref":"#/components/schemas/HexUint256","description":"Minimum order size increment, hex-encoded with `1e18` scale. Order sizes must be multiples of this value."},"maker_fee":{"$ref":"#/components/schemas/HexUint256","description":"Maker fee rate (1e18-scaled)"},"taker_fee":{"$ref":"#/components/schemas/HexUint256","description":"Taker fee rate (1e18-scaled)"},"max_leverage":{"type":"integer","description":"Maximum allowed leverage. Returned for both spot and perp markets, but only meaningful for perp."},"oracle_price":{"type":"string","nullable":true,"description":"Perp markets only. Latest Pyth oracle price as a hex-encoded\nunsigned 256-bit integer (1e18-scaled), used as the mark for funding\nand liquidation. `null` for spot markets.\n"},"mark_price":{"type":"string","nullable":true,"description":"Perp markets only. True mark price (oracle-anchored) as a hex-encoded\nunsigned 256-bit integer (1e18-scaled). `null` for spot markets.\n"},"funding_rate":{"type":"string","nullable":true,"description":"Perp markets only. Per-`funding_window` funding rate as a signed\ndecimal string (1e18-scaled, may be negative). `null` for spot markets.\n"},"funding_index":{"type":"string","nullable":true,"description":"Perp markets only. Cumulative per-unit-size funding accumulator as\na signed decimal string (1e18-scaled, may be negative). `null` for\nspot markets.\n"},"funding_last_updated":{"type":"integer","format":"int64","nullable":true,"description":"Perp markets only. Microsecond Unix timestamp of the batch that produced\nthe most recent funding update. `null` for spot markets.\n"},"open_interest":{"type":"string","nullable":true,"description":"Perp markets only. Open interest in 1e18-scaled USD notional as a\nhex-encoded unsigned 256-bit integer —\n`mark_price * Σ |position.size|` across every open cross-margin\nposition on this market. `null` for spot markets.\n"}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"MarketType":{"type":"string","enum":["spot","perpetual"],"description":"Type of market - spot trading or perpetual futures"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"}}}}
```

## Get Orderbook Snapshot

> Retrieves the current orderbook snapshot for a specified market, showing buy and sell orders aggregated by price level.\
> \
> Orders are grouped by price and include the total volume resting at each level.\
> Buy orders are sorted by price descending (best bid first), sell orders by price ascending (best ask first).<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Orderbook Data (ob_)","description":"Orderbook Data (`ob_`) is a read-focused API surface that provides access to\nmarkets and orderbook activity without requiring clients to run their own\nindexer or interact with the orderbook contracts directly. It is powered\nby a native indexer built into the Pod protocol, ensuring fast, consistent,\nand up-to-date views of on-chain state.\n\nThe API exposes live orderbook snapshots, historical OHLCV candles,\naccount-level order history and positions, making it ideal for trading\ninterfaces, analytics, and monitoring services.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/ob_getOrderbook":{"post":{"tags":["Orderbook Data (ob_)"],"summary":"Get Orderbook Snapshot","operationId":"ob_getOrderbook","description":"Retrieves the current orderbook snapshot for a specified market, showing buy and sell orders aggregated by price level.\n\nOrders are grouped by price and include the total volume resting at each level.\nBuy orders are sorted by price descending (best bid first), sell orders by price ascending (best ask first).\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"ob_getOrderbook"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `orderbook_id` (bytes32): The 32-byte orderbook identifier\n2. `depth` (integer, optional): Maximum number of price levels to return for each side. If omitted, all available price levels are returned.\n","items":{"oneOf":[{"$ref":"#/components/schemas/Bytes32"},{"type":"integer","description":"Depth - maximum price levels per side"}]}}}}}}},"responses":{"200":{"description":"Orderbook snapshot with aggregated buy and sell orders","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"$ref":"#/components/schemas/OrderbookSnapshot"},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"OrderbookSnapshot":{"type":"object","description":"Current state of an orderbook with aggregated buy/sell levels.\nThe response field is `orderbook_id`; `clob_id` is accepted as an input alias when deserializing.\n","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32","description":"Orderbook identifier. Also accepts `clob_id` as an alias on input."},"buys":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/TickSnapshot"},"description":"Buy orders keyed by price (decimal string), sorted by price descending"},"sells":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/TickSnapshot"},"description":"Sell orders keyed by price (decimal string), sorted by price ascending"},"clearing_price":{"$ref":"#/components/schemas/HexUint256","description":"Current/last clearing price"},"grouping_precision":{"$ref":"#/components/schemas/HexUint256","description":"Price grouping precision used for aggregation (1e18, hex-encoded)"},"timestamp":{"type":"integer","description":"Snapshot timestamp in microseconds"},"new_orders_count":{"type":"integer","description":"Number of new orders since the last snapshot"},"buys_count":{"type":"integer","description":"Total number of buy orders in the orderbook (regardless of depth parameter)"},"sells_count":{"type":"integer","description":"Total number of sell orders in the orderbook (regardless of depth parameter)"},"oracle_price":{"type":"string","nullable":true,"description":"Perp orderbooks only. Pyth oracle price from the most recent perp solution's `priceProof` (1e18, hex-encoded). `null` for spot orderbooks."},"funding_rate":{"type":"string","nullable":true,"description":"Perp orderbooks only. Funding rate computed for this batch (per-`funding_window`, signed 1e18 decimal string). `null` for spot orderbooks."},"funding_index":{"type":"string","nullable":true,"description":"Perp orderbooks only. Cumulative per-unit-size funding accumulator after this batch (signed 1e18 decimal string). `null` for spot orderbooks."},"funding_last_updated":{"type":"integer","format":"int64","nullable":true,"description":"Perp orderbooks only. Microsecond timestamp of the batch that produced the funding update. `null` for spot orderbooks."}}},"TickSnapshot":{"type":"object","description":"Aggregated order volume at a specific price level","properties":{"volume":{"$ref":"#/components/schemas/HexUint256","description":"Total volume available at this price level (1e18, hex-encoded)"}}},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"}}}}
```

## Get Historical Candles

> Retrieves historical candle (OHLCV) data for a specified orderbook.\
> \
> Candles represent aggregated price and volume data over specified time intervals.\
> Results are returned sorted by timestamp in descending order (newest first).\
> \
> All prices are in quote/base units with 1e18 scale (hex-encoded).<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Orderbook Data (ob_)","description":"Orderbook Data (`ob_`) is a read-focused API surface that provides access to\nmarkets and orderbook activity without requiring clients to run their own\nindexer or interact with the orderbook contracts directly. It is powered\nby a native indexer built into the Pod protocol, ensuring fast, consistent,\nand up-to-date views of on-chain state.\n\nThe API exposes live orderbook snapshots, historical OHLCV candles,\naccount-level order history and positions, making it ideal for trading\ninterfaces, analytics, and monitoring services.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/ob_getCandles":{"post":{"tags":["Orderbook Data (ob_)"],"summary":"Get Historical Candles","operationId":"ob_getCandles","description":"Retrieves historical candle (OHLCV) data for a specified orderbook.\n\nCandles represent aggregated price and volume data over specified time intervals.\nResults are returned sorted by timestamp in descending order (newest first).\n\nAll prices are in quote/base units with 1e18 scale (hex-encoded).\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"ob_getCandles"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Positional parameters:\n1. `orderbook_id` (Bytes32): The 32-byte orderbook identifier\n2. `query` (CandlesQuery): Query parameters with resolution, time range, and limit\n","items":{"oneOf":[{"$ref":"#/components/schemas/Bytes32"},{"$ref":"#/components/schemas/CandlesQuery"}]}}}}}}},"responses":{"200":{"description":"Array of candle objects sorted by timestamp (newest first)","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"type":"array","items":{"$ref":"#/components/schemas/Candle"}},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"CandlesQuery":{"type":"object","description":"Query parameters for fetching historical candles","required":["resolution","from_ts"],"properties":{"resolution":{"$ref":"#/components/schemas/CandleResolution","description":"Candle time interval"},"from_ts":{"$ref":"#/components/schemas/Timestamp","description":"Start timestamp (inclusive) in microseconds"},"to_ts":{"$ref":"#/components/schemas/Timestamp","description":"End timestamp (inclusive) in microseconds. Defaults to current time if omitted."},"limit":{"type":"integer","description":"Maximum number of candles to return. No limit if omitted."}}},"CandleResolution":{"type":"string","enum":["1m","5m","15m","1h","4h","1d"],"description":"Time interval for OHLCV candles"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"},"Candle":{"type":"object","description":"OHLCV candle representing price/volume data for a time period","properties":{"timestamp":{"$ref":"#/components/schemas/Timestamp","description":"Candle timestamp in microseconds"},"open":{"$ref":"#/components/schemas/HexUint256","description":"Opening price (quote/base with 1e18 scale)"},"close":{"$ref":"#/components/schemas/HexUint256","description":"Closing price (quote/base with 1e18 scale)"},"high":{"$ref":"#/components/schemas/HexUint256","description":"Highest price (quote/base with 1e18 scale)"},"low":{"$ref":"#/components/schemas/HexUint256","description":"Lowest price (quote/base with 1e18 scale)"},"volume":{"$ref":"#/components/schemas/HexUint256","description":"Total volume traded during this candle period"}}},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"}}}}
```

## Get Account Orders

> Retrieves orders for a specific address in a given orderbook, with support for cursor-based pagination.\
> \
> Orders are returned in descending order by timestamp/nonce.\
> Use the \`next\_cursor\` from the response to fetch subsequent pages.<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Orderbook Data (ob_)","description":"Orderbook Data (`ob_`) is a read-focused API surface that provides access to\nmarkets and orderbook activity without requiring clients to run their own\nindexer or interact with the orderbook contracts directly. It is powered\nby a native indexer built into the Pod protocol, ensuring fast, consistent,\nand up-to-date views of on-chain state.\n\nThe API exposes live orderbook snapshots, historical OHLCV candles,\naccount-level order history and positions, making it ideal for trading\ninterfaces, analytics, and monitoring services.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/ob_getOrders":{"post":{"tags":["Orderbook Data (ob_)"],"summary":"Get Account Orders","operationId":"ob_getOrders","description":"Retrieves orders for a specific address in a given orderbook, with support for cursor-based pagination.\n\nOrders are returned in descending order by timestamp/nonce.\nUse the `next_cursor` from the response to fetch subsequent pages.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"ob_getOrders"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Positional parameters:\n1. `address` (Address): The address to get orders for\n2. `query` (OrdersQuery): Query parameters with optional orderbook_id, limit, cursor, and status filter\n","items":{"oneOf":[{"$ref":"#/components/schemas/Address"},{"$ref":"#/components/schemas/OrdersQuery"}]}}}}}}},"responses":{"200":{"description":"Object containing orders array and pagination cursor","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"type":"object","properties":{"orders":{"type":"array","items":{"$ref":"#/components/schemas/Order"}},"total_count":{"type":"integer","description":"Total number of orders matching the query, regardless of pagination. Present only when the request set `with_total` (omitted otherwise, not null). Older nodes always return it."},"next_cursor":{"type":"string","nullable":true,"description":"Cursor for fetching the next page (wire format `\"{ts}:{nonce}:{order_id_hex}\"`). Null if no more results."}}},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"OrdersQuery":{"type":"object","description":"Query parameters for ob_getOrders (address is passed as first param)","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32","description":"Optional filter by orderbook; omit for all orderbooks"},"limit":{"type":"integer","description":"Maximum number of orders to return"},"cursor":{"type":"string","description":"Pagination cursor from previous response"},"status":{"$ref":"#/components/schemas/OrderStatus","description":"Filter orders by status"},"with_fills":{"type":"boolean","description":"When true, include each order's per-batch partial `fills` array in the response. Defaults to false."},"with_total":{"type":"boolean","description":"When true, compute and return `total_count`. Defaults to false — the count walks every order the account ever placed (expensive for high-churn accounts), and cursor pagination does not need it. Nodes running builds predating this flag ignore it and always return `total_count`."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"OrderStatus":{"type":"string","enum":["pending","active","filled","expired","canceled"],"description":"Current status of an order:\n- `pending`: Order submitted but not yet included in orderbook\n- `active`: Order is live in the orderbook\n- `filled`: Order completely filled\n- `expired`: Order expired (TTL exceeded)\n- `canceled`: Order was canceled by user\n"},"Order":{"type":"object","description":"An order returned by `ob_getOrders`. Carries spot and perp shapes — perp-only fields (`reduce_only`, `ioc`, `direction`) are present only when `market_type = perpetual`. The `initial_size` is signed: positive for Buy/Long, negative for Sell/Short.\n","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32","description":"The orderbook this order belongs to"},"market_type":{"$ref":"#/components/schemas/MarketType"},"kind":{"$ref":"#/components/schemas/OrderKind"},"order_id":{"$ref":"#/components/schemas/Bytes32","description":"Computed order identifier `keccak256(abi.encode(signer, nonce, sequence))` — the id orders, cancels, and updates are keyed by."},"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"Transaction hash that created this order. Zero for engine-generated orders (liquidations, fired-trigger synthetics)."},"bidder":{"$ref":"#/components/schemas/Address","description":"Address of the order creator"},"nonce":{"type":"integer","format":"int64","description":"Nonce of the transaction that created the order — the signing key's nonce, not a\nper-order counter, and the delegate's rather than the master's for a delegated order.\nOrders from one `submitBatch` share it.\n"},"order_type":{"type":"string","enum":["limit","market"],"description":"Limit or market"},"status":{"$ref":"#/components/schemas/OrderStatus"},"side":{"type":"string","enum":["buy","sell"],"description":"Bid (buy) or ask (sell). For perps, prefer `direction` for the position-effect label."},"price":{"$ref":"#/components/schemas/HexUint256","description":"Limit price in quote/base units with 1e18 scale"},"initial_size":{"type":"string","description":"Original signed order size (positive = Buy/Long, negative = Sell/Short)"},"filled_base_amount":{"$ref":"#/components/schemas/HexUint256","description":"Cumulative amount of base tokens filled"},"filled_quote_amount":{"$ref":"#/components/schemas/HexUint256","description":"Cumulative amount of quote tokens filled"},"fee":{"$ref":"#/components/schemas/HexUint256","description":"Accumulated trading fee. Currently always zero."},"deadline":{"$ref":"#/components/schemas/Timestamp","description":"Timestamp by which order must be included in the orderbook (microseconds)"},"end":{"$ref":"#/components/schemas/Timestamp","description":"Timestamp when order expires (microseconds)"},"effective_price":{"$ref":"#/components/schemas/HexUint256","description":"Effective price the order has been filled at so far (filled_quote / filled_base, 1e18)"},"fills":{"type":"array","items":{"$ref":"#/components/schemas/PartialFill"},"description":"Per-batch partial fills against this order"},"reduce_only":{"type":"boolean","description":"Perp only. If true, the order can only reduce existing exposure. Omitted for spot orders.","nullable":true},"ioc":{"type":"boolean","description":"Perp only. Immediate-or-cancel — any unfilled remainder is canceled at end of batch. Omitted for spot orders.","nullable":true},"direction":{"$ref":"#/components/schemas/OrderDirection","description":"Composite direction label (set for spot, and for perps once fills land or for liquidation orders).","nullable":true},"grouping":{"$ref":"#/components/schemas/TriggerGrouping","description":"Trigger-grouping mode inherited from the parent trigger. Omitted when it is the default `none`."},"trigger_type":{"$ref":"#/components/schemas/TriggerType","description":"Trigger type (`take_profit` / `stop_loss`) inherited from the parent `TriggerOrder` when this order is the synthetic produced by a fired trigger (`kind = triggered`). Omitted for every other order.","nullable":true}}},"MarketType":{"type":"string","enum":["spot","perpetual"],"description":"Type of market - spot trading or perpetual futures"},"OrderKind":{"type":"string","enum":["user_signed","liquidation","triggered"],"description":"Origin of the order:\n- `user_signed`: a normal user-submitted order (every order placed via the `submitOrder` contract call)\n- `liquidation`: synthesized by the engine, per (user, pair), when an account falls below maintenance margin\n- `triggered`: the synthetic order emitted deterministically by validators when an armed TP/SL trigger crosses its threshold against the pair's mark price. Carries `trigger_type` and `grouping` inherited from the parent trigger.\n"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"},"PartialFill":{"type":"object","description":"A single fill round against this order.","properties":{"base_amount":{"$ref":"#/components/schemas/HexUint256","description":"Base token amount filled in this round (1e18)"},"quote_amount":{"$ref":"#/components/schemas/HexUint256","description":"Quote token amount filled in this round (1e18)"},"timestamp":{"$ref":"#/components/schemas/Timestamp","description":"Batch settlement timestamp (microseconds)"},"price":{"$ref":"#/components/schemas/HexUint256","description":"Clearing price of the batch (1e18)"}}},"OrderDirection":{"type":"string","enum":["buy","sell","open_long","add_long","reduce_long","close_long","open_short","add_short","reduce_short","close_short","long_to_short","short_to_long","liquidation"],"description":"Composite per-order direction for history and open-orders UIs.\nSpot orders use `buy`/`sell`. Perp orders use the position-effect labels (`open_long`, `reduce_long`, `close_long`, `long_to_short`, etc.) computed from the position before/after the fill. `liquidation` is set when `kind = liquidation`.\n"},"TriggerGrouping":{"type":"string","enum":["none","asset","position"],"description":"Whether a trigger (and any synthetic order it produces) is bound to the bidder's exposure on the pair:\n- `none`: standalone — the trigger is removed only by a user cancel, TTL expiry, or its own fire; any synthetic order it produced survives independently\n- `asset`: exposure-bound — on perp markets the venue removes the armed trigger *and* any resting synthetic order it produced once the bidder's position on the pair reaches size 0; on spot markets, once the bidder's base-asset holdings reach 0\n\n`asset` was formerly named `position` (same semantics, same ABI value); nodes running older builds still emit `position` and clients should treat the two as equivalent.\n\nOmitted from an `Order` response when it is the default `none`.\n"},"TriggerType":{"type":"string","enum":["take_profit","stop_loss"],"description":"Type of a TP/SL trigger order on a perp market:\n- `take_profit`: fires when the mark price moves favorably across `trigger_price`\n- `stop_loss`: fires when the mark price moves adversely across `trigger_price`\n\nAlso set on a synthetic order (`kind = triggered`) that a fired trigger produced.\n"}}}}
```

## Get Account Positions

> Retrieves trading positions for a specific address across all orderbooks.\
> \
> Positions track the cost basis of acquired tokens (from buys and deposits) and compute\
> unrealized PnL using the current clearing price. The response includes per-token positions\
> (balance, position size, unrealized PnL) and aggregate metrics (total realized PnL,\
> total invested, total unrealized PnL).\
> \
> All amounts use 1e18 fixed-point scale.<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Orderbook Data (ob_)","description":"Orderbook Data (`ob_`) is a read-focused API surface that provides access to\nmarkets and orderbook activity without requiring clients to run their own\nindexer or interact with the orderbook contracts directly. It is powered\nby a native indexer built into the Pod protocol, ensuring fast, consistent,\nand up-to-date views of on-chain state.\n\nThe API exposes live orderbook snapshots, historical OHLCV candles,\naccount-level order history and positions, making it ideal for trading\ninterfaces, analytics, and monitoring services.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/ob_getPositions":{"post":{"tags":["Orderbook Data (ob_)"],"summary":"Get Account Positions","operationId":"ob_getPositions","description":"Retrieves trading positions for a specific address across all orderbooks.\n\nPositions track the cost basis of acquired tokens (from buys and deposits) and compute\nunrealized PnL using the current clearing price. The response includes per-token positions\n(balance, position size, unrealized PnL) and aggregate metrics (total realized PnL,\ntotal invested, total unrealized PnL).\n\nAll amounts use 1e18 fixed-point scale.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"ob_getPositions"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `address` (address): The address to get positions for\n","items":{"$ref":"#/components/schemas/Address"}}}}}}},"responses":{"200":{"description":"Positions response with per-token positions and aggregate PnL","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"$ref":"#/components/schemas/PositionsResponse"},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"PositionsResponse":{"type":"object","description":"Account positions across all orderbooks with aggregate PnL.","properties":{"positions":{"type":"array","items":{"$ref":"#/components/schemas/Position"},"description":"Heterogeneous list of spot holdings and open perp positions."},"total_unrealized_pnl":{"type":"string","description":"Sum of `unrealized_pnl` across every spot holding and perp position (signed, 1e18 USD)."},"total_realized_pnl":{"type":"string","description":"Lifetime portfolio-wide spot realized PnL plus the account-level perp realized-PnL counter. Both are cumulative across the account's history — closing a perp does not zero its contribution (signed, 1e18 USD).\n"},"perps_equity":{"type":"string","description":"Cash adjusted for unsettled funding plus unrealized PnL across all open perp positions. Excludes spot holdings (signed, 1e18 USD)."},"account_value":{"type":"string","description":"`perps_equity` plus the mark value of all spot holdings (signed, 1e18 USD)."},"cash":{"type":"string","description":"Deposited collateral adjusted for unsettled funding. Signed — can be negative if the account is underwater (1e18 USD)."},"withdrawable_cash":{"$ref":"#/components/schemas/HexUint256","description":"Free margin — `cash` minus the initial margin reserved by open positions (1e18 USD)."},"net_deposits":{"type":"string","description":"Net native collateral deposited minus withdrawn (signed, 1e18 USD). Negative once realized profit is withdrawn; lifetime PnL is `account_value − net_deposits`."}}},"Position":{"description":"Tagged union: a single entry in `PositionsResponse.positions`. The `kind` field selects between a `SpotHolding` (one per token) or a `PerpPosition` (one per pair).\n","oneOf":[{"$ref":"#/components/schemas/SpotHolding"},{"$ref":"#/components/schemas/PerpPosition"}],"discriminator":{"propertyName":"kind","mapping":{"spot":"#/components/schemas/SpotHolding","perp":"#/components/schemas/PerpPosition"}}},"SpotHolding":{"type":"object","description":"A token balance with cost-basis tracking. One per token the wallet has touched on a spot market.","properties":{"kind":{"type":"string","enum":["spot"],"description":"Discriminator for the `Position` union."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"balance":{"$ref":"#/components/schemas/HexUint256","description":"Total base tokens held for this market (free + locked, 1e18)."},"free_balance":{"$ref":"#/components/schemas/HexUint256","description":"Spendable portion of `balance` after sell-side order locks (1e18)."},"locked_balance":{"$ref":"#/components/schemas/HexUint256","description":"Base tokens locked in open sell orders (`balance - free_balance`, 1e18)."},"cost_basis":{"$ref":"#/components/schemas/HexUint256","description":"Total quote spent to acquire `balance` (1e18 USD)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Last clearing price for this token's market (1e18)."},"unrealized_pnl":{"type":"string","description":"`(mark - avg_cost) × balance` (signed, 1e18 USD)."},"realized_pnl":{"type":"string","description":"Lifetime realized PnL on the user's spot trading (signed, 1e18 USD; portfolio-wide for v1)."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"PerpPosition":{"type":"object","description":"A leveraged perp position. One per (user, pair).","properties":{"kind":{"type":"string","enum":["perp"],"description":"Discriminator for the `Position` union."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"side":{"$ref":"#/components/schemas/PerpPositionSide"},"size":{"type":"string","description":"Signed position size in base units (1e18). Positive = long, negative = short."},"notional":{"$ref":"#/components/schemas/HexUint256","description":"`|size| × mark_price / 1e18` — dollar value of exposure (1e18)."},"entry_price":{"$ref":"#/components/schemas/HexUint256","description":"Volume-weighted average entry price; updated only on opening fills (1e18)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Latest mark price for the pair, post batch clearing (1e18)."},"margin":{"$ref":"#/components/schemas/HexUint256","description":"Allocated initial margin; cumulative across opens/increases, released proportionally on partial closes (1e18)."},"leverage":{"$ref":"#/components/schemas/HexUint256","description":"`notional × 1e18 / margin`. Effective leverage (0 if `margin` is 0)."},"funding_accrued":{"type":"string","description":"`(market.funding − position.entry_funding) × size` (signed, 1e18 USD)."},"liquidation_price":{"$ref":"#/components/schemas/HexUint256","description":"Mark price at which this position would be liquidated against its own `margin` and the market's maintenance-margin rate. Funding ignored. 0 when position is empty."},"unrealized_pnl":{"type":"string","description":"`((mark − entry) − (funding − entry_funding)) × size` (signed, 1e18 USD)."},"realized_pnl":{"type":"string","description":"Lifetime realized PnL on this position (signed, 1e18 USD). Resets to 0 when the position closes — the next open of the same pair starts fresh."},"stop_loss":{"$ref":"#/components/schemas/HexUint256","description":"Reserved — stop-loss not yet supported.","nullable":true},"take_profit":{"$ref":"#/components/schemas/HexUint256","description":"Reserved — take-profit not yet supported.","nullable":true}}},"PerpPositionSide":{"type":"string","enum":["long","short"],"description":"Side of a perpetual position, derived from the sign of `size`."}}}}
```

## Get Account Fills

> Retrieves trade fills for a specific address within a time range.\
> \
> Fills represent individual trade executions from batch auction settlements.\
> A single order may produce multiple fills across different batches. Each fill\
> includes the clearing price, base and quote amounts, and the associated\
> orderbook and token addresses.\
> \
> Results are returned in descending order by timestamp (most recent first).<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Orderbook Data (ob_)","description":"Orderbook Data (`ob_`) is a read-focused API surface that provides access to\nmarkets and orderbook activity without requiring clients to run their own\nindexer or interact with the orderbook contracts directly. It is powered\nby a native indexer built into the Pod protocol, ensuring fast, consistent,\nand up-to-date views of on-chain state.\n\nThe API exposes live orderbook snapshots, historical OHLCV candles,\naccount-level order history and positions, making it ideal for trading\ninterfaces, analytics, and monitoring services.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/ob_getFills":{"post":{"tags":["Orderbook Data (ob_)"],"summary":"Get Account Fills","operationId":"ob_getFills","description":"Retrieves trade fills for a specific address within a time range.\n\nFills represent individual trade executions from batch auction settlements.\nA single order may produce multiple fills across different batches. Each fill\nincludes the clearing price, base and quote amounts, and the associated\norderbook and token addresses.\n\nResults are returned in descending order by timestamp (most recent first).\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"ob_getFills"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Positional parameters:\n1. `address` (Address): The address to get fills for\n2. `query` (FillsQuery): Query parameters with required from_ts and optional to_ts, orderbook_id, and limit\n","items":{"oneOf":[{"$ref":"#/components/schemas/Address"},{"$ref":"#/components/schemas/FillsQuery"}]}}}}}}},"responses":{"200":{"description":"Object containing fills array","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"$ref":"#/components/schemas/GetFillsResponse"},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"FillsQuery":{"type":"object","description":"Query parameters for ob_getFills (address is passed as first param)","required":["from_ts"],"properties":{"from_ts":{"$ref":"#/components/schemas/Timestamp","description":"Start timestamp (inclusive) in microseconds"},"to_ts":{"$ref":"#/components/schemas/Timestamp","description":"End timestamp (exclusive) in microseconds. Defaults to current time if omitted."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32","description":"Optional filter by orderbook; omit for all orderbooks"},"limit":{"type":"integer","description":"Maximum number of fills to return (max 500). Defaults to 500."}}},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"GetFillsResponse":{"type":"object","description":"Response containing a list of fills","properties":{"fills":{"type":"array","items":{"$ref":"#/components/schemas/FillResponse"},"description":"List of fills ordered by timestamp descending"}}},"FillResponse":{"type":"object","description":"A single trade fill from a batch auction settlement","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32","description":"The orderbook this fill belongs to"},"base_token":{"$ref":"#/components/schemas/Address","description":"Base token contract address"},"quote_token":{"$ref":"#/components/schemas/Address","description":"Quote token contract address"},"order_id":{"$ref":"#/components/schemas/Bytes32","description":"Identifier of the order that was filled"},"order_type":{"type":"string","enum":["limit","market"],"description":"Type of the order"},"initial_size":{"type":"string","description":"Initial order size (1e18); decimal string (signed int256). Positive for buy, negative for sell."},"fee":{"$ref":"#/components/schemas/HexUint256","description":"Accumulated fee for this order (1e18); hex-encoded. Currently always zero."},"base_amount":{"$ref":"#/components/schemas/HexUint256","description":"Base token amount filled in this settlement round (1e18); hex-encoded"},"quote_amount":{"$ref":"#/components/schemas/HexUint256","description":"Quote token amount filled in this settlement round (1e18); hex-encoded"},"timestamp":{"$ref":"#/components/schemas/Timestamp","description":"Timestamp of the batch settlement, in microseconds."},"price":{"$ref":"#/components/schemas/HexUint256","description":"Clearing price of the batch (1e18); hex-encoded"}}},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"}}}}
```

## Get Account Backstop Transfers

> Retrieves the backstop transfers for a specific address, with cursor-based pagination.\
> \
> A backstop transfer is recorded when a perp position is swept to the backstop during\
> liquidation: the position's remaining size and cash are moved off the account. Each entry\
> captures the swept size, cash, the mark price at the sweep, and the account equity at that\
> moment.\
> \
> Results are returned in descending order by timestamp (most recent first). Use \`next\_cursor\`\
> from the response to fetch subsequent pages.<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Orderbook Data (ob_)","description":"Orderbook Data (`ob_`) is a read-focused API surface that provides access to\nmarkets and orderbook activity without requiring clients to run their own\nindexer or interact with the orderbook contracts directly. It is powered\nby a native indexer built into the Pod protocol, ensuring fast, consistent,\nand up-to-date views of on-chain state.\n\nThe API exposes live orderbook snapshots, historical OHLCV candles,\naccount-level order history and positions, making it ideal for trading\ninterfaces, analytics, and monitoring services.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/ob_getBackstopTransfers":{"post":{"tags":["Orderbook Data (ob_)"],"summary":"Get Account Backstop Transfers","operationId":"ob_getBackstopTransfers","description":"Retrieves the backstop transfers for a specific address, with cursor-based pagination.\n\nA backstop transfer is recorded when a perp position is swept to the backstop during\nliquidation: the position's remaining size and cash are moved off the account. Each entry\ncaptures the swept size, cash, the mark price at the sweep, and the account equity at that\nmoment.\n\nResults are returned in descending order by timestamp (most recent first). Use `next_cursor`\nfrom the response to fetch subsequent pages.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"ob_getBackstopTransfers"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Positional parameters:\n1. `address` (Address): The address to get backstop transfers for\n2. `query` (BackstopTransfersQuery): Optional filters — `orderbook_id`, `limit` (clamped to `[1, 200]`), and `cursor`\n","items":{"oneOf":[{"$ref":"#/components/schemas/Address"},{"$ref":"#/components/schemas/BackstopTransfersQuery"}]}}}}}}},"responses":{"200":{"description":"Object containing the backstop transfers array, total count, and pagination cursor","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"$ref":"#/components/schemas/GetBackstopTransfersResponse"},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"BackstopTransfersQuery":{"type":"object","description":"Query parameters for ob_getBackstopTransfers (address is passed as first param). All fields optional.","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32","description":"Optional filter by orderbook; omit for all orderbooks."},"limit":{"type":"integer","description":"Maximum number of transfers to return. Clamped to `[1, 200]`."},"cursor":{"type":"string","description":"Pagination cursor — pass `next_cursor` from the previous response. Wire format `\"{ts}:{id}\"`."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"GetBackstopTransfersResponse":{"type":"object","description":"Paginated result of `ob_getBackstopTransfers`.","properties":{"transfers":{"type":"array","items":{"$ref":"#/components/schemas/BackstopTransferResponse"},"description":"List of backstop transfers ordered by timestamp descending."},"total_count":{"type":"integer","description":"Count of transfers matching `(address, orderbook_id)` *before* pagination."},"next_cursor":{"type":"string","nullable":true,"description":"Pass back as `query.cursor` to fetch the next page. Wire format `\"{ts}:{id}\"`. Null if no more results."}}},"BackstopTransferResponse":{"type":"object","description":"A perp position swept to the backstop during liquidation, as returned by `ob_getBackstopTransfers`.","properties":{"user":{"$ref":"#/components/schemas/Address","description":"Account whose position was swept."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32","description":"The orderbook the swept position belonged to. Omitted when not recorded."},"size":{"type":"string","description":"Signed position size moved to the backstop (decimal int256, 1e18). Positive = long, negative = short."},"cash":{"type":"string","description":"Signed cash moved with the position (decimal int256, 1e18)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Mark price at the sweep (1e18); hex-encoded."},"equity":{"type":"string","description":"Account equity at the moment of the sweep (decimal int256, 1e18)."},"timestamp":{"$ref":"#/components/schemas/Timestamp","description":"Timestamp of the batch that produced the sweep, in microseconds."}}},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```

## Get Account Triggers

> Retrieves the armed TP/SL trigger orders owned by an address, with cursor-based pagination.\
> \
> Triggers are conditional perp orders: when the pair's mark price crosses \`trigger\_price\`\
> in the direction implied by \`trigger\_type\` and the sign of \`size\`, the engine emits a\
> synthetic order (surfaced through \`ob\_getOrders\` with \`kind = triggered\`). Triggers\
> themselves have no fill history, so this response is leaner than \`ob\_getOrders\`.\
> \
> Triggers are returned sorted by \`(orderbook\_id, order\_id)\`. Use \`next\_cursor\` from the\
> response to fetch subsequent pages.<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Orderbook Data (ob_)","description":"Orderbook Data (`ob_`) is a read-focused API surface that provides access to\nmarkets and orderbook activity without requiring clients to run their own\nindexer or interact with the orderbook contracts directly. It is powered\nby a native indexer built into the Pod protocol, ensuring fast, consistent,\nand up-to-date views of on-chain state.\n\nThe API exposes live orderbook snapshots, historical OHLCV candles,\naccount-level order history and positions, making it ideal for trading\ninterfaces, analytics, and monitoring services.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/ob_getTriggers":{"post":{"tags":["Orderbook Data (ob_)"],"summary":"Get Account Triggers","operationId":"ob_getTriggers","description":"Retrieves the armed TP/SL trigger orders owned by an address, with cursor-based pagination.\n\nTriggers are conditional perp orders: when the pair's mark price crosses `trigger_price`\nin the direction implied by `trigger_type` and the sign of `size`, the engine emits a\nsynthetic order (surfaced through `ob_getOrders` with `kind = triggered`). Triggers\nthemselves have no fill history, so this response is leaner than `ob_getOrders`.\n\nTriggers are returned sorted by `(orderbook_id, order_id)`. Use `next_cursor` from the\nresponse to fetch subsequent pages.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"ob_getTriggers"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Positional parameters:\n1. `address` (Address): The address to get triggers for\n2. `query` (TriggersQuery): Optional filters — `orderbook_id`, `limit` (clamped to `[1, 200]`), and `cursor`\n","items":{"oneOf":[{"$ref":"#/components/schemas/Address"},{"$ref":"#/components/schemas/TriggersQuery"}]}}}}}}},"responses":{"200":{"description":"Object containing the triggers array, total count, and pagination cursor","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"$ref":"#/components/schemas/GetTriggersResponse"},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"TriggersQuery":{"type":"object","description":"Query parameters for ob_getTriggers (address is passed as first param). All fields optional — an empty object returns every armed trigger owned by the address, capped at the server-side limit.","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32","description":"Optional filter by orderbook; omit for all orderbooks."},"limit":{"type":"integer","description":"Maximum number of triggers to return. Clamped to `[1, 200]`."},"cursor":{"type":"string","description":"Pagination cursor — pass `next_cursor` from the previous response. Wire format `\"{orderbook_id}:{order_id}\"`."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"GetTriggersResponse":{"type":"object","description":"Paginated result of `ob_getTriggers`.","properties":{"triggers":{"type":"array","items":{"$ref":"#/components/schemas/TriggerOrderResponse"}},"total_count":{"type":"integer","description":"Count of triggers matching `(address, orderbook_id)` *before* pagination."},"next_cursor":{"type":"string","nullable":true,"description":"Pass back as `query.cursor` to fetch the next page. Wire format `\"{orderbook_id}:{order_id}\"`. Null if no more results."}}},"TriggerOrderResponse":{"type":"object","description":"An armed TP/SL trigger order, as returned by `ob_getTriggers`.","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"order_id":{"$ref":"#/components/schemas/Bytes32","description":"Identifier of the trigger (and of the synthetic order it produces when it fires)."},"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"Hash of the `submitTrigger` transaction that armed this trigger."},"bidder":{"$ref":"#/components/schemas/Address"},"nonce":{"type":"integer","format":"int64"},"size":{"type":"string","description":"Signed size of the synthetic order produced when the trigger fires (decimal int256). Positive = buy/long, negative = sell/short."},"limit_price":{"$ref":"#/components/schemas/HexUint256","description":"Limit price of the synthetic order produced when the trigger fires (1e18)."},"trigger_price":{"$ref":"#/components/schemas/HexUint256","description":"Mark-price threshold that arms the trigger (1e18)."},"trigger_type":{"$ref":"#/components/schemas/TriggerType"},"grouping":{"$ref":"#/components/schemas/TriggerGrouping"},"reduce_only":{"type":"boolean"},"ioc":{"type":"boolean","description":"Immediate-or-cancel — any unfilled remainder of the fired order is canceled at end of batch."},"deadline":{"$ref":"#/components/schemas/Timestamp"},"end":{"$ref":"#/components/schemas/Timestamp","description":"TTL expiry — the trigger is swept once `end < batch_deadline` (microseconds)."}}},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"TriggerType":{"type":"string","enum":["take_profit","stop_loss"],"description":"Type of a TP/SL trigger order on a perp market:\n- `take_profit`: fires when the mark price moves favorably across `trigger_price`\n- `stop_loss`: fires when the mark price moves adversely across `trigger_price`\n\nAlso set on a synthetic order (`kind = triggered`) that a fired trigger produced.\n"},"TriggerGrouping":{"type":"string","enum":["none","asset","position"],"description":"Whether a trigger (and any synthetic order it produces) is bound to the bidder's exposure on the pair:\n- `none`: standalone — the trigger is removed only by a user cancel, TTL expiry, or its own fire; any synthetic order it produced survives independently\n- `asset`: exposure-bound — on perp markets the venue removes the armed trigger *and* any resting synthetic order it produced once the bidder's position on the pair reaches size 0; on spot markets, once the bidder's base-asset holdings reach 0\n\n`asset` was formerly named `position` (same semantics, same ABI value); nodes running older builds still emit `position` and clients should treat the two as equivalent.\n\nOmitted from an `Order` response when it is the default `none`.\n"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```

## Get Ranked Positions (Leaderboard)

> Returns accounts ranked by combined realized + unrealized PnL\
> (\`total\_realized\_pnl + total\_unrealized\_pnl\`) descending, paginated by \`offset\`/\`limit\`.\
> \
> Because the unrealized component moves with mark prices, the ordering can shift between\
> calls even without trades. When an \`address\` is supplied, the response also includes that\
> account's own positions and rank (\`queried\`), independent of the returned page.<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Orderbook Data (ob_)","description":"Orderbook Data (`ob_`) is a read-focused API surface that provides access to\nmarkets and orderbook activity without requiring clients to run their own\nindexer or interact with the orderbook contracts directly. It is powered\nby a native indexer built into the Pod protocol, ensuring fast, consistent,\nand up-to-date views of on-chain state.\n\nThe API exposes live orderbook snapshots, historical OHLCV candles,\naccount-level order history and positions, making it ideal for trading\ninterfaces, analytics, and monitoring services.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/ob_getRankedPositions":{"post":{"tags":["Orderbook Data (ob_)"],"summary":"Get Ranked Positions (Leaderboard)","operationId":"ob_getRankedPositions","description":"Returns accounts ranked by combined realized + unrealized PnL\n(`total_realized_pnl + total_unrealized_pnl`) descending, paginated by `offset`/`limit`.\n\nBecause the unrealized component moves with mark prices, the ordering can shift between\ncalls even without trades. When an `address` is supplied, the response also includes that\naccount's own positions and rank (`queried`), independent of the returned page.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"ob_getRankedPositions"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Positional parameters (all optional):\n1. `limit` (integer, nullable): Page size\n2. `offset` (integer, nullable): Number of ranked accounts to skip\n3. `address` (Address, nullable): When supplied, also return this account's positions and rank in `queried`\n","items":{"oneOf":[{"type":"integer","nullable":true},{"$ref":"#/components/schemas/Address"}]}}}}}}},"responses":{"200":{"description":"Ranked window of accounts plus the total count and optional queried account","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"$ref":"#/components/schemas/GetRankedPositionsResponse"},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"GetRankedPositionsResponse":{"type":"object","description":"Paginated leaderboard of accounts ordered by combined realized + unrealized PnL descending.","properties":{"ranked":{"type":"array","items":{"$ref":"#/components/schemas/RankedPosition"},"description":"The requested `[offset, offset + limit)` window, ordered by combined PnL descending."},"total":{"type":"integer","description":"Full count of ranked accounts before pagination."},"queried":{"$ref":"#/components/schemas/RankedAccount","nullable":true,"description":"Populated only when the request supplies an `address` — that account's positions and rank. Null if no address was given, or the account has no PnL-bearing state."}}},"RankedPosition":{"type":"object","description":"One account's full positions snapshot, as an entry in `GetRankedPositionsResponse.ranked`.","properties":{"account":{"$ref":"#/components/schemas/Address"},"positions":{"$ref":"#/components/schemas/PositionsResponse"}}},"PositionsResponse":{"type":"object","description":"Account positions across all orderbooks with aggregate PnL.","properties":{"positions":{"type":"array","items":{"$ref":"#/components/schemas/Position"},"description":"Heterogeneous list of spot holdings and open perp positions."},"total_unrealized_pnl":{"type":"string","description":"Sum of `unrealized_pnl` across every spot holding and perp position (signed, 1e18 USD)."},"total_realized_pnl":{"type":"string","description":"Lifetime portfolio-wide spot realized PnL plus the account-level perp realized-PnL counter. Both are cumulative across the account's history — closing a perp does not zero its contribution (signed, 1e18 USD).\n"},"perps_equity":{"type":"string","description":"Cash adjusted for unsettled funding plus unrealized PnL across all open perp positions. Excludes spot holdings (signed, 1e18 USD)."},"account_value":{"type":"string","description":"`perps_equity` plus the mark value of all spot holdings (signed, 1e18 USD)."},"cash":{"type":"string","description":"Deposited collateral adjusted for unsettled funding. Signed — can be negative if the account is underwater (1e18 USD)."},"withdrawable_cash":{"$ref":"#/components/schemas/HexUint256","description":"Free margin — `cash` minus the initial margin reserved by open positions (1e18 USD)."},"net_deposits":{"type":"string","description":"Net native collateral deposited minus withdrawn (signed, 1e18 USD). Negative once realized profit is withdrawn; lifetime PnL is `account_value − net_deposits`."}}},"Position":{"description":"Tagged union: a single entry in `PositionsResponse.positions`. The `kind` field selects between a `SpotHolding` (one per token) or a `PerpPosition` (one per pair).\n","oneOf":[{"$ref":"#/components/schemas/SpotHolding"},{"$ref":"#/components/schemas/PerpPosition"}],"discriminator":{"propertyName":"kind","mapping":{"spot":"#/components/schemas/SpotHolding","perp":"#/components/schemas/PerpPosition"}}},"SpotHolding":{"type":"object","description":"A token balance with cost-basis tracking. One per token the wallet has touched on a spot market.","properties":{"kind":{"type":"string","enum":["spot"],"description":"Discriminator for the `Position` union."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"balance":{"$ref":"#/components/schemas/HexUint256","description":"Total base tokens held for this market (free + locked, 1e18)."},"free_balance":{"$ref":"#/components/schemas/HexUint256","description":"Spendable portion of `balance` after sell-side order locks (1e18)."},"locked_balance":{"$ref":"#/components/schemas/HexUint256","description":"Base tokens locked in open sell orders (`balance - free_balance`, 1e18)."},"cost_basis":{"$ref":"#/components/schemas/HexUint256","description":"Total quote spent to acquire `balance` (1e18 USD)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Last clearing price for this token's market (1e18)."},"unrealized_pnl":{"type":"string","description":"`(mark - avg_cost) × balance` (signed, 1e18 USD)."},"realized_pnl":{"type":"string","description":"Lifetime realized PnL on the user's spot trading (signed, 1e18 USD; portfolio-wide for v1)."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"PerpPosition":{"type":"object","description":"A leveraged perp position. One per (user, pair).","properties":{"kind":{"type":"string","enum":["perp"],"description":"Discriminator for the `Position` union."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"side":{"$ref":"#/components/schemas/PerpPositionSide"},"size":{"type":"string","description":"Signed position size in base units (1e18). Positive = long, negative = short."},"notional":{"$ref":"#/components/schemas/HexUint256","description":"`|size| × mark_price / 1e18` — dollar value of exposure (1e18)."},"entry_price":{"$ref":"#/components/schemas/HexUint256","description":"Volume-weighted average entry price; updated only on opening fills (1e18)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Latest mark price for the pair, post batch clearing (1e18)."},"margin":{"$ref":"#/components/schemas/HexUint256","description":"Allocated initial margin; cumulative across opens/increases, released proportionally on partial closes (1e18)."},"leverage":{"$ref":"#/components/schemas/HexUint256","description":"`notional × 1e18 / margin`. Effective leverage (0 if `margin` is 0)."},"funding_accrued":{"type":"string","description":"`(market.funding − position.entry_funding) × size` (signed, 1e18 USD)."},"liquidation_price":{"$ref":"#/components/schemas/HexUint256","description":"Mark price at which this position would be liquidated against its own `margin` and the market's maintenance-margin rate. Funding ignored. 0 when position is empty."},"unrealized_pnl":{"type":"string","description":"`((mark − entry) − (funding − entry_funding)) × size` (signed, 1e18 USD)."},"realized_pnl":{"type":"string","description":"Lifetime realized PnL on this position (signed, 1e18 USD). Resets to 0 when the position closes — the next open of the same pair starts fresh."},"stop_loss":{"$ref":"#/components/schemas/HexUint256","description":"Reserved — stop-loss not yet supported.","nullable":true},"take_profit":{"$ref":"#/components/schemas/HexUint256","description":"Reserved — take-profit not yet supported.","nullable":true}}},"PerpPositionSide":{"type":"string","enum":["long","short"],"description":"Side of a perpetual position, derived from the sign of `size`."},"RankedAccount":{"type":"object","description":"An account's positions plus its zero-based rank (0 = top) in the full combined-PnL ordering.","properties":{"account":{"$ref":"#/components/schemas/Address"},"rank":{"type":"integer","description":"Zero-based rank in the full ordering (0 = top), independent of the returned page."},"positions":{"$ref":"#/components/schemas/PositionsResponse"}}}}}}
```

## Get Oracle & Mark Prices

> Returns the latest oracle and mark prices recorded for perp orderbooks by the indexer.\
> \
> Pass an \`orderbook\_id\` to fetch a single orderbook, or omit it for every perp orderbook.\
> Numeric fields are \`0\` and \`as\_of\` is epoch until the orderbook has run a perp batch.\
> Funding state is not included here — call \`ob\_getFundingRates\` for that.<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Orderbook Data (ob_)","description":"Orderbook Data (`ob_`) is a read-focused API surface that provides access to\nmarkets and orderbook activity without requiring clients to run their own\nindexer or interact with the orderbook contracts directly. It is powered\nby a native indexer built into the Pod protocol, ensuring fast, consistent,\nand up-to-date views of on-chain state.\n\nThe API exposes live orderbook snapshots, historical OHLCV candles,\naccount-level order history and positions, making it ideal for trading\ninterfaces, analytics, and monitoring services.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/ob_getOraclePrices":{"post":{"tags":["Orderbook Data (ob_)"],"summary":"Get Oracle & Mark Prices","operationId":"ob_getOraclePrices","description":"Returns the latest oracle and mark prices recorded for perp orderbooks by the indexer.\n\nPass an `orderbook_id` to fetch a single orderbook, or omit it for every perp orderbook.\nNumeric fields are `0` and `as_of` is epoch until the orderbook has run a perp batch.\nFunding state is not included here — call `ob_getFundingRates` for that.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"ob_getOraclePrices"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Positional parameters:\n1. `orderbook_id` (Bytes32, optional): Restrict to a single orderbook; omit for all perp orderbooks\n","items":{"$ref":"#/components/schemas/Bytes32"}}}}}}},"responses":{"200":{"description":"Array of oracle/mark price objects","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"type":"array","items":{"$ref":"#/components/schemas/OraclePrice"}},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"OraclePrice":{"type":"object","description":"Latest oracle and mark prices recorded for a perp orderbook by the indexer.","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"oracle_price":{"$ref":"#/components/schemas/HexUint256","description":"Latest Pyth oracle price (1e18). `0` until the orderbook has run a perp batch."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Most recent non-zero clearing price (1e18). `0` until the orderbook has run a perp batch."},"as_of":{"$ref":"#/components/schemas/Timestamp","description":"Deadline of the batch that produced this row (microseconds). Epoch until the orderbook has run a perp batch."}}},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```

## Get Funding Rates

> Returns the latest funding state for perp orderbooks, with the mark and oracle prices\
> included for context.\
> \
> Pass an \`orderbook\_id\` to fetch a single orderbook, or omit it for every perp orderbook.<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Orderbook Data (ob_)","description":"Orderbook Data (`ob_`) is a read-focused API surface that provides access to\nmarkets and orderbook activity without requiring clients to run their own\nindexer or interact with the orderbook contracts directly. It is powered\nby a native indexer built into the Pod protocol, ensuring fast, consistent,\nand up-to-date views of on-chain state.\n\nThe API exposes live orderbook snapshots, historical OHLCV candles,\naccount-level order history and positions, making it ideal for trading\ninterfaces, analytics, and monitoring services.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/ob_getFundingRates":{"post":{"tags":["Orderbook Data (ob_)"],"summary":"Get Funding Rates","operationId":"ob_getFundingRates","description":"Returns the latest funding state for perp orderbooks, with the mark and oracle prices\nincluded for context.\n\nPass an `orderbook_id` to fetch a single orderbook, or omit it for every perp orderbook.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"ob_getFundingRates"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Positional parameters:\n1. `orderbook_id` (Bytes32, optional): Restrict to a single orderbook; omit for all perp orderbooks\n","items":{"$ref":"#/components/schemas/Bytes32"}}}}}}},"responses":{"200":{"description":"Array of funding rate objects","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"type":"array","items":{"$ref":"#/components/schemas/FundingRate"}},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"FundingRate":{"type":"object","description":"Funding state for a perp orderbook, with the latest mark and oracle prices for context. Returned by `ob_getFundingRates`.","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"funding_rate":{"type":"string","description":"Per-`funding_window` funding rate (signed decimal int256, 1e18; may be negative)."},"funding_index":{"type":"string","description":"Cumulative per-unit-size funding accumulator (signed decimal int256, 1e18; may be negative)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Most recent mark price for the pair (1e18)."},"oracle_price":{"$ref":"#/components/schemas/HexUint256","description":"Latest Pyth oracle price (1e18)."},"as_of":{"$ref":"#/components/schemas/Timestamp","description":"Deadline of the batch that produced this funding update (microseconds). Epoch until the orderbook has run a perp batch."}}},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```


# Ethereum Interface (eth )

Ethereum Interface (`eth_`) provides an Ethereum-compatible JSON-RPC layer that allows existing wallets, tools, and libraries to interact with Pod using familiar methods and conventions. It is designed to be drop-in compatible with standard Ethereum client workflows, allowing developers to use common tooling such as `ethers.js`, `alloy.rs`, and `cast` without modification.

The interface covers the transaction submission and receipt lifecycle, including balance and nonce discovery, read-only contract calls, log queries, and real-time subscriptions.

📝 This is a JSON-RPC 2.0 API. The request path is not important; the method to execute is defined by the method field in the request body. You can send all requests to /, and any path after / is optional and used only for documentation clarity.

&#x20;   &#x20;

## Get Native Token Balance

> Returns the native token balance for the specified address in the wallet.\
> \
> \*\*Note:\*\* This returns the wallet balance, which is distinct from the orderbook contract balance.\
> To query the balance deposited in the orderbook contract, call the \`balanceOf\` function on the orderbook contract.\
> \
> The \`block\_number\` parameter is accepted for Ethereum compatibility but is ignored.<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Ethereum Interface (eth_)","description":"Ethereum Interface (`eth_`) provides an Ethereum-compatible JSON-RPC layer\nthat allows existing wallets, tools, and libraries to interact with Pod\nusing familiar methods and conventions. It is designed to be drop-in\ncompatible with standard Ethereum client workflows, allowing developers to\nuse common tooling such as `ethers.js`, `alloy.rs`, and `cast` without\nmodification.\n\nThe interface covers the transaction submission and receipt lifecycle,\nincluding balance and nonce discovery, read-only contract calls, log\nqueries, and real-time subscriptions.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/eth_getBalance":{"post":{"tags":["Ethereum Interface (eth_)"],"summary":"Get Native Token Balance","operationId":"eth_getBalance","description":"Returns the native token balance for the specified address in the wallet.\n\n**Note:** This returns the wallet balance, which is distinct from the orderbook contract balance.\nTo query the balance deposited in the orderbook contract, call the `balanceOf` function on the orderbook contract.\n\nThe `block_number` parameter is accepted for Ethereum compatibility but is ignored.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"eth_getBalance"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `address` (address): The address to check balance for\n2. `block_number` (string): Block identifier (accepted but ignored)\n","items":{"anyOf":[{"$ref":"#/components/schemas/Address"},{"type":"string","default":"latest"}]}}}}}}},"responses":{"200":{"description":"Balance in wei (hex-encoded uint256)","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"$ref":"#/components/schemas/HexUint256"},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"}}}}
```

## Get Chain ID

> Returns the chain ID used for signing transactions (EIP-155).

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Ethereum Interface (eth_)","description":"Ethereum Interface (`eth_`) provides an Ethereum-compatible JSON-RPC layer\nthat allows existing wallets, tools, and libraries to interact with Pod\nusing familiar methods and conventions. It is designed to be drop-in\ncompatible with standard Ethereum client workflows, allowing developers to\nuse common tooling such as `ethers.js`, `alloy.rs`, and `cast` without\nmodification.\n\nThe interface covers the transaction submission and receipt lifecycle,\nincluding balance and nonce discovery, read-only contract calls, log\nqueries, and real-time subscriptions.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/eth_chainId":{"post":{"tags":["Ethereum Interface (eth_)"],"summary":"Get Chain ID","operationId":"eth_chainId","description":"Returns the chain ID used for signing transactions (EIP-155).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"eth_chainId"},"id":{"type":"integer","default":1},"params":{"type":"array","default":[]}}}}}},"responses":{"200":{"description":"Chain ID (hex-encoded)","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"type":"string"},"id":{"type":"integer"}}}}}}}}}}}
```

## Get Transaction by Hash

> Returns the transaction that matches the given hash, or null if not found.<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Ethereum Interface (eth_)","description":"Ethereum Interface (`eth_`) provides an Ethereum-compatible JSON-RPC layer\nthat allows existing wallets, tools, and libraries to interact with Pod\nusing familiar methods and conventions. It is designed to be drop-in\ncompatible with standard Ethereum client workflows, allowing developers to\nuse common tooling such as `ethers.js`, `alloy.rs`, and `cast` without\nmodification.\n\nThe interface covers the transaction submission and receipt lifecycle,\nincluding balance and nonce discovery, read-only contract calls, log\nqueries, and real-time subscriptions.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/eth_getTransactionByHash":{"post":{"tags":["Ethereum Interface (eth_)"],"summary":"Get Transaction by Hash","operationId":"eth_getTransactionByHash","description":"Returns the transaction that matches the given hash, or null if not found.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"eth_getTransactionByHash"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `transaction_hash` (bytes32): The transaction hash to look up\n","items":{"$ref":"#/components/schemas/Bytes32"}}}}}}},"responses":{"200":{"description":"Transaction object, or `null` if not found.","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"$ref":"#/components/schemas/Transaction"},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"Transaction":{"type":"object","description":"Transaction object returned by eth_getTransactionByHash","properties":{"hash":{"$ref":"#/components/schemas/Bytes32"},"nonce":{"type":"string"},"blockHash":{"$ref":"#/components/schemas/Bytes32","nullable":true},"blockNumber":{"type":"string","nullable":true},"transactionIndex":{"type":"string","nullable":true},"from":{"$ref":"#/components/schemas/Address"},"to":{"$ref":"#/components/schemas/Address","nullable":true},"value":{"$ref":"#/components/schemas/HexUint256"},"gas":{"type":"string"},"gasPrice":{"type":"string"},"input":{"type":"string"},"v":{"type":"string"},"r":{"type":"string"},"s":{"type":"string"}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"}}}}
```

## Get Transaction Count (Nonce)

> Returns the transaction count (nonce) for the specified address.\
> Required for transaction signing to prevent replay attacks.\
> The nonce is the current transaction count for the address.\
> \
> \*\*Pod-specific:\*\* The \`block\_tag\` parameter is accepted for Ethereum compatibility but is ignored.<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Ethereum Interface (eth_)","description":"Ethereum Interface (`eth_`) provides an Ethereum-compatible JSON-RPC layer\nthat allows existing wallets, tools, and libraries to interact with Pod\nusing familiar methods and conventions. It is designed to be drop-in\ncompatible with standard Ethereum client workflows, allowing developers to\nuse common tooling such as `ethers.js`, `alloy.rs`, and `cast` without\nmodification.\n\nThe interface covers the transaction submission and receipt lifecycle,\nincluding balance and nonce discovery, read-only contract calls, log\nqueries, and real-time subscriptions.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/eth_getTransactionCount":{"post":{"tags":["Ethereum Interface (eth_)"],"summary":"Get Transaction Count (Nonce)","operationId":"eth_getTransactionCount","description":"Returns the transaction count (nonce) for the specified address.\nRequired for transaction signing to prevent replay attacks.\nThe nonce is the current transaction count for the address.\n\n**Pod-specific:** The `block_tag` parameter is accepted for Ethereum compatibility but is ignored.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"eth_getTransactionCount"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `address` (address): The address to get nonce for\n2. `block_tag` (string): Block tag (accepted but ignored)\n"}}}}}},"responses":{"200":{"description":"Nonce (hex-encoded uint256)","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"$ref":"#/components/schemas/HexUint256"},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"}}}}
```

## Send Raw Transaction (Fire-and-Forget)

> Submits a signed EIP-1559 transaction to the network. Returns the transaction hash on success.\
> \
> The transaction must be RLP-encoded and signed. Use this method to submit orderbook operations\
> (deposits, withdrawals, order submissions, cancellations) to the orderbook contract.\
> \
> For synchronous attestation feedback (successes/errors from validators), use \`pod\_sendRawTransaction\`.<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Ethereum Interface (eth_)","description":"Ethereum Interface (`eth_`) provides an Ethereum-compatible JSON-RPC layer\nthat allows existing wallets, tools, and libraries to interact with Pod\nusing familiar methods and conventions. It is designed to be drop-in\ncompatible with standard Ethereum client workflows, allowing developers to\nuse common tooling such as `ethers.js`, `alloy.rs`, and `cast` without\nmodification.\n\nThe interface covers the transaction submission and receipt lifecycle,\nincluding balance and nonce discovery, read-only contract calls, log\nqueries, and real-time subscriptions.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/eth_sendRawTransaction":{"post":{"tags":["Ethereum Interface (eth_)"],"summary":"Send Raw Transaction (Fire-and-Forget)","operationId":"eth_sendRawTransaction","description":"Submits a signed EIP-1559 transaction to the network. Returns the transaction hash on success.\n\nThe transaction must be RLP-encoded and signed. Use this method to submit orderbook operations\n(deposits, withdrawals, order submissions, cancellations) to the orderbook contract.\n\nFor synchronous attestation feedback (successes/errors from validators), use `pod_sendRawTransaction`.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"eth_sendRawTransaction"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `signed_tx` (string): Signed RLP-encoded transaction data\n","items":{"type":"string","description":"Signed RLP-encoded transaction"}}}}}}},"responses":{"200":{"description":"Transaction hash","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"$ref":"#/components/schemas/Bytes32"},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."}}}}
```

## Execute Read-Only Call

> Executes a new message call immediately without creating a transaction on the blockchain.\
> \
> Use this method for read-only operations on the orderbook contract, such as:\
> \- \`balanceOf(address token, address account)\` - Get deposited balance for a token\
> \
> \*\*Orderbook Contract Address:\*\* \`0x50d0000000000000000000000000000000000002\`<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Ethereum Interface (eth_)","description":"Ethereum Interface (`eth_`) provides an Ethereum-compatible JSON-RPC layer\nthat allows existing wallets, tools, and libraries to interact with Pod\nusing familiar methods and conventions. It is designed to be drop-in\ncompatible with standard Ethereum client workflows, allowing developers to\nuse common tooling such as `ethers.js`, `alloy.rs`, and `cast` without\nmodification.\n\nThe interface covers the transaction submission and receipt lifecycle,\nincluding balance and nonce discovery, read-only contract calls, log\nqueries, and real-time subscriptions.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/eth_call":{"post":{"tags":["Ethereum Interface (eth_)"],"summary":"Execute Read-Only Call","operationId":"eth_call","description":"Executes a new message call immediately without creating a transaction on the blockchain.\n\nUse this method for read-only operations on the orderbook contract, such as:\n- `balanceOf(address token, address account)` - Get deposited balance for a token\n\n**Orderbook Contract Address:** `0x50d0000000000000000000000000000000000002`\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"eth_call"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `transaction` (object): Call object with `to`, `data`, and optionally `from`\n2. `block_tag` (string): Block tag (e.g., \"latest\")\n"}}}}}},"responses":{"200":{"description":"Return data (hex-encoded)","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"type":"string"},"id":{"type":"integer"}}}}}}}}}}}
```

## Get Transaction Receipt

> Retrieves the transaction receipt including execution status and event logs.\
> \
> \*\*Pod-specific:\*\* The receipt includes \`pod\_metadata\` containing validator attestations for transaction finality verification.\
> \
> Returns \`null\` if the transaction is not found or not yet processed.<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Ethereum Interface (eth_)","description":"Ethereum Interface (`eth_`) provides an Ethereum-compatible JSON-RPC layer\nthat allows existing wallets, tools, and libraries to interact with Pod\nusing familiar methods and conventions. It is designed to be drop-in\ncompatible with standard Ethereum client workflows, allowing developers to\nuse common tooling such as `ethers.js`, `alloy.rs`, and `cast` without\nmodification.\n\nThe interface covers the transaction submission and receipt lifecycle,\nincluding balance and nonce discovery, read-only contract calls, log\nqueries, and real-time subscriptions.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/eth_getTransactionReceipt":{"post":{"tags":["Ethereum Interface (eth_)"],"summary":"Get Transaction Receipt","operationId":"eth_getTransactionReceipt","description":"Retrieves the transaction receipt including execution status and event logs.\n\n**Pod-specific:** The receipt includes `pod_metadata` containing validator attestations for transaction finality verification.\n\nReturns `null` if the transaction is not found or not yet processed.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"eth_getTransactionReceipt"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `transaction_hash` (bytes32): The transaction hash to look up\n","items":{"$ref":"#/components/schemas/Bytes32"}}}}}}},"responses":{"200":{"description":"Transaction receipt with Pod-specific attestation data, or `null` if not found.","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"$ref":"#/components/schemas/TransactionReceipt"},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"TransactionReceipt":{"type":"object","description":"Transaction receipt with execution status, logs, and Pod-specific metadata","properties":{"type":{"type":"string","description":"Transaction type (EIP-2718)"},"status":{"type":"string","enum":["0x0","0x1"],"description":"Execution status - \"0x1\" for success, \"0x0\" for failure"},"cumulativeGasUsed":{"$ref":"#/components/schemas/HexUint256"},"logs":{"type":"array","items":{"$ref":"#/components/schemas/Log"}},"logsBloom":{"type":"string","description":"Bloom filter for logs (hex-encoded)"},"transactionHash":{"$ref":"#/components/schemas/Bytes32"},"transactionIndex":{"type":"string","description":"Transaction index in block (hex-encoded)"},"blockHash":{"$ref":"#/components/schemas/Bytes32"},"blockNumber":{"type":"string","description":"Block number (hex-encoded)"},"gasUsed":{"$ref":"#/components/schemas/HexUint256"},"effectiveGasPrice":{"$ref":"#/components/schemas/HexUint256"},"from":{"$ref":"#/components/schemas/Address"},"to":{"$ref":"#/components/schemas/Address"},"contractAddress":{"type":"string","nullable":true,"description":"Contract address if this was a contract creation (null otherwise)"},"pod_metadata":{"$ref":"#/components/schemas/PodMetadata","description":"Pod-specific attestation data for transaction finality verification"}}},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"Log":{"type":"object","description":"Event log emitted during transaction execution","properties":{"address":{"$ref":"#/components/schemas/Address","description":"Address of the contract that emitted the log"},"topics":{"type":"array","items":{"$ref":"#/components/schemas/Bytes32"},"description":"Indexed event parameters"},"data":{"type":"string","description":"Non-indexed event data (hex-encoded)"}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"PodMetadata":{"type":"object","description":"Pod-specific metadata containing validator attestations for finality verification","properties":{"attestations":{"type":"array","items":{"$ref":"#/components/schemas/PodAttestation"},"description":"List of validator attestations for the transaction"},"committee_epoch":{"type":"integer","format":"int64","description":"The committee epoch during which the transaction was attested"}}},"PodAttestation":{"type":"object","description":"Validator attestation for a transaction","properties":{"validator_address":{"$ref":"#/components/schemas/Address","description":"Address of the attesting validator"},"sequence_number":{"type":"integer","format":"int64","description":"Sequence number of the attestation"},"batch_index":{"type":"integer","description":"Index within the attestation batch"},"timestamp":{"$ref":"#/components/schemas/Timestamp","description":"Timestamp when the attestation was created (microseconds)"},"signature":{"type":"string","description":"Hex-encoded secp256k1 ECDSA signature"}}},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```

## Estimate Gas

> Estimates the gas required for a transaction.\
> \
> \*\*Pod-specific behavior:\*\* If the transaction already specifies a gas value, returns that value.\
> Otherwise, returns \`21000\` (standard transaction gas).<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Ethereum Interface (eth_)","description":"Ethereum Interface (`eth_`) provides an Ethereum-compatible JSON-RPC layer\nthat allows existing wallets, tools, and libraries to interact with Pod\nusing familiar methods and conventions. It is designed to be drop-in\ncompatible with standard Ethereum client workflows, allowing developers to\nuse common tooling such as `ethers.js`, `alloy.rs`, and `cast` without\nmodification.\n\nThe interface covers the transaction submission and receipt lifecycle,\nincluding balance and nonce discovery, read-only contract calls, log\nqueries, and real-time subscriptions.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/eth_estimateGas":{"post":{"tags":["Ethereum Interface (eth_)"],"summary":"Estimate Gas","operationId":"eth_estimateGas","description":"Estimates the gas required for a transaction.\n\n**Pod-specific behavior:** If the transaction already specifies a gas value, returns that value.\nOtherwise, returns `21000` (standard transaction gas).\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"eth_estimateGas"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `transaction` (object): Transaction object with `to`, `data`, `value`, `from`, etc.\n"}}}}}},"responses":{"200":{"description":"Estimated gas (hex-encoded)","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"$ref":"#/components/schemas/HexUint256"},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"}}}}
```

## Get Logs

> Returns an array of log objects matching the given filter criteria.

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Ethereum Interface (eth_)","description":"Ethereum Interface (`eth_`) provides an Ethereum-compatible JSON-RPC layer\nthat allows existing wallets, tools, and libraries to interact with Pod\nusing familiar methods and conventions. It is designed to be drop-in\ncompatible with standard Ethereum client workflows, allowing developers to\nuse common tooling such as `ethers.js`, `alloy.rs`, and `cast` without\nmodification.\n\nThe interface covers the transaction submission and receipt lifecycle,\nincluding balance and nonce discovery, read-only contract calls, log\nqueries, and real-time subscriptions.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/eth_getLogs":{"post":{"tags":["Ethereum Interface (eth_)"],"summary":"Get Logs","operationId":"eth_getLogs","description":"Returns an array of log objects matching the given filter criteria.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"eth_getLogs"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `filter` (object): Filter object with `address`, `topics`, `fromBlock`, `toBlock`\n"}}}}}},"responses":{"200":{"description":"Array of log objects","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"type":"array","items":{"$ref":"#/components/schemas/Log"}},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Log":{"type":"object","description":"Event log emitted during transaction execution","properties":{"address":{"$ref":"#/components/schemas/Address","description":"Address of the contract that emitted the log"},"topics":{"type":"array","items":{"$ref":"#/components/schemas/Bytes32"},"description":"Indexed event parameters"},"data":{"type":"string","description":"Non-indexed event data (hex-encoded)"}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."}}}}
```

## Subscribe to Events (WebSocket)

> Creates a subscription to receive real-time updates over WebSocket. Updates are pushed\
> after each auction settlement for the subscribed orderbook(s) / account.\
> \
> \*\*Subscription types:\*\*\
> \- \`pod\_orderbook\` — each notification is a single \`OrderbookSnapshot\` for the orderbook\
> &#x20; (the same shape \`ob\_getOrderbook\` returns).\
> \- \`pod\_orders\` — each notification is an \*\*array of \`OrderUpdate\`\*\* describing what changed\
> &#x20; to orders this settlement: new/invalid orders, expirations, cancellations, modifications,\
> &#x20; and fills.\
> \- \`pod\_orders\_v2\` — the same information as \`pod\_orders\` in a smaller, extensible frame: one\
> &#x20; \`OrdersFrameV2\` per orderbook per batch, which names the batch and the orderbook once,\
> &#x20; publishes each order created in that batch once, and expresses everything else as events\
> &#x20; referencing it. Prefer this for new integrations; \`pod\_orders\` is unchanged and stays\
> &#x20; supported.\
> \- \`pod\_candles\` — a per-tick candle hint (\`CandleTick\`) per cleared orderbook: clearing\
> &#x20; price and volume at the batch deadline, for folding into the forming bar. Not a closed\
> &#x20; OHLCV bar (see \`ob\_getCandles\`).\
> \- \`pod\_markets\` — a \`MarketDynamicEntry\` per orderbook carrying live market statistics\
> &#x20; (last clearing price, 24h volume/high/low, and perp mark/oracle/funding/open-interest).\
> \- \`pod\_positions\` — a \`PositionsUpdate\` (\`{ account, data }\`, where \`data\` matches\
> &#x20; \`ob\_getPositions\`) for the subscribed account, pushed when a settlement touches it.\
> &#x20; \*\*Requires\*\* \`account\` (alias \`bidder\`).\
> \- \`pod\_triggers\` — a \`TriggersUpdate\` (the \`ob\_getTriggers\` fields plus \`account\`) for the\
> &#x20; subscribed account, pushed when a settlement touches it. \*\*Requires\*\* \`account\`.\
> \
> \`pod\_orderbook\`, \`pod\_orders\`, \`pod\_orders\_v2\`, and \`pod\_candles\` are \*\*delta\*\* channels\
> (they stream what changed each tick). \`pod\_markets\`, \`pod\_positions\`, and \`pod\_triggers\` are \*\*state\*\* channels\
> (each pushes a current snapshot). See \`since\` below for how each behaves on catch-up.\
> \
> Subscriptions follow the standard Ethereum \`eth\_subscribe\` pattern:\
> 1\. Subscribe with \`eth\_subscribe\` → receive a subscription ID.\
> 2\. Receive updates as \`eth\_subscription\` notifications (see the notification shape below).\
> 3\. Cancel with \`eth\_unsubscribe\`, passing the subscription ID.\
> \
> \*\*Notification format.\*\* Updates arrive as JSON-RPC notifications, not responses:\
> \`\`\`json\
> {\
> &#x20; "jsonrpc": "2.0",\
> &#x20; "method": "eth\_subscription",\
> &#x20; "params": { "subscription": "0x\<id>", "result": \<payload> }\
> }\
> \`\`\`\
> The \`result\` payload shape depends on the subscription type (see the list above).\
> \
> \*\*Reading a \`pod\_orders\_v2\` frame.\*\* \`orders\` holds the orders \*created\* in this batch, each\
> once; \`events\` says what happened. An event names its order either by \`o\` (an index into this\
> frame's \`orders\`) or by \`id\` (an order resting from an earlier batch, whose owner is \`a\`) —\
> exactly one of the two. Owners are interned into \`accts\` and referenced by index, except when the\
> subscription names exactly one account, where \`accts\` and every \`a\` are omitted because every\
> row belongs to you. A subscription naming several accounts carries them, so decode on whether\
> \`accts\` is present rather than on whether you sent a filter. Absent optional fields carry a documented default (see \`OrderEntityV2\`), so a\
> plain user-signed limit order is small.\
> \
> Two things clients most often get wrong. \`batch\` is the batch an action \*\*landed in\*\*, which\
> for an order is at or before the \`deadline\` it was signed for — an intent may be included in an\
> earlier batch than it targets. And a fill carries \*\*both\*\* kinds of amount: \`b\`/\`q\` are what\
> that fill filled, while \`tb\`/\`tq\`/\`tf\` are the order's running totals. Apply \`b\`/\`q\`; use the\
> totals to check your own figure. Reading a total as a per-batch amount double-counts. There is\
> no per-fill fee, so difference \`tf\` for that.\
> \
> \*\*Identity.\*\* \`id\` is the resting order id, derived as\
> \`keccak256(abi\_encode(signer, nonce, sequence))\` — the signing key, that transaction's nonce,\
> and the order's position inside a \`submitBatch\` envelope (\`0\` when the transaction carries one\
> intent). You can compute it before broadcasting and match your own orders on the first frame\
> that mentions them. Derive from the \*delegate's\* address for a delegated order: the id keys on\
> the signer, while \`a\`/\`accts\` report the owner. Note \`n\` is the transaction's nonce, so orders\
> from one envelope share \`n\` and \`tx\` and differ only in \`id\`.\
> \
> \*\*Every terminal event carries the order's final totals\*\*, whichever shape ends it: a \`fill\`\
> bearing \`st\` for an order that filled out, or \`cancel\`/\`expire\` for one removed from the book —\
> both with \`tb\`/\`tq\`/\`tf\`. So a terminal handler is uniform and needs no accumulation of the\
> order's earlier fills, which matters for a partially filled order canceled for its remainder:\
> the amounts it did fill travel with the cancel. An order that both fills and terminates in the\
> same batch reports the totals on both events, with the same values.\
> \
> \*\*Forward compatibility.\*\* Clients MUST ignore event kinds (\`k\`) and fields they do not\
> recognise: new event kinds will be added without a new channel version. Existing keys are\
> never renamed or repurposed.\
> \
> \*\*Server-initiated close.\*\* The server may end a subscription on its own — most often because\
> it dropped ticks for a subscriber that fell behind, which it does rather than serve a delta\
> stream with a gap in it. That arrives on the same \`eth\_subscription\` method with \`error\` in\
> place of \`result\`, carrying a code, whether the stream is resumable, and the \`resume\_since\`\
> watermark to resubscribe from:\
> \`\`\`json\
> {\
> &#x20; "jsonrpc": "2.0",\
> &#x20; "method": "eth\_subscription",\
> &#x20; "params": {\
> &#x20;   "subscription": "0x\<id>",\
> &#x20;   "error": { "code": -32020, "message": "…", "data": { "resumable": true, "resume\_since": 1718900000000000 } }\
> &#x20; }\
> }\
> \`\`\`\
> Nothing further is sent for that subscription; the connection and any other subscriptions on\
> it are unaffected. Because a delta stream never has holes, this close is the only signal that\
> data was lost — while a subscription is open, no updates means an idle market. See\
> \[JSON-RPC Errors]\(../json-rpc-errors.md#subscription-close-notifications) for every code and\
> the recommended client response.\
> \
> On \`pod\_orders\_v2\` the close additionally carries \`resume\_since\_book\` whenever the batch it\
> stopped in was only partly delivered — the last \`book\` you were sent. Pass both back, as\
> \`since\` and \`since\_book\`, and you receive exactly the frames you never got: no replay, no gap.\
> This is the case the two-part cursor exists for, because a close midway through a batch is\
> precisely when you cannot tell where you got to — frames already accepted by the connection\
> may not have reached your code yet. \`resume\_since\_book\` is absent when the batch landed whole,\
> and then \`resume\_since\` alone is the position.\
> \
> \*\*Filtering.\*\* \`pod\_orderbook\`, \`pod\_orders\`, \`pod\_orders\_v2\`, \`pod\_candles\`, and \`pod\_markets\` accept\
> \`orderbook\_ids\` (alias \`clob\_ids\`) to restrict the stream to specific orderbooks\
> (empty/omitted = all). \`pod\_orders\` and \`pod\_orders\_v2\` additionally accept \`bidder\` to deliver\
> only that account's updates, and \`pod\_orders\_v2\` accepts \`bidders\` — a set of up to 64\
> distinct accounts — to follow several on one subscription instead of opening one each.\
> \`bidder\` and \`bidders\` are mutually exclusive, and naming more than one account makes the\
> frame carry \`accts\`/\`a\` (see above). \`pod\_positions\` and \`pod\_triggers\` are account-scoped and \*\*require\*\*\
> \`account\` (alias \`bidder\`); they ignore \`orderbook\_ids\`. \`depth\` applies to \`pod\_orderbook\`\
> snapshots only.\
> \
> \*\*Catch-up (\`since\`).\*\* Optionally pass \`since\` (a solution time in \*\*microseconds\*\*) to\
> catch up with no gap or duplicate. Delta channels (\`pod\_orderbook\`, \`pod\_orders\`,\
> \`pod\_candles\`) replay buffered ticks with deadline strictly greater than \`since\`; if \`since\`\
> predates the retained buffer the subscription is rejected (backfill via REST and\
> resubscribe). State channels (\`pod\_markets\`, \`pod\_positions\`, \`pod\_triggers\`) emit one\
> current snapshot immediately, then stream live. Omitted = live-only. Which option applies to\
> which subscription type is summarised in \`SubscriptionParams\`.\
> \
> \*\*Catch-up on \`pod\_orders\_v2\` (\`since\` + \`since\_book\`).\*\* One batch settles many orderbooks\
> and is delivered as one frame each, so a batch is not atomic on the wire — a client can hold\
> part of one. Resume on the \*\*pair\*\*: \`since\` is the \`batch\` of the last frame you accepted and\
> \`since\_book\` its \`book\`. Replay then skips every book at or below \`since\_book\` within that\
> batch and delivers later batches whole, so a client that accepted 7 of 10 books receives the\
> remaining 3 without a gap or a duplicate. Track one pair, not a per-book map. Omitting\
> \`since\_book\` means "the whole of \`since\` arrived", which is correct if you subscribe to a\
> single orderbook, because a batch is then one frame.<br>

````json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Ethereum Interface (eth_)","description":"Ethereum Interface (`eth_`) provides an Ethereum-compatible JSON-RPC layer\nthat allows existing wallets, tools, and libraries to interact with Pod\nusing familiar methods and conventions. It is designed to be drop-in\ncompatible with standard Ethereum client workflows, allowing developers to\nuse common tooling such as `ethers.js`, `alloy.rs`, and `cast` without\nmodification.\n\nThe interface covers the transaction submission and receipt lifecycle,\nincluding balance and nonce discovery, read-only contract calls, log\nqueries, and real-time subscriptions.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/eth_subscribe":{"post":{"tags":["Ethereum Interface (eth_)"],"summary":"Subscribe to Events (WebSocket)","operationId":"eth_subscribe","description":"Creates a subscription to receive real-time updates over WebSocket. Updates are pushed\nafter each auction settlement for the subscribed orderbook(s) / account.\n\n**Subscription types:**\n- `pod_orderbook` — each notification is a single `OrderbookSnapshot` for the orderbook\n  (the same shape `ob_getOrderbook` returns).\n- `pod_orders` — each notification is an **array of `OrderUpdate`** describing what changed\n  to orders this settlement: new/invalid orders, expirations, cancellations, modifications,\n  and fills.\n- `pod_orders_v2` — the same information as `pod_orders` in a smaller, extensible frame: one\n  `OrdersFrameV2` per orderbook per batch, which names the batch and the orderbook once,\n  publishes each order created in that batch once, and expresses everything else as events\n  referencing it. Prefer this for new integrations; `pod_orders` is unchanged and stays\n  supported.\n- `pod_candles` — a per-tick candle hint (`CandleTick`) per cleared orderbook: clearing\n  price and volume at the batch deadline, for folding into the forming bar. Not a closed\n  OHLCV bar (see `ob_getCandles`).\n- `pod_markets` — a `MarketDynamicEntry` per orderbook carrying live market statistics\n  (last clearing price, 24h volume/high/low, and perp mark/oracle/funding/open-interest).\n- `pod_positions` — a `PositionsUpdate` (`{ account, data }`, where `data` matches\n  `ob_getPositions`) for the subscribed account, pushed when a settlement touches it.\n  **Requires** `account` (alias `bidder`).\n- `pod_triggers` — a `TriggersUpdate` (the `ob_getTriggers` fields plus `account`) for the\n  subscribed account, pushed when a settlement touches it. **Requires** `account`.\n\n`pod_orderbook`, `pod_orders`, `pod_orders_v2`, and `pod_candles` are **delta** channels\n(they stream what changed each tick). `pod_markets`, `pod_positions`, and `pod_triggers` are **state** channels\n(each pushes a current snapshot). See `since` below for how each behaves on catch-up.\n\nSubscriptions follow the standard Ethereum `eth_subscribe` pattern:\n1. Subscribe with `eth_subscribe` → receive a subscription ID.\n2. Receive updates as `eth_subscription` notifications (see the notification shape below).\n3. Cancel with `eth_unsubscribe`, passing the subscription ID.\n\n**Notification format.** Updates arrive as JSON-RPC notifications, not responses:\n```json\n{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"eth_subscription\",\n  \"params\": { \"subscription\": \"0x<id>\", \"result\": <payload> }\n}\n```\nThe `result` payload shape depends on the subscription type (see the list above).\n\n**Reading a `pod_orders_v2` frame.** `orders` holds the orders *created* in this batch, each\nonce; `events` says what happened. An event names its order either by `o` (an index into this\nframe's `orders`) or by `id` (an order resting from an earlier batch, whose owner is `a`) —\nexactly one of the two. Owners are interned into `accts` and referenced by index, except when the\nsubscription names exactly one account, where `accts` and every `a` are omitted because every\nrow belongs to you. A subscription naming several accounts carries them, so decode on whether\n`accts` is present rather than on whether you sent a filter. Absent optional fields carry a documented default (see `OrderEntityV2`), so a\nplain user-signed limit order is small.\n\nTwo things clients most often get wrong. `batch` is the batch an action **landed in**, which\nfor an order is at or before the `deadline` it was signed for — an intent may be included in an\nearlier batch than it targets. And a fill carries **both** kinds of amount: `b`/`q` are what\nthat fill filled, while `tb`/`tq`/`tf` are the order's running totals. Apply `b`/`q`; use the\ntotals to check your own figure. Reading a total as a per-batch amount double-counts. There is\nno per-fill fee, so difference `tf` for that.\n\n**Identity.** `id` is the resting order id, derived as\n`keccak256(abi_encode(signer, nonce, sequence))` — the signing key, that transaction's nonce,\nand the order's position inside a `submitBatch` envelope (`0` when the transaction carries one\nintent). You can compute it before broadcasting and match your own orders on the first frame\nthat mentions them. Derive from the *delegate's* address for a delegated order: the id keys on\nthe signer, while `a`/`accts` report the owner. Note `n` is the transaction's nonce, so orders\nfrom one envelope share `n` and `tx` and differ only in `id`.\n\n**Every terminal event carries the order's final totals**, whichever shape ends it: a `fill`\nbearing `st` for an order that filled out, or `cancel`/`expire` for one removed from the book —\nboth with `tb`/`tq`/`tf`. So a terminal handler is uniform and needs no accumulation of the\norder's earlier fills, which matters for a partially filled order canceled for its remainder:\nthe amounts it did fill travel with the cancel. An order that both fills and terminates in the\nsame batch reports the totals on both events, with the same values.\n\n**Forward compatibility.** Clients MUST ignore event kinds (`k`) and fields they do not\nrecognise: new event kinds will be added without a new channel version. Existing keys are\nnever renamed or repurposed.\n\n**Server-initiated close.** The server may end a subscription on its own — most often because\nit dropped ticks for a subscriber that fell behind, which it does rather than serve a delta\nstream with a gap in it. That arrives on the same `eth_subscription` method with `error` in\nplace of `result`, carrying a code, whether the stream is resumable, and the `resume_since`\nwatermark to resubscribe from:\n```json\n{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"eth_subscription\",\n  \"params\": {\n    \"subscription\": \"0x<id>\",\n    \"error\": { \"code\": -32020, \"message\": \"…\", \"data\": { \"resumable\": true, \"resume_since\": 1718900000000000 } }\n  }\n}\n```\nNothing further is sent for that subscription; the connection and any other subscriptions on\nit are unaffected. Because a delta stream never has holes, this close is the only signal that\ndata was lost — while a subscription is open, no updates means an idle market. See\n[JSON-RPC Errors](../json-rpc-errors.md#subscription-close-notifications) for every code and\nthe recommended client response.\n\nOn `pod_orders_v2` the close additionally carries `resume_since_book` whenever the batch it\nstopped in was only partly delivered — the last `book` you were sent. Pass both back, as\n`since` and `since_book`, and you receive exactly the frames you never got: no replay, no gap.\nThis is the case the two-part cursor exists for, because a close midway through a batch is\nprecisely when you cannot tell where you got to — frames already accepted by the connection\nmay not have reached your code yet. `resume_since_book` is absent when the batch landed whole,\nand then `resume_since` alone is the position.\n\n**Filtering.** `pod_orderbook`, `pod_orders`, `pod_orders_v2`, `pod_candles`, and `pod_markets` accept\n`orderbook_ids` (alias `clob_ids`) to restrict the stream to specific orderbooks\n(empty/omitted = all). `pod_orders` and `pod_orders_v2` additionally accept `bidder` to deliver\nonly that account's updates, and `pod_orders_v2` accepts `bidders` — a set of up to 64\ndistinct accounts — to follow several on one subscription instead of opening one each.\n`bidder` and `bidders` are mutually exclusive, and naming more than one account makes the\nframe carry `accts`/`a` (see above). `pod_positions` and `pod_triggers` are account-scoped and **require**\n`account` (alias `bidder`); they ignore `orderbook_ids`. `depth` applies to `pod_orderbook`\nsnapshots only.\n\n**Catch-up (`since`).** Optionally pass `since` (a solution time in **microseconds**) to\ncatch up with no gap or duplicate. Delta channels (`pod_orderbook`, `pod_orders`,\n`pod_candles`) replay buffered ticks with deadline strictly greater than `since`; if `since`\npredates the retained buffer the subscription is rejected (backfill via REST and\nresubscribe). State channels (`pod_markets`, `pod_positions`, `pod_triggers`) emit one\ncurrent snapshot immediately, then stream live. Omitted = live-only. Which option applies to\nwhich subscription type is summarised in `SubscriptionParams`.\n\n**Catch-up on `pod_orders_v2` (`since` + `since_book`).** One batch settles many orderbooks\nand is delivered as one frame each, so a batch is not atomic on the wire — a client can hold\npart of one. Resume on the **pair**: `since` is the `batch` of the last frame you accepted and\n`since_book` its `book`. Replay then skips every book at or below `since_book` within that\nbatch and delivers later batches whole, so a client that accepted 7 of 10 books receives the\nremaining 3 without a gap or a duplicate. Track one pair, not a per-book map. Omitting\n`since_book` means \"the whole of `since` arrived\", which is correct if you subscribe to a\nsingle orderbook, because a batch is then one frame.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"eth_subscribe"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `subscription_type` (string): one of `pod_orderbook`, `pod_orders`,\n   `pod_orders_v2`, `pod_candles`, `pod_markets`, `pod_positions`,\n   `pod_triggers`.\n2. `options` (SubscriptionParams): filter/format options; all fields optional\n   except where a channel requires `account`. Which fields take effect depends on\n   the subscription type:\n   - `orderbook_ids` (alias `clob_ids`, array of bytes32) — `pod_orderbook`,\n     `pod_orders`, `pod_orders_v2`, `pod_candles`, `pod_markets`: restrict to\n     those orderbooks (empty/omitted = all). Ignored by `pod_positions` /\n     `pod_triggers`.\n   - `depth` (integer) — **`pod_orderbook` only**: cap the price levels per side\n     in each snapshot (omit for all levels).\n   - `bidder` (alias `account`, address) — `pod_orders`, `pod_orders_v2`:\n     stream only that bidder's updates (omit for all). **Required** for\n     `pod_positions` and `pod_triggers` (the account to stream).\n   - `bidders` (array of addresses) — **`pod_orders_v2` only**: follow several\n     accounts on one subscription. A set — order irrelevant, repeats collapsed —\n     capped at 64 distinct accounts. Mutually exclusive with `bidder`; rejected\n     on other channels. More than one account makes the frame carry `accts`/`a`.\n   - `since` (integer, microseconds) — all channels: catch-up watermark (see the\n     method description).\n   - `since_book` (bytes32) — **`pod_orders_v2` only**: the `book` of the last\n     frame accepted at `since`, completing the resume cursor (see the method\n     description). Omit if the whole of `since` arrived.\n","items":{"oneOf":[{"type":"string","enum":["pod_orderbook","pod_orders","pod_orders_v2","pod_candles","pod_markets","pod_positions","pod_triggers"]},{"$ref":"#/components/schemas/SubscriptionParams"}]}}}}}}},"responses":{"200":{"description":"Messages received on the subscription. The immediate reply to `eth_subscribe` is the\nsubscription ID; every subsequent message is an `eth_subscription` notification whose\n`params.result` carries the streamed payload — its shape determined by the subscription\ntype (see the method description and `EthSubscriptionMessage`).\n","content":{"application/json":{"schema":{"oneOf":[{"title":"Subscription confirmation (immediate reply)","type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"type":"string","description":"Subscription ID"},"id":{"type":"integer"}}},{"$ref":"#/components/schemas/EthSubscriptionMessage"}]}}}}}}}},"components":{"schemas":{"SubscriptionParams":{"type":"object","description":"Options object (second `eth_subscribe` param). All fields are optional except that\n`pod_positions` / `pod_triggers` require `account` (alias `bidder`). Which fields take\neffect depends on the subscription type:\n- `orderbook_ids` (alias `clob_ids`) — `pod_orderbook`, `pod_orders`, `pod_orders_v2`,\n  `pod_candles`, `pod_markets`; ignored by `pod_positions` / `pod_triggers`.\n- `depth` — `pod_orderbook` only.\n- `bidder` (alias `account`) — optional for `pod_orders` / `pod_orders_v2`; **required** for\n  `pod_positions` and `pod_triggers`.\n- `bidders` — `pod_orders_v2` only, to follow several accounts on one subscription.\n  Mutually exclusive with `bidder`.\n- `since` — all channels (catch-up watermark, microseconds).\n- `since_book` — `pod_orders_v2` only, completing its `(batch, book)` resume cursor.\n","properties":{"depth":{"type":"integer","description":"`pod_orderbook` only: maximum price levels per side to include in snapshots. Omit for all levels."},"orderbook_ids":{"type":"array","items":{"$ref":"#/components/schemas/Bytes32"},"description":"Orderbook (clob) IDs to restrict the subscription to (accepted alias: `clob_ids`). Empty or omitted = all orderbooks. Honored by `pod_orderbook`, `pod_orders`, `pod_candles`, `pod_markets`; ignored by the account-scoped channels."},"clob_ids":{"type":"array","items":{"$ref":"#/components/schemas/Bytes32"},"description":"Accepted alias for `orderbook_ids`."},"bidder":{"$ref":"#/components/schemas/Address","description":"Account filter (accepted alias: `account`). For `pod_orders`, when set, streams only this bidder's updates (omit for all bidders). For `pod_positions` / `pod_triggers` this is **required** — the account whose positions / triggers to stream. On `pod_orders_v2` it is the single-account form of `bidders`, and sending both is an error."},"bidders":{"type":"array","items":{"$ref":"#/components/schemas/Address"},"description":"`pod_orders_v2` only: follow several accounts on one subscription, streaming\nonly rows owned by them. One subscription instead of one per account — each\nsubscription costs the server a copy of every batch, a notification and a\nsocket write whether or not your accounts traded, so this is markedly\ncheaper than N of them.\n\nTreated as a **set**: order is irrelevant and repeats are collapsed, so the\n64-account limit counts *distinct* accounts. Exceeding it is an error, as is\nsending it together with `bidder` (which is the single-account form) or on\nany other channel — a filter that silently did not apply would hand you the\nwhole book.\n\n**This changes the frame shape.** With more than one account the frame\ncarries the `accts` table and every row carries an `a` index, exactly as an\nunfiltered stream does, because otherwise its rows would not be\nattributable. With exactly one account (whether via `bidders` or `bidder`)\nboth are omitted, since every row belongs to you. Decode on the presence of\n`accts`, not on whether you sent a filter.\n"},"since":{"type":"integer","format":"int64","description":"Catch-up watermark: a solution time in microseconds. Delta channels replay buffered ticks after it; state channels emit one current snapshot then stream live. Omit for live-only. If a delta channel's `since` predates the retained buffer, the subscription is rejected."},"since_book":{"$ref":"#/components/schemas/Bytes32","description":"`pod_orders_v2` only: the `book` of the last frame accepted at `since`, which together with it forms the resume cursor. A batch is delivered as one frame per orderbook, so a client can hold part of a batch; replay skips every book at or below this one within `since`, then delivers later batches whole. Omit when the whole of `since` arrived (always true when subscribed to a single orderbook)."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"EthSubscriptionMessage":{"type":"object","description":"An asynchronous `eth_subscription` notification pushed over the WebSocket after\n`eth_subscribe`. The `params.result` payload depends on the subscription type:\n- `pod_orderbook` → an `OrderbookSnapshot`.\n- `pod_orders` → an array of `OrderUpdate`.\n- `pod_candles` → a `CandleTick`.\n- `pod_markets` → a `MarketDynamicEntry`.\n- `pod_positions` → a `PositionsUpdate`.\n- `pod_triggers` → a `TriggersUpdate`.\n","properties":{"jsonrpc":{"type":"string","enum":["2.0"]},"method":{"type":"string","enum":["eth_subscription"]},"params":{"type":"object","properties":{"subscription":{"type":"string","description":"The subscription ID this message belongs to."},"result":{"description":"The streamed payload — shape determined by the subscription type.","oneOf":[{"$ref":"#/components/schemas/OrderbookSnapshot"},{"type":"array","items":{"$ref":"#/components/schemas/OrderUpdate"}},{"$ref":"#/components/schemas/CandleTick"},{"$ref":"#/components/schemas/MarketDynamicEntry"},{"$ref":"#/components/schemas/PositionsUpdate"},{"$ref":"#/components/schemas/TriggersUpdate"}]}}}}},"OrderbookSnapshot":{"type":"object","description":"Current state of an orderbook with aggregated buy/sell levels.\nThe response field is `orderbook_id`; `clob_id` is accepted as an input alias when deserializing.\n","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32","description":"Orderbook identifier. Also accepts `clob_id` as an alias on input."},"buys":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/TickSnapshot"},"description":"Buy orders keyed by price (decimal string), sorted by price descending"},"sells":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/TickSnapshot"},"description":"Sell orders keyed by price (decimal string), sorted by price ascending"},"clearing_price":{"$ref":"#/components/schemas/HexUint256","description":"Current/last clearing price"},"grouping_precision":{"$ref":"#/components/schemas/HexUint256","description":"Price grouping precision used for aggregation (1e18, hex-encoded)"},"timestamp":{"type":"integer","description":"Snapshot timestamp in microseconds"},"new_orders_count":{"type":"integer","description":"Number of new orders since the last snapshot"},"buys_count":{"type":"integer","description":"Total number of buy orders in the orderbook (regardless of depth parameter)"},"sells_count":{"type":"integer","description":"Total number of sell orders in the orderbook (regardless of depth parameter)"},"oracle_price":{"type":"string","nullable":true,"description":"Perp orderbooks only. Pyth oracle price from the most recent perp solution's `priceProof` (1e18, hex-encoded). `null` for spot orderbooks."},"funding_rate":{"type":"string","nullable":true,"description":"Perp orderbooks only. Funding rate computed for this batch (per-`funding_window`, signed 1e18 decimal string). `null` for spot orderbooks."},"funding_index":{"type":"string","nullable":true,"description":"Perp orderbooks only. Cumulative per-unit-size funding accumulator after this batch (signed 1e18 decimal string). `null` for spot orderbooks."},"funding_last_updated":{"type":"integer","format":"int64","nullable":true,"description":"Perp orderbooks only. Microsecond timestamp of the batch that produced the funding update. `null` for spot orderbooks."}}},"TickSnapshot":{"type":"object","description":"Aggregated order volume at a specific price level","properties":{"volume":{"$ref":"#/components/schemas/HexUint256","description":"Total volume available at this price level (1e18, hex-encoded)"}}},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"OrderUpdate":{"type":"object","description":"A single change to an order, pushed in the `pod_orders` notification array. It is a\n`type`-tagged union: the `type` field selects the variant and the remaining fields depend\non it.\n- `new` / `invalid`: the full `Order` fields are inlined alongside `type` (an `invalid`\n  order was rejected at execution and never entered the book; the reason is on its\n  `status`).\n- `expired` / `canceled`: only `type` and `order_id` are present.\n- `modified`: a resting order's price and/or size was changed in place by an `update`\n  intent — `type`, `order_id`, and the new `new_price` / `new_size` are present.\n- `fill`: the `OrderFillUpdate` fields are inlined alongside `type`.\n","required":["type"],"properties":{"type":{"type":"string","enum":["new","invalid","expired","canceled","modified","fill"],"description":"Discriminator selecting the variant."},"order_id":{"$ref":"#/components/schemas/Bytes32","description":"Present for `expired`, `canceled`, and `modified` — the affected order id."},"new_price":{"$ref":"#/components/schemas/HexUint256","description":"`modified` only: the order's price after the change (1e18)."},"new_size":{"$ref":"#/components/schemas/HexUint256","description":"`modified` only: the order's remaining base size after the change (1e18, unsigned magnitude — side is unchanged from the original `new`)."}}},"CandleTick":{"type":"object","description":"Per-tick candle hint streamed on the `pod_candles` subscription — one object per orderbook\ncleared this settlement. It is not a closed OHLCV bar (use `ob_getCandles` for those); the\nclient folds it into the forming bar.\n","required":["orderbook","timestamp_us","price","volume"],"properties":{"orderbook":{"$ref":"#/components/schemas/Bytes32"},"timestamp_us":{"type":"integer","format":"int64","description":"Batch deadline (settlement time) in microseconds."},"price":{"type":"string","description":"Clearing price for this tick (decimal, 1e18)."},"volume":{"type":"string","description":"Total volume cleared this tick (decimal, 1e18)."}}},"MarketDynamicEntry":{"type":"object","description":"Live market statistics for one orderbook, streamed on the `pod_markets` subscription (one\nobject per orderbook). Optional fields are omitted (not null) when unset — e.g. perp-only\nfields on a spot market, or stats with no data yet.\n","required":["orderbook_id","volume_24h"],"properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"last_clearing_price":{"type":"string","description":"Most recent clearing price (decimal, 1e18). Omitted if the market has not cleared."},"volume_24h":{"type":"string","description":"Rolling 24h traded volume (decimal, 1e18)."},"high_24h":{"type":"string","description":"24h high clearing price (decimal, 1e18). Omitted if unavailable."},"low_24h":{"type":"string","description":"24h low clearing price (decimal, 1e18). Omitted if unavailable."},"price_change_24h":{"type":"integer","format":"int128","description":"24h price change (signed, 1e18), as a JSON number. Omitted if unavailable."},"oracle_price":{"type":"string","description":"Perp only: latest oracle price (decimal, 1e18)."},"mark_price":{"type":"string","description":"Perp only: current mark price (decimal, 1e18)."},"funding_rate":{"type":"string","description":"Perp only: current funding rate (decimal)."},"funding_index":{"type":"string","description":"Perp only: cumulative funding index (decimal)."},"funding_last_updated_us":{"type":"integer","format":"int64","description":"Perp only: last funding update time (microseconds)."},"open_interest":{"type":"string","description":"Perp only: open interest (decimal, 1e18)."}}},"PositionsUpdate":{"type":"object","description":"A `pod_positions` notification — the account's full positions snapshot, pushed for a settlement that touched the account.","required":["account","data"],"properties":{"account":{"$ref":"#/components/schemas/Address"},"data":{"$ref":"#/components/schemas/PositionsResponse"}}},"PositionsResponse":{"type":"object","description":"Account positions across all orderbooks with aggregate PnL.","properties":{"positions":{"type":"array","items":{"$ref":"#/components/schemas/Position"},"description":"Heterogeneous list of spot holdings and open perp positions."},"total_unrealized_pnl":{"type":"string","description":"Sum of `unrealized_pnl` across every spot holding and perp position (signed, 1e18 USD)."},"total_realized_pnl":{"type":"string","description":"Lifetime portfolio-wide spot realized PnL plus the account-level perp realized-PnL counter. Both are cumulative across the account's history — closing a perp does not zero its contribution (signed, 1e18 USD).\n"},"perps_equity":{"type":"string","description":"Cash adjusted for unsettled funding plus unrealized PnL across all open perp positions. Excludes spot holdings (signed, 1e18 USD)."},"account_value":{"type":"string","description":"`perps_equity` plus the mark value of all spot holdings (signed, 1e18 USD)."},"cash":{"type":"string","description":"Deposited collateral adjusted for unsettled funding. Signed — can be negative if the account is underwater (1e18 USD)."},"withdrawable_cash":{"$ref":"#/components/schemas/HexUint256","description":"Free margin — `cash` minus the initial margin reserved by open positions (1e18 USD)."},"net_deposits":{"type":"string","description":"Net native collateral deposited minus withdrawn (signed, 1e18 USD). Negative once realized profit is withdrawn; lifetime PnL is `account_value − net_deposits`."}}},"Position":{"description":"Tagged union: a single entry in `PositionsResponse.positions`. The `kind` field selects between a `SpotHolding` (one per token) or a `PerpPosition` (one per pair).\n","oneOf":[{"$ref":"#/components/schemas/SpotHolding"},{"$ref":"#/components/schemas/PerpPosition"}],"discriminator":{"propertyName":"kind","mapping":{"spot":"#/components/schemas/SpotHolding","perp":"#/components/schemas/PerpPosition"}}},"SpotHolding":{"type":"object","description":"A token balance with cost-basis tracking. One per token the wallet has touched on a spot market.","properties":{"kind":{"type":"string","enum":["spot"],"description":"Discriminator for the `Position` union."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"balance":{"$ref":"#/components/schemas/HexUint256","description":"Total base tokens held for this market (free + locked, 1e18)."},"free_balance":{"$ref":"#/components/schemas/HexUint256","description":"Spendable portion of `balance` after sell-side order locks (1e18)."},"locked_balance":{"$ref":"#/components/schemas/HexUint256","description":"Base tokens locked in open sell orders (`balance - free_balance`, 1e18)."},"cost_basis":{"$ref":"#/components/schemas/HexUint256","description":"Total quote spent to acquire `balance` (1e18 USD)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Last clearing price for this token's market (1e18)."},"unrealized_pnl":{"type":"string","description":"`(mark - avg_cost) × balance` (signed, 1e18 USD)."},"realized_pnl":{"type":"string","description":"Lifetime realized PnL on the user's spot trading (signed, 1e18 USD; portfolio-wide for v1)."}}},"PerpPosition":{"type":"object","description":"A leveraged perp position. One per (user, pair).","properties":{"kind":{"type":"string","enum":["perp"],"description":"Discriminator for the `Position` union."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"side":{"$ref":"#/components/schemas/PerpPositionSide"},"size":{"type":"string","description":"Signed position size in base units (1e18). Positive = long, negative = short."},"notional":{"$ref":"#/components/schemas/HexUint256","description":"`|size| × mark_price / 1e18` — dollar value of exposure (1e18)."},"entry_price":{"$ref":"#/components/schemas/HexUint256","description":"Volume-weighted average entry price; updated only on opening fills (1e18)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Latest mark price for the pair, post batch clearing (1e18)."},"margin":{"$ref":"#/components/schemas/HexUint256","description":"Allocated initial margin; cumulative across opens/increases, released proportionally on partial closes (1e18)."},"leverage":{"$ref":"#/components/schemas/HexUint256","description":"`notional × 1e18 / margin`. Effective leverage (0 if `margin` is 0)."},"funding_accrued":{"type":"string","description":"`(market.funding − position.entry_funding) × size` (signed, 1e18 USD)."},"liquidation_price":{"$ref":"#/components/schemas/HexUint256","description":"Mark price at which this position would be liquidated against its own `margin` and the market's maintenance-margin rate. Funding ignored. 0 when position is empty."},"unrealized_pnl":{"type":"string","description":"`((mark − entry) − (funding − entry_funding)) × size` (signed, 1e18 USD)."},"realized_pnl":{"type":"string","description":"Lifetime realized PnL on this position (signed, 1e18 USD). Resets to 0 when the position closes — the next open of the same pair starts fresh."},"stop_loss":{"$ref":"#/components/schemas/HexUint256","description":"Reserved — stop-loss not yet supported.","nullable":true},"take_profit":{"$ref":"#/components/schemas/HexUint256","description":"Reserved — take-profit not yet supported.","nullable":true}}},"PerpPositionSide":{"type":"string","enum":["long","short"],"description":"Side of a perpetual position, derived from the sign of `size`."},"TriggersUpdate":{"type":"object","description":"A `pod_triggers` notification — the account's armed TP/SL triggers, pushed for a settlement that touched the account. Carries the `GetTriggersResponse` fields inlined alongside `account`.","required":["account","triggers","total_count"],"properties":{"account":{"$ref":"#/components/schemas/Address"},"triggers":{"type":"array","items":{"$ref":"#/components/schemas/TriggerOrderResponse"}},"total_count":{"type":"integer","description":"Count of triggers for the account before pagination."},"next_cursor":{"type":"string","nullable":true,"description":"Pagination cursor, wire format `\"{orderbook_id}:{order_id}\"`. Null if no more results."}}},"TriggerOrderResponse":{"type":"object","description":"An armed TP/SL trigger order, as returned by `ob_getTriggers`.","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"order_id":{"$ref":"#/components/schemas/Bytes32","description":"Identifier of the trigger (and of the synthetic order it produces when it fires)."},"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"Hash of the `submitTrigger` transaction that armed this trigger."},"bidder":{"$ref":"#/components/schemas/Address"},"nonce":{"type":"integer","format":"int64"},"size":{"type":"string","description":"Signed size of the synthetic order produced when the trigger fires (decimal int256). Positive = buy/long, negative = sell/short."},"limit_price":{"$ref":"#/components/schemas/HexUint256","description":"Limit price of the synthetic order produced when the trigger fires (1e18)."},"trigger_price":{"$ref":"#/components/schemas/HexUint256","description":"Mark-price threshold that arms the trigger (1e18)."},"trigger_type":{"$ref":"#/components/schemas/TriggerType"},"grouping":{"$ref":"#/components/schemas/TriggerGrouping"},"reduce_only":{"type":"boolean"},"ioc":{"type":"boolean","description":"Immediate-or-cancel — any unfilled remainder of the fired order is canceled at end of batch."},"deadline":{"$ref":"#/components/schemas/Timestamp"},"end":{"$ref":"#/components/schemas/Timestamp","description":"TTL expiry — the trigger is swept once `end < batch_deadline` (microseconds)."}}},"TriggerType":{"type":"string","enum":["take_profit","stop_loss"],"description":"Type of a TP/SL trigger order on a perp market:\n- `take_profit`: fires when the mark price moves favorably across `trigger_price`\n- `stop_loss`: fires when the mark price moves adversely across `trigger_price`\n\nAlso set on a synthetic order (`kind = triggered`) that a fired trigger produced.\n"},"TriggerGrouping":{"type":"string","enum":["none","asset","position"],"description":"Whether a trigger (and any synthetic order it produces) is bound to the bidder's exposure on the pair:\n- `none`: standalone — the trigger is removed only by a user cancel, TTL expiry, or its own fire; any synthetic order it produced survives independently\n- `asset`: exposure-bound — on perp markets the venue removes the armed trigger *and* any resting synthetic order it produced once the bidder's position on the pair reaches size 0; on spot markets, once the bidder's base-asset holdings reach 0\n\n`asset` was formerly named `position` (same semantics, same ABI value); nodes running older builds still emit `position` and clients should treat the two as equivalent.\n\nOmitted from an `Order` response when it is the default `none`.\n"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
````

## Cancel a Subscription (WebSocket)

> Cancels an active subscription created with \`eth\_subscribe\`. Pass the subscription ID\
> returned by the original \`eth\_subscribe\` call. Returns \`true\` if a matching subscription\
> was found and removed.<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Ethereum Interface (eth_)","description":"Ethereum Interface (`eth_`) provides an Ethereum-compatible JSON-RPC layer\nthat allows existing wallets, tools, and libraries to interact with Pod\nusing familiar methods and conventions. It is designed to be drop-in\ncompatible with standard Ethereum client workflows, allowing developers to\nuse common tooling such as `ethers.js`, `alloy.rs`, and `cast` without\nmodification.\n\nThe interface covers the transaction submission and receipt lifecycle,\nincluding balance and nonce discovery, read-only contract calls, log\nqueries, and real-time subscriptions.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/eth_unsubscribe":{"post":{"tags":["Ethereum Interface (eth_)"],"summary":"Cancel a Subscription (WebSocket)","operationId":"eth_unsubscribe","description":"Cancels an active subscription created with `eth_subscribe`. Pass the subscription ID\nreturned by the original `eth_subscribe` call. Returns `true` if a matching subscription\nwas found and removed.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"eth_unsubscribe"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `subscription_id` (string): The ID returned by `eth_subscribe`\n","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Whether the subscription was found and cancelled","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"type":"boolean"},"id":{"type":"integer"}}}}}}}}}}}
```


# Network & Consensus (pod )

Network & Consensus (`pod_`) exposes Pod-specific endpoints that provide visibility into the network’s validator set and consensus process. These APIs surface data that is not available through standard Ethereum JSON-RPC methods, such as validator committees and aggregated voting information.

This interface is intended for infrastructure providers, validators, and light clients that need to inspect, monitor, or verify the state of the Pod network.

📝 This is a JSON-RPC 2.0 API. The request path is not important; the method to execute is defined by the method field in the request body. You can send all requests to /, and any path after / is optional and used only for documentation clarity.

&#x20;   &#x20;

## Send Raw Transaction (With Attestation Feedback)

> Submits a signed EIP-1559 transaction and waits for validator attestations, returning\
> tx\_hash, success count, and any rejection errors from validators.\
> \
> \*\*Parameters:\*\*\
> \- \`signed\_tx\` (string): Signed RLP-encoded transaction data\
> \- \`timeout\_secs\` (integer, optional): Max seconds to wait for attestations. Default 10.<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Network & Consensus (pod_)","description":"Network & Consensus (`pod_`) exposes Pod-specific endpoints that provide\nvisibility into the network’s validator set and consensus process. These\nAPIs surface data that is not available through standard Ethereum JSON-RPC\nmethods, such as validator committees and aggregated voting information.\n\nThis interface is intended for infrastructure providers, validators, and\nlight clients that need to inspect, monitor, or verify the state of the\nPod network.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/pod_sendRawTransaction":{"post":{"tags":["Network & Consensus (pod_)"],"summary":"Send Raw Transaction (With Attestation Feedback)","operationId":"pod_sendRawTransaction","description":"Submits a signed EIP-1559 transaction and waits for validator attestations, returning\ntx_hash, success count, and any rejection errors from validators.\n\n**Parameters:**\n- `signed_tx` (string): Signed RLP-encoded transaction data\n- `timeout_secs` (integer, optional): Max seconds to wait for attestations. Default 10.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"pod_sendRawTransaction"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `signed_tx` (string): Signed RLP-encoded transaction data\n2. `timeout_secs` (integer, optional): Max seconds to wait for attestations\n"}}}}}},"responses":{"200":{"description":"Object with tx_hash, successes count, and errors array","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"type":"object","properties":{"tx_hash":{"$ref":"#/components/schemas/Bytes32"},"successes":{"type":"integer","description":"Number of successful attestations"},"errors":{"type":"array","items":{"type":"object"}}}},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."}}}}
```

## Get Validator Committee

> Returns information about the current validator committee.

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Network & Consensus (pod_)","description":"Network & Consensus (`pod_`) exposes Pod-specific endpoints that provide\nvisibility into the network’s validator set and consensus process. These\nAPIs surface data that is not available through standard Ethereum JSON-RPC\nmethods, such as validator committees and aggregated voting information.\n\nThis interface is intended for infrastructure providers, validators, and\nlight clients that need to inspect, monitor, or verify the state of the\nPod network.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/pod_getCommittee":{"post":{"tags":["Network & Consensus (pod_)"],"summary":"Get Validator Committee","operationId":"pod_getCommittee","description":"Returns information about the current validator committee.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"pod_getCommittee"},"id":{"type":"integer","default":1},"params":{"type":"array","default":[]}}}}}},"responses":{"200":{"description":"Committee information","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"type":"object"},"id":{"type":"integer"}}}}}}}}}}}
```

## Get Vote Batches

> Retrieves vote batches from validators within a specified range.

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Network & Consensus (pod_)","description":"Network & Consensus (`pod_`) exposes Pod-specific endpoints that provide\nvisibility into the network’s validator set and consensus process. These\nAPIs surface data that is not available through standard Ethereum JSON-RPC\nmethods, such as validator committees and aggregated voting information.\n\nThis interface is intended for infrastructure providers, validators, and\nlight clients that need to inspect, monitor, or verify the state of the\nPod network.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/pod_getVoteBatches":{"post":{"tags":["Network & Consensus (pod_)"],"summary":"Get Vote Batches","operationId":"pod_getVoteBatches","description":"Retrieves vote batches from validators within a specified range.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"pod_getVoteBatches"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `from_sequence` (integer, nullable): Starting sequence number. None = start from 0\n2. `to_sequence` (integer, nullable): Ending sequence number. None = up to latest\n","items":{"type":"integer","nullable":true}}}}}}},"responses":{"200":{"description":"Array of vote batch objects","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"type":"array","items":{"type":"object"}},"id":{"type":"integer"}}}}}}}}}}}
```

## Get Bridge Claim Proof

> Returns a proof for claiming bridged assets on an external chain. Use this after a\
> deposit transaction has been executed on Pod to obtain the committee attestations\
> and proof data needed to call \`claim\` on the external bridge contract.<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Network & Consensus (pod_)","description":"Network & Consensus (`pod_`) exposes Pod-specific endpoints that provide\nvisibility into the network’s validator set and consensus process. These\nAPIs surface data that is not available through standard Ethereum JSON-RPC\nmethods, such as validator committees and aggregated voting information.\n\nThis interface is intended for infrastructure providers, validators, and\nlight clients that need to inspect, monitor, or verify the state of the\nPod network.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/pod_getBridgeClaimProof":{"post":{"tags":["Network & Consensus (pod_)"],"summary":"Get Bridge Claim Proof","operationId":"pod_getBridgeClaimProof","description":"Returns a proof for claiming bridged assets on an external chain. Use this after a\ndeposit transaction has been executed on Pod to obtain the committee attestations\nand proof data needed to call `claim` on the external bridge contract.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"pod_getBridgeClaimProof"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `tx_hash` (bytes32): Transaction hash of the deposit transaction\n","items":{"$ref":"#/components/schemas/Bytes32"}}}}}}},"responses":{"200":{"description":"Bridge claim proof for the external chain `claim` call","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"$ref":"#/components/schemas/BridgeClaimProof"},"id":{"type":"integer"}}}}}},"400":{"description":"Receipt not found or insufficient attestations","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"error":{"type":"object","properties":{"code":{"type":"integer"},"message":{"type":"string"}}},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"BridgeClaimProof":{"type":"object","description":"Proof data for claiming bridged assets on an external chain via the bridge contract's `claim` function.","required":["signatures","committee_epoch","proof"],"properties":{"signatures":{"$ref":"#/components/schemas/HexBytes","description":"Aggregated 65-byte ECDSA signatures (r, s, v) from validators, concatenated"},"committee_epoch":{"type":"integer","format":"uint64","description":"Committee epoch for signature verification"},"proof":{"$ref":"#/components/schemas/Bytes32","description":"Transaction hash (proof data for the claim)"}}},"HexBytes":{"type":"string","pattern":"^0x[a-fA-F0-9]*$","description":"Variable-length bytes (hex-encoded with 0x prefix). Length must be even."}}}}
```

## Get Account Info

> Returns an account's finalized/expected nonces and last finalized transaction as this node\
> sees them. Public and unauthenticated diagnostic info. Returns null when the account has\
> never finalized a transaction.<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Network & Consensus (pod_)","description":"Network & Consensus (`pod_`) exposes Pod-specific endpoints that provide\nvisibility into the network’s validator set and consensus process. These\nAPIs surface data that is not available through standard Ethereum JSON-RPC\nmethods, such as validator committees and aggregated voting information.\n\nThis interface is intended for infrastructure providers, validators, and\nlight clients that need to inspect, monitor, or verify the state of the\nPod network.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/pod_getAccountInfo":{"post":{"tags":["Network & Consensus (pod_)"],"summary":"Get Account Info","operationId":"pod_getAccountInfo","description":"Returns an account's finalized/expected nonces and last finalized transaction as this node\nsees them. Public and unauthenticated diagnostic info. Returns null when the account has\nnever finalized a transaction.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"pod_getAccountInfo"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `account` (address): The account to look up.\n","items":{"$ref":"#/components/schemas/Address"}}}}}}},"responses":{"200":{"description":"Account nonce info, or null if the account has never finalized a tx","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"$ref":"#/components/schemas/AccountInfoResponse","nullable":true},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"AccountInfoResponse":{"type":"object","description":"An account's finalized/expected nonces and last finalized tx, as this node sees them.","required":["next_finalized_nonce","expected_nonce","last_finalized_tx"],"properties":{"next_finalized_nonce":{"type":"integer","format":"int64","description":"The next nonce to finalize; every lower nonce is already finalized."},"expected_nonce":{"type":"integer","format":"int64","description":"The next nonce the account is expected to submit."},"last_finalized_tx":{"$ref":"#/components/schemas/Bytes32"}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."}}}}
```

## Get Last Finalized Nonce

> Returns the account's last finalized nonce, or null when the account has never finalized a tx.

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Network & Consensus (pod_)","description":"Network & Consensus (`pod_`) exposes Pod-specific endpoints that provide\nvisibility into the network’s validator set and consensus process. These\nAPIs surface data that is not available through standard Ethereum JSON-RPC\nmethods, such as validator committees and aggregated voting information.\n\nThis interface is intended for infrastructure providers, validators, and\nlight clients that need to inspect, monitor, or verify the state of the\nPod network.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/pod_getLastFinalizedNonce":{"post":{"tags":["Network & Consensus (pod_)"],"summary":"Get Last Finalized Nonce","operationId":"pod_getLastFinalizedNonce","description":"Returns the account's last finalized nonce, or null when the account has never finalized a tx.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"pod_getLastFinalizedNonce"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `account` (address): The account to look up.\n","items":{"$ref":"#/components/schemas/Address"}}}}}}},"responses":{"200":{"description":"The account's last finalized nonce, or null","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"type":"integer","format":"int64","nullable":true},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"}}}}
```

## Get Transaction Status

> Returns the full pipeline status of a transaction: \`pending\` (with live vote counts),\
> \`finalized\` (with execution result), or \`not\_found\` for an unknown tx hash.<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Network & Consensus (pod_)","description":"Network & Consensus (`pod_`) exposes Pod-specific endpoints that provide\nvisibility into the network’s validator set and consensus process. These\nAPIs surface data that is not available through standard Ethereum JSON-RPC\nmethods, such as validator committees and aggregated voting information.\n\nThis interface is intended for infrastructure providers, validators, and\nlight clients that need to inspect, monitor, or verify the state of the\nPod network.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/pod_getTxStatus":{"post":{"tags":["Network & Consensus (pod_)"],"summary":"Get Transaction Status","operationId":"pod_getTxStatus","description":"Returns the full pipeline status of a transaction: `pending` (with live vote counts),\n`finalized` (with execution result), or `not_found` for an unknown tx hash.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"pod_getTxStatus"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `tx_hash` (bytes32): The transaction hash to look up.\n","items":{"$ref":"#/components/schemas/Bytes32"}}}}}}},"responses":{"200":{"description":"Transaction status","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"$ref":"#/components/schemas/TxStatusResponse"},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"TxStatusResponse":{"type":"object","description":"Full pipeline status of a transaction, returned by `pod_getTxStatus`. It is a `status`-tagged\nunion; the fields present depend on `status`:\n- `not_found`: unknown to this node (no cached tx and no receipt) — only `status` is present.\n- `pending`: in-flight — the `PendingTxStatus` fields are inlined alongside `status`.\n- `finalized`: executed — the `FinalizedTxStatus` fields are inlined alongside `status`.\n","required":["status"],"properties":{"status":{"type":"string","enum":["not_found","pending","finalized"],"description":"Discriminator selecting the variant."},"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"Present for `pending` and `finalized`."},"account":{"$ref":"#/components/schemas/Address","description":"Present for `pending` and `finalized`."},"nonce":{"type":"integer","format":"int64","description":"Present for `pending` and `finalized`."},"account_next_finalized_nonce":{"type":"integer","format":"int64","description":"`pending` only."},"account_expected_nonce":{"type":"integer","format":"int64","description":"`pending` only."},"quorum":{"type":"integer","description":"`pending` only: votes needed for a certificate (n − f)."},"votes":{"$ref":"#/components/schemas/AccountNonceVotesResponse","description":"`pending` only: the votes observed at this (account, nonce)."},"success":{"type":"boolean","description":"`finalized` only: whether execution succeeded."},"gas_used":{"type":"integer","format":"int64","description":"`finalized` only."}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"AccountNonceVotesResponse":{"type":"object","description":"Votes observed for a given (account, nonce), as tracked by this node's vote accounting. Returned by `pod_getVotes` and embedded in a pending `pod_getTxStatus`.","required":["account","nonce","txs","bot_voters","total_tx_votes","quorum"],"properties":{"account":{"$ref":"#/components/schemas/Address"},"nonce":{"type":"integer","format":"int64"},"txs":{"type":"array","items":{"$ref":"#/components/schemas/TxVotesResponse"},"description":"Voter sets per transaction hash seen at this (account, nonce)."},"bot_voters":{"type":"array","items":{"$ref":"#/components/schemas/VoterResponse"},"description":"Validators that voted BOT (bottom / no-op) at this (account, nonce)."},"total_tx_votes":{"type":"integer","description":"Distinct validators that voted for any tx (each counted once even when equivocating)."},"quorum":{"type":"integer","description":"Votes required for a certificate (n − f)."}}},"TxVotesResponse":{"type":"object","description":"The set of validators that voted for one specific transaction hash at a given (account, nonce).","required":["tx_hash","voters"],"properties":{"tx_hash":{"$ref":"#/components/schemas/Bytes32"},"voters":{"type":"array","items":{"$ref":"#/components/schemas/VoterResponse"}}}},"VoterResponse":{"type":"object","description":"A validator that cast a vote, resolved from the committee vote bitmap.","required":["validator_index","validator_address"],"properties":{"validator_index":{"type":"integer","description":"Index of the validator within the committee."},"validator_address":{"$ref":"#/components/schemas/Address"}}}}}}
```

## Get Votes at a Nonce

> Returns the votes observed for a given (account, nonce): the voter set per transaction hash\
> plus the BOT voters. Returns null when no votes are pending at that nonce (never seen, or\
> already finalized).<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Network & Consensus (pod_)","description":"Network & Consensus (`pod_`) exposes Pod-specific endpoints that provide\nvisibility into the network’s validator set and consensus process. These\nAPIs surface data that is not available through standard Ethereum JSON-RPC\nmethods, such as validator committees and aggregated voting information.\n\nThis interface is intended for infrastructure providers, validators, and\nlight clients that need to inspect, monitor, or verify the state of the\nPod network.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/pod_getVotes":{"post":{"tags":["Network & Consensus (pod_)"],"summary":"Get Votes at a Nonce","operationId":"pod_getVotes","description":"Returns the votes observed for a given (account, nonce): the voter set per transaction hash\nplus the BOT voters. Returns null when no votes are pending at that nonce (never seen, or\nalready finalized).\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"pod_getVotes"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `account` (address): The account whose votes to inspect.\n2. `nonce` (integer): The nonce to inspect.\n"}}}}}},"responses":{"200":{"description":"Votes at the (account, nonce), or null if none are pending","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"$ref":"#/components/schemas/AccountNonceVotesResponse","nullable":true},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"AccountNonceVotesResponse":{"type":"object","description":"Votes observed for a given (account, nonce), as tracked by this node's vote accounting. Returned by `pod_getVotes` and embedded in a pending `pod_getTxStatus`.","required":["account","nonce","txs","bot_voters","total_tx_votes","quorum"],"properties":{"account":{"$ref":"#/components/schemas/Address"},"nonce":{"type":"integer","format":"int64"},"txs":{"type":"array","items":{"$ref":"#/components/schemas/TxVotesResponse"},"description":"Voter sets per transaction hash seen at this (account, nonce)."},"bot_voters":{"type":"array","items":{"$ref":"#/components/schemas/VoterResponse"},"description":"Validators that voted BOT (bottom / no-op) at this (account, nonce)."},"total_tx_votes":{"type":"integer","description":"Distinct validators that voted for any tx (each counted once even when equivocating)."},"quorum":{"type":"integer","description":"Votes required for a certificate (n − f)."}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"TxVotesResponse":{"type":"object","description":"The set of validators that voted for one specific transaction hash at a given (account, nonce).","required":["tx_hash","voters"],"properties":{"tx_hash":{"$ref":"#/components/schemas/Bytes32"},"voters":{"type":"array","items":{"$ref":"#/components/schemas/VoterResponse"}}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"VoterResponse":{"type":"object","description":"A validator that cast a vote, resolved from the committee vote bitmap.","required":["validator_index","validator_address"],"properties":{"validator_index":{"type":"integer","description":"Index of the validator within the committee."},"validator_address":{"$ref":"#/components/schemas/Address"}}}}}}
```

## Get Transactions by Hash

> Fetches full signed transactions by hash. The request hash list is capped server-side, and\
> the response is additionally truncated to the node's max response body size — a transaction\
> that does not fit is omitted (re-request whatever is missing). Each returned item is a signed\
> Pod transaction (EIP-1559 envelope plus signature); decode with the Pod SDK.<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Network & Consensus (pod_)","description":"Network & Consensus (`pod_`) exposes Pod-specific endpoints that provide\nvisibility into the network’s validator set and consensus process. These\nAPIs surface data that is not available through standard Ethereum JSON-RPC\nmethods, such as validator committees and aggregated voting information.\n\nThis interface is intended for infrastructure providers, validators, and\nlight clients that need to inspect, monitor, or verify the state of the\nPod network.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/pod_getTransactions":{"post":{"tags":["Network & Consensus (pod_)"],"summary":"Get Transactions by Hash","operationId":"pod_getTransactions","description":"Fetches full signed transactions by hash. The request hash list is capped server-side, and\nthe response is additionally truncated to the node's max response body size — a transaction\nthat does not fit is omitted (re-request whatever is missing). Each returned item is a signed\nPod transaction (EIP-1559 envelope plus signature); decode with the Pod SDK.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"pod_getTransactions"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `tx_hashes` (array of bytes32): Transaction hashes to fetch.\n","items":{"type":"array","items":{"$ref":"#/components/schemas/Bytes32"}}}}}}}},"responses":{"200":{"description":"Array of signed transaction objects (possibly truncated to the body-size budget)","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"type":"array","items":{"type":"object","description":"A signed Pod transaction."}},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."}}}}
```

## List Transactions

> Lists signed transactions, optionally filtered by sender and/or recipient, up to an optional limit.

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Network & Consensus (pod_)","description":"Network & Consensus (`pod_`) exposes Pod-specific endpoints that provide\nvisibility into the network’s validator set and consensus process. These\nAPIs surface data that is not available through standard Ethereum JSON-RPC\nmethods, such as validator committees and aggregated voting information.\n\nThis interface is intended for infrastructure providers, validators, and\nlight clients that need to inspect, monitor, or verify the state of the\nPod network.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/pod_listTransactions":{"post":{"tags":["Network & Consensus (pod_)"],"summary":"List Transactions","operationId":"pod_listTransactions","description":"Lists signed transactions, optionally filtered by sender and/or recipient, up to an optional limit.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"pod_listTransactions"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters (all optional, positional):\n1. `from_account` (address, nullable): filter by sender.\n2. `to_account` (address, nullable): filter by recipient.\n3. `limit` (integer, nullable): maximum number of transactions to return.\n"}}}}}},"responses":{"200":{"description":"Array of signed transaction objects","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"type":"array","items":{"type":"object","description":"A signed Pod transaction."}},"id":{"type":"integer"}}}}}}}}}}}
```

## Get Recovery Target Transaction

> Returns the transaction an account must recover past to make progress, or null if the account does not need recovery.

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Network & Consensus (pod_)","description":"Network & Consensus (`pod_`) exposes Pod-specific endpoints that provide\nvisibility into the network’s validator set and consensus process. These\nAPIs surface data that is not available through standard Ethereum JSON-RPC\nmethods, such as validator committees and aggregated voting information.\n\nThis interface is intended for infrastructure providers, validators, and\nlight clients that need to inspect, monitor, or verify the state of the\nPod network.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/pod_getRecoveryTargetTx":{"post":{"tags":["Network & Consensus (pod_)"],"summary":"Get Recovery Target Transaction","operationId":"pod_getRecoveryTargetTx","description":"Returns the transaction an account must recover past to make progress, or null if the account does not need recovery.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"pod_getRecoveryTargetTx"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `account` (address): The account to inspect.\n","items":{"$ref":"#/components/schemas/Address"}}}}}}},"responses":{"200":{"description":"The recovery target, or null if none","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"$ref":"#/components/schemas/TargetTx","nullable":true},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"TargetTx":{"type":"object","description":"A transaction an account must recover past before it can make progress again.","required":["hash","nonce"],"properties":{"hash":{"$ref":"#/components/schemas/Bytes32"},"nonce":{"type":"integer","format":"int64"}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."}}}}
```

## Get Processed Deposits

> Returns the bridge deposit replay-protection set (a \`watermark\` plus the processed ids at or\
> above it). The relayer queries this to drop already-processed deposits from a batch.<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Network & Consensus (pod_)","description":"Network & Consensus (`pod_`) exposes Pod-specific endpoints that provide\nvisibility into the network’s validator set and consensus process. These\nAPIs surface data that is not available through standard Ethereum JSON-RPC\nmethods, such as validator committees and aggregated voting information.\n\nThis interface is intended for infrastructure providers, validators, and\nlight clients that need to inspect, monitor, or verify the state of the\nPod network.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/pod_getProcessedDeposits":{"post":{"tags":["Network & Consensus (pod_)"],"summary":"Get Processed Deposits","operationId":"pod_getProcessedDeposits","description":"Returns the bridge deposit replay-protection set (a `watermark` plus the processed ids at or\nabove it). The relayer queries this to drop already-processed deposits from a batch.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"pod_getProcessedDeposits"},"id":{"type":"integer","default":1},"params":{"type":"array","default":[]}}}}}},"responses":{"200":{"description":"The processed-deposit set","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"$ref":"#/components/schemas/ProcessedDepositsResponse"},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"ProcessedDepositsResponse":{"type":"object","description":"The bridge deposit replay-protection set. Every deposit id strictly below `watermark` has\nbeen processed; `above_watermark` lists the processed ids at or above it. The relayer uses\nthis to drop already-processed deposits from a batch before (re)submitting it.\n","required":["watermark","above_watermark"],"properties":{"watermark":{"$ref":"#/components/schemas/HexUint256"},"above_watermark":{"type":"array","items":{"$ref":"#/components/schemas/HexUint256"},"description":"Processed deposit ids `>= watermark`, sorted ascending."}}},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"}}}}
```

## Get Precompiles

> Returns the list of enshrined precompile contracts (bridge, CLOB, recovery, ...) with their addresses and names.

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Network & Consensus (pod_)","description":"Network & Consensus (`pod_`) exposes Pod-specific endpoints that provide\nvisibility into the network’s validator set and consensus process. These\nAPIs surface data that is not available through standard Ethereum JSON-RPC\nmethods, such as validator committees and aggregated voting information.\n\nThis interface is intended for infrastructure providers, validators, and\nlight clients that need to inspect, monitor, or verify the state of the\nPod network.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/pod_getPrecompiles":{"post":{"tags":["Network & Consensus (pod_)"],"summary":"Get Precompiles","operationId":"pod_getPrecompiles","description":"Returns the list of enshrined precompile contracts (bridge, CLOB, recovery, ...) with their addresses and names.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"pod_getPrecompiles"},"id":{"type":"integer","default":1},"params":{"type":"array","default":[]}}}}}},"responses":{"200":{"description":"Array of precompiles","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"type":"array","items":{"$ref":"#/components/schemas/Precompile"}},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Precompile":{"type":"object","description":"An enshrined precompile contract (bridge, CLOB, recovery, ...).","required":["address","name"],"properties":{"address":{"$ref":"#/components/schemas/Address"},"name":{"type":"string"}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"}}}}
```

## Get Precompile Info

> Returns a single precompile's address, name, and callable interface.

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Network & Consensus (pod_)","description":"Network & Consensus (`pod_`) exposes Pod-specific endpoints that provide\nvisibility into the network’s validator set and consensus process. These\nAPIs surface data that is not available through standard Ethereum JSON-RPC\nmethods, such as validator committees and aggregated voting information.\n\nThis interface is intended for infrastructure providers, validators, and\nlight clients that need to inspect, monitor, or verify the state of the\nPod network.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/pod_getPrecompileInfo":{"post":{"tags":["Network & Consensus (pod_)"],"summary":"Get Precompile Info","operationId":"pod_getPrecompileInfo","description":"Returns a single precompile's address, name, and callable interface.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"pod_getPrecompileInfo"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `address` (address): The precompile address.\n","items":{"$ref":"#/components/schemas/Address"}}}}}}},"responses":{"200":{"description":"Precompile info","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"$ref":"#/components/schemas/PrecompileInfo"},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"PrecompileInfo":{"type":"object","description":"A precompile plus its callable interface. The `Precompile` fields (`address`, `name`) are flattened to the top level alongside `interface`.","required":["address","name","interface"],"properties":{"address":{"$ref":"#/components/schemas/Address"},"name":{"type":"string"},"interface":{"type":"string","description":"The precompile's callable interface (human-readable descriptor)."}}}}}}
```

## Get Solver State

> Returns the solver node's current state: its address and public key, next finalized nonce,\
> last executed and last generated solution batches, and the votes seen for the next solution.\
> Only meaningful when queried against the solver node.<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Network & Consensus (pod_)","description":"Network & Consensus (`pod_`) exposes Pod-specific endpoints that provide\nvisibility into the network’s validator set and consensus process. These\nAPIs surface data that is not available through standard Ethereum JSON-RPC\nmethods, such as validator committees and aggregated voting information.\n\nThis interface is intended for infrastructure providers, validators, and\nlight clients that need to inspect, monitor, or verify the state of the\nPod network.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/pod_getSolverState":{"post":{"tags":["Network & Consensus (pod_)"],"summary":"Get Solver State","operationId":"pod_getSolverState","description":"Returns the solver node's current state: its address and public key, next finalized nonce,\nlast executed and last generated solution batches, and the votes seen for the next solution.\nOnly meaningful when queried against the solver node.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"pod_getSolverState"},"id":{"type":"integer","default":1},"params":{"type":"array","default":[]}}}}}},"responses":{"200":{"description":"Solver state","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"$ref":"#/components/schemas/SolverStateResponse"},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"SolverStateResponse":{"type":"object","description":"The solver node's current state. Only meaningful when queried against the solver node.","required":["solver_address","solver_pub_key","next_finalized_nonce","next_solution_votes"],"properties":{"solver_address":{"$ref":"#/components/schemas/Address"},"solver_pub_key":{"$ref":"#/components/schemas/Secp256k1PublicKey"},"next_finalized_nonce":{"type":"integer","format":"int64"},"last_executed_batch":{"$ref":"#/components/schemas/SolverBatchInfo","nullable":true,"description":"The most recently executed solution batch, or null if none."},"last_generated_batch":{"$ref":"#/components/schemas/SolverBatchInfo","nullable":true,"description":"The most recently generated (proposed) solution batch, or null if none."},"next_solution_votes":{"type":"object","additionalProperties":{"type":"array","items":{"type":"integer"}},"description":"Votes for the next solution: an object mapping each candidate solution tx hash (bytes32, hex string key) to the list of validator indices that voted for it."}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"Secp256k1PublicKey":{"type":"string","pattern":"^[0-9a-fA-F]{66}$","description":"A 33-byte compressed secp256k1 public key, lowercase hex, with **no** `0x` prefix (66 hex characters)."},"SolverBatchInfo":{"type":"object","description":"Identifies a solver solution batch by its auction deadline and transaction hash.","required":["deadline","tx_hash"],"properties":{"deadline":{"$ref":"#/components/schemas/Timestamp"},"tx_hash":{"$ref":"#/components/schemas/Bytes32"}}},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."}}}}
```

## Get Validator Status

> Returns this node's own validator state: append-log sequence number, local past-perfect\
> time, last executed batch deadline, and derived next-solution deadline. Values reflect the\
> queried node's in-memory state, not a consensus view.<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Network & Consensus (pod_)","description":"Network & Consensus (`pod_`) exposes Pod-specific endpoints that provide\nvisibility into the network’s validator set and consensus process. These\nAPIs surface data that is not available through standard Ethereum JSON-RPC\nmethods, such as validator committees and aggregated voting information.\n\nThis interface is intended for infrastructure providers, validators, and\nlight clients that need to inspect, monitor, or verify the state of the\nPod network.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/pod_getValidatorStatus":{"post":{"tags":["Network & Consensus (pod_)"],"summary":"Get Validator Status","operationId":"pod_getValidatorStatus","description":"Returns this node's own validator state: append-log sequence number, local past-perfect\ntime, last executed batch deadline, and derived next-solution deadline. Values reflect the\nqueried node's in-memory state, not a consensus view.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"pod_getValidatorStatus"},"id":{"type":"integer","default":1},"params":{"type":"array","default":[]}}}}}},"responses":{"200":{"description":"Validator status","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"$ref":"#/components/schemas/ValidatorStatusResponse"},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"ValidatorStatusResponse":{"type":"object","description":"This node's own in-memory validator state. `validator_index` / `validator_address` are\npresent on a validator node and null on a full node. Values reflect the queried node's local\nstate, not a consensus view.\n","required":["append_log_sequence","current_ppt","quorum","committee_size"],"properties":{"validator_index":{"type":"integer","nullable":true},"validator_address":{"$ref":"#/components/schemas/Address","nullable":true},"append_log_sequence":{"type":"integer","format":"int64","description":"The node's current append-log sequence number."},"current_ppt":{"$ref":"#/components/schemas/Timestamp","description":"This node's local past-perfect time (microseconds)."},"last_executed_batch":{"$ref":"#/components/schemas/Timestamp","nullable":true,"description":"Deadline of the last executed solution batch (microseconds), or null if none."},"next_solution_deadline":{"$ref":"#/components/schemas/Timestamp","nullable":true,"description":"`last_executed_batch + auction_interval`, or null if no batch has executed yet."},"quorum":{"type":"integer","description":"Votes required for a certificate (n − f)."},"committee_size":{"type":"integer"}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```

## Get Validator Account Status

> Returns how a specific validator has voted with respect to a specific account: what it has\
> (or hasn't) voted at each pending nonce, as seen by this node. Returns null when the\
> validator address is not in the current committee.<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Network & Consensus (pod_)","description":"Network & Consensus (`pod_`) exposes Pod-specific endpoints that provide\nvisibility into the network’s validator set and consensus process. These\nAPIs surface data that is not available through standard Ethereum JSON-RPC\nmethods, such as validator committees and aggregated voting information.\n\nThis interface is intended for infrastructure providers, validators, and\nlight clients that need to inspect, monitor, or verify the state of the\nPod network.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/pod_getValidatorAccountStatus":{"post":{"tags":["Network & Consensus (pod_)"],"summary":"Get Validator Account Status","operationId":"pod_getValidatorAccountStatus","description":"Returns how a specific validator has voted with respect to a specific account: what it has\n(or hasn't) voted at each pending nonce, as seen by this node. Returns null when the\nvalidator address is not in the current committee.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"pod_getValidatorAccountStatus"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `validator` (address): The validator to inspect.\n2. `account` (address): The account to inspect.\n","items":{"$ref":"#/components/schemas/Address"}}}}}}},"responses":{"200":{"description":"Validator's per-nonce vote state for the account, or null if the validator is not in the committee","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"$ref":"#/components/schemas/ValidatorAccountStatusResponse","nullable":true},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"ValidatorAccountStatusResponse":{"type":"object","description":"How one validator has voted for one account across its pending nonces, as seen by this node.","required":["validator_index","validator_address","account","account_next_finalized_nonce","account_expected_nonce","quorum","pending_nonces"],"properties":{"validator_index":{"type":"integer"},"validator_address":{"$ref":"#/components/schemas/Address"},"account":{"$ref":"#/components/schemas/Address"},"account_next_finalized_nonce":{"type":"integer","format":"int64","description":"This node's `next_finalized_nonce` for the account (votes at lower nonces are already gone)."},"account_expected_nonce":{"type":"integer","format":"int64","description":"This node's `expected_nonce` for the account."},"quorum":{"type":"integer","description":"Votes required for a certificate (n − f)."},"pending_nonces":{"type":"array","items":{"$ref":"#/components/schemas/ValidatorNonceVote"},"description":"One entry per pending nonce in `[next_finalized_nonce, expected_nonce)`. Capped at 256 entries; if the gap is larger the oldest nonces are omitted."}}},"ValidatorNonceVote":{"type":"object","description":"A single validator's vote at one pending nonce.","required":["nonce","vote"],"properties":{"nonce":{"type":"integer","format":"int64"},"vote":{"$ref":"#/components/schemas/ValidatorVoteKind"}}},"ValidatorVoteKind":{"type":"object","description":"A validator's vote at a single nonce. Tagged union on `kind`:\n- `tx`: voted for a specific transaction hash — `tx_hash` is present.\n- `bot`: cast a BOT (bottom / no-op) vote — only `kind` is present.\n- `not_seen`: no vote observed from this validator at this nonce — only `kind` is present.\n","required":["kind"],"properties":{"kind":{"type":"string","enum":["tx","bot","not_seen"]},"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"Present only when `kind` is `tx`."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."}}}}
```

## Get Account Diagnostics

> Returns a full diagnostic snapshot of a single account across all committee validators:\
> per-validator vote state, recovery status, CLOB pending-solution presence, and equivocation\
> detection — all in one call.<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Network & Consensus (pod_)","description":"Network & Consensus (`pod_`) exposes Pod-specific endpoints that provide\nvisibility into the network’s validator set and consensus process. These\nAPIs surface data that is not available through standard Ethereum JSON-RPC\nmethods, such as validator committees and aggregated voting information.\n\nThis interface is intended for infrastructure providers, validators, and\nlight clients that need to inspect, monitor, or verify the state of the\nPod network.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/pod_getAccountDiagnostics":{"post":{"tags":["Network & Consensus (pod_)"],"summary":"Get Account Diagnostics","operationId":"pod_getAccountDiagnostics","description":"Returns a full diagnostic snapshot of a single account across all committee validators:\nper-validator vote state, recovery status, CLOB pending-solution presence, and equivocation\ndetection — all in one call.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"pod_getAccountDiagnostics"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `account` (address): The account to diagnose.\n","items":{"$ref":"#/components/schemas/Address"}}}}}}},"responses":{"200":{"description":"Account diagnostics","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"$ref":"#/components/schemas/AccountDiagnosticsResponse"},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"AccountDiagnosticsResponse":{"type":"object","description":"Full diagnostic snapshot of a single account across all committee validators, returned by `pod_getAccountDiagnostics`.","required":["account","next_finalized_nonce","expected_nonce","last_finalized_tx","is_locked","quorum","validators","needs_recovery","has_clob_order_pending_solution","equivocating"],"properties":{"account":{"$ref":"#/components/schemas/Address"},"next_finalized_nonce":{"type":"integer","format":"int64"},"expected_nonce":{"type":"integer","format":"int64"},"last_finalized_tx":{"$ref":"#/components/schemas/Bytes32"},"is_locked":{"type":"boolean","description":"True when the account is locked (a tx is pending decision)."},"quorum":{"type":"integer","description":"Votes required for a certificate (n − f)."},"validators":{"type":"array","items":{"$ref":"#/components/schemas/ValidatorDiagnostics"},"description":"Per-validator vote state."},"needs_recovery":{"type":"boolean"},"recovery_target":{"$ref":"#/components/schemas/TargetTx","nullable":true,"description":"The tx the account needs to recover past, if any."},"has_clob_order_pending_solution":{"type":"boolean","description":"True if this account has at least one order in the CLOB's pending-solution window."},"equivocating":{"type":"boolean","description":"True if two competing tx hashes at the same nonce both reached the certificate threshold (n − 3f)."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"ValidatorDiagnostics":{"type":"object","description":"Per-validator vote state for a single account, as seen by the queried node. Part of `AccountDiagnosticsResponse`.","required":["validator_index","validator_address","current_vote","equivocating"],"properties":{"validator_index":{"type":"integer"},"validator_address":{"$ref":"#/components/schemas/Address"},"highest_attested_nonce":{"type":"integer","format":"int64","nullable":true,"description":"Highest nonce in the current pending window where this validator has voted. Null when there are no pending nonces or the validator has not voted."},"current_vote":{"$ref":"#/components/schemas/ValidatorVoteKind","description":"Vote cast at the latest pending nonce (`expected_nonce − 1`); `not_seen` if none."},"equivocating":{"type":"boolean","description":"True if this validator voted for two different tx hashes at the same nonce."}}},"ValidatorVoteKind":{"type":"object","description":"A validator's vote at a single nonce. Tagged union on `kind`:\n- `tx`: voted for a specific transaction hash — `tx_hash` is present.\n- `bot`: cast a BOT (bottom / no-op) vote — only `kind` is present.\n- `not_seen`: no vote observed from this validator at this nonce — only `kind` is present.\n","required":["kind"],"properties":{"kind":{"type":"string","enum":["tx","bot","not_seen"]},"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"Present only when `kind` is `tx`."}}},"TargetTx":{"type":"object","description":"A transaction an account must recover past before it can make progress again.","required":["hash","nonce"],"properties":{"hash":{"$ref":"#/components/schemas/Bytes32"},"nonce":{"type":"integer","format":"int64"}}}}}}
```

## Get Node Status

> Returns the operational status of the node. Currently exposes \`read\_only\` — when true, the\
> node rejects \`sendRawTransaction\` submissions. Public and unauthenticated.<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Network & Consensus (pod_)","description":"Network & Consensus (`pod_`) exposes Pod-specific endpoints that provide\nvisibility into the network’s validator set and consensus process. These\nAPIs surface data that is not available through standard Ethereum JSON-RPC\nmethods, such as validator committees and aggregated voting information.\n\nThis interface is intended for infrastructure providers, validators, and\nlight clients that need to inspect, monitor, or verify the state of the\nPod network.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/pod_status":{"post":{"tags":["Network & Consensus (pod_)"],"summary":"Get Node Status","operationId":"pod_status","description":"Returns the operational status of the node. Currently exposes `read_only` — when true, the\nnode rejects `sendRawTransaction` submissions. Public and unauthenticated.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"pod_status"},"id":{"type":"integer","default":1},"params":{"type":"array","default":[]}}}}}},"responses":{"200":{"description":"Node status","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"$ref":"#/components/schemas/PodStatus"},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"PodStatus":{"type":"object","description":"Operational status of the node.","required":["read_only"],"properties":{"read_only":{"type":"boolean","description":"When true, the node rejects `sendRawTransaction` submissions (both `eth_` and `pod_`)."}}}}}}
```

## Wait Past Perfect Time

> Long-poll that resolves once this node's past-perfect time (PPT) reaches the given\
> timestamp, then returns a null result. The target must be within \~500 ms of now; a target\
> too far in the future is rejected with an invalid-params error.<br>

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"tags":[{"name":"Network & Consensus (pod_)","description":"Network & Consensus (`pod_`) exposes Pod-specific endpoints that provide\nvisibility into the network’s validator set and consensus process. These\nAPIs surface data that is not available through standard Ethereum JSON-RPC\nmethods, such as validator committees and aggregated voting information.\n\nThis interface is intended for infrastructure providers, validators, and\nlight clients that need to inspect, monitor, or verify the state of the\nPod network.\n\n📝 This is a JSON-RPC 2.0 API. The request path is not important; the\nmethod to execute is defined by the method field in the request body. You\ncan send all requests to /, and any path after / is optional and used only\nfor documentation clarity.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/","description":"Pod testnet"}],"paths":{"/pod_waitPastPerfectTime":{"post":{"tags":["Network & Consensus (pod_)"],"summary":"Wait Past Perfect Time","operationId":"pod_waitPastPerfectTime","description":"Long-poll that resolves once this node's past-perfect time (PPT) reaches the given\ntimestamp, then returns a null result. The target must be within ~500 ms of now; a target\ntoo far in the future is rejected with an invalid-params error.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["jsonrpc","method","params","id"],"properties":{"jsonrpc":{"type":"string","default":"2.0"},"method":{"type":"string","default":"pod_waitPastPerfectTime"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `timestamp` (integer): Target past-perfect time, in microseconds since the Unix epoch.\n","items":{"$ref":"#/components/schemas/Timestamp"}}}}}}},"responses":{"200":{"description":"Resolves once PPT reaches the target; result is always null","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"nullable":true,"description":"Always null on success."},"id":{"type":"integer"}}}}}},"400":{"description":"Requested PPT is too far in the future, or the timestamp does not fit in a u64","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"error":{"type":"object","properties":{"code":{"type":"integer"},"message":{"type":"string"}}},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```


# Models

## The JsonRpcRequest object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"JsonRpcRequest":{"type":"object","description":"Standard JSON-RPC 2.0 request object","required":["jsonrpc","method","id"],"properties":{"jsonrpc":{"type":"string","enum":["2.0"],"description":"JSON-RPC protocol version (always \"2.0\")"},"method":{"type":"string","description":"Name of the RPC method to invoke"},"params":{"type":"array","items":{},"description":"Method parameters as an array"},"id":{"oneOf":[{"type":"integer"},{"type":"string"}],"description":"Request identifier for correlating responses"}}}}}}
```

## The JsonRpcResponse object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"JsonRpcResponse":{"type":"object","description":"Standard JSON-RPC 2.0 response object","required":["jsonrpc","id"],"properties":{"jsonrpc":{"type":"string","enum":["2.0"]},"result":{"description":"Result of the method call (mutually exclusive with error)"},"error":{"$ref":"#/components/schemas/JsonRpcError","description":"Error object if the call failed"},"id":{"oneOf":[{"type":"integer"},{"type":"string"}]}}},"JsonRpcError":{"type":"object","description":"JSON-RPC error object","required":["code","message"],"properties":{"code":{"type":"integer","description":"Numeric error code"},"message":{"type":"string","description":"Human-readable error message"},"data":{"description":"Additional error information"}}}}}}
```

## The JsonRpcError object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"JsonRpcError":{"type":"object","description":"JSON-RPC error object","required":["code","message"],"properties":{"code":{"type":"integer","description":"Numeric error code"},"message":{"type":"string","description":"Human-readable error message"},"data":{"description":"Additional error information"}}}}}}
```

## The Address object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"}}}}
```

## The Bytes32 object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."}}}}
```

## The HexBytes object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"HexBytes":{"type":"string","pattern":"^0x[a-fA-F0-9]*$","description":"Variable-length bytes (hex-encoded with 0x prefix). Length must be even."}}}}
```

## The BridgeClaimProof object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"BridgeClaimProof":{"type":"object","description":"Proof data for claiming bridged assets on an external chain via the bridge contract's `claim` function.","required":["signatures","committee_epoch","proof"],"properties":{"signatures":{"$ref":"#/components/schemas/HexBytes","description":"Aggregated 65-byte ECDSA signatures (r, s, v) from validators, concatenated"},"committee_epoch":{"type":"integer","format":"uint64","description":"Committee epoch for signature verification"},"proof":{"$ref":"#/components/schemas/Bytes32","description":"Transaction hash (proof data for the claim)"}}},"HexBytes":{"type":"string","pattern":"^0x[a-fA-F0-9]*$","description":"Variable-length bytes (hex-encoded with 0x prefix). Length must be even."},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."}}}}
```

## The HexUint256 object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"}}}}
```

## The DecimalUint256 object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"DecimalUint256":{"type":"string","pattern":"^[0-9]+$","description":"Unsigned 256-bit integer (decimal string representation)"}}}}
```

## The Timestamp object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```

## The TimestampString object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"TimestampString":{"type":"string","pattern":"^[0-9]+$","description":"Unix timestamp in microseconds as a string"}}}}
```

## The Side object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"Side":{"type":"string","enum":["buy","sell"],"description":"Order side — `buy` (bid) or `sell` (ask). For perps, prefer `direction` (see `OrderDirection`) for the position-effect label."}}}}
```

## The OrderStatus object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"OrderStatus":{"type":"string","enum":["pending","active","filled","expired","canceled"],"description":"Current status of an order:\n- `pending`: Order submitted but not yet included in orderbook\n- `active`: Order is live in the orderbook\n- `filled`: Order completely filled\n- `expired`: Order expired (TTL exceeded)\n- `canceled`: Order was canceled by user\n"}}}}
```

## The MarketType object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"MarketType":{"type":"string","enum":["spot","perpetual"],"description":"Type of market - spot trading or perpetual futures"}}}}
```

## The CandleResolution object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"CandleResolution":{"type":"string","enum":["1m","5m","15m","1h","4h","1d"],"description":"Time interval for OHLCV candles"}}}}
```

## The TriggerType object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"TriggerType":{"type":"string","enum":["take_profit","stop_loss"],"description":"Type of a TP/SL trigger order on a perp market:\n- `take_profit`: fires when the mark price moves favorably across `trigger_price`\n- `stop_loss`: fires when the mark price moves adversely across `trigger_price`\n\nAlso set on a synthetic order (`kind = triggered`) that a fired trigger produced.\n"}}}}
```

## The TriggerGrouping object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"TriggerGrouping":{"type":"string","enum":["none","asset","position"],"description":"Whether a trigger (and any synthetic order it produces) is bound to the bidder's exposure on the pair:\n- `none`: standalone — the trigger is removed only by a user cancel, TTL expiry, or its own fire; any synthetic order it produced survives independently\n- `asset`: exposure-bound — on perp markets the venue removes the armed trigger *and* any resting synthetic order it produced once the bidder's position on the pair reaches size 0; on spot markets, once the bidder's base-asset holdings reach 0\n\n`asset` was formerly named `position` (same semantics, same ABI value); nodes running older builds still emit `position` and clients should treat the two as equivalent.\n\nOmitted from an `Order` response when it is the default `none`.\n"}}}}
```

## The OrderKind object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"OrderKind":{"type":"string","enum":["user_signed","liquidation","triggered"],"description":"Origin of the order:\n- `user_signed`: a normal user-submitted order (every order placed via the `submitOrder` contract call)\n- `liquidation`: synthesized by the engine, per (user, pair), when an account falls below maintenance margin\n- `triggered`: the synthetic order emitted deterministically by validators when an armed TP/SL trigger crosses its threshold against the pair's mark price. Carries `trigger_type` and `grouping` inherited from the parent trigger.\n"}}}}
```

## The OrderDirection object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"OrderDirection":{"type":"string","enum":["buy","sell","open_long","add_long","reduce_long","close_long","open_short","add_short","reduce_short","close_short","long_to_short","short_to_long","liquidation"],"description":"Composite per-order direction for history and open-orders UIs.\nSpot orders use `buy`/`sell`. Perp orders use the position-effect labels (`open_long`, `reduce_long`, `close_long`, `long_to_short`, etc.) computed from the position before/after the fill. `liquidation` is set when `kind = liquidation`.\n"}}}}
```

## The PartialFill object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"PartialFill":{"type":"object","description":"A single fill round against this order.","properties":{"base_amount":{"$ref":"#/components/schemas/HexUint256","description":"Base token amount filled in this round (1e18)"},"quote_amount":{"$ref":"#/components/schemas/HexUint256","description":"Quote token amount filled in this round (1e18)"},"timestamp":{"$ref":"#/components/schemas/Timestamp","description":"Batch settlement timestamp (microseconds)"},"price":{"$ref":"#/components/schemas/HexUint256","description":"Clearing price of the batch (1e18)"}}},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```

## The Order object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"Order":{"type":"object","description":"An order returned by `ob_getOrders`. Carries spot and perp shapes — perp-only fields (`reduce_only`, `ioc`, `direction`) are present only when `market_type = perpetual`. The `initial_size` is signed: positive for Buy/Long, negative for Sell/Short.\n","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32","description":"The orderbook this order belongs to"},"market_type":{"$ref":"#/components/schemas/MarketType"},"kind":{"$ref":"#/components/schemas/OrderKind"},"order_id":{"$ref":"#/components/schemas/Bytes32","description":"Computed order identifier `keccak256(abi.encode(signer, nonce, sequence))` — the id orders, cancels, and updates are keyed by."},"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"Transaction hash that created this order. Zero for engine-generated orders (liquidations, fired-trigger synthetics)."},"bidder":{"$ref":"#/components/schemas/Address","description":"Address of the order creator"},"nonce":{"type":"integer","format":"int64","description":"Nonce of the transaction that created the order — the signing key's nonce, not a\nper-order counter, and the delegate's rather than the master's for a delegated order.\nOrders from one `submitBatch` share it.\n"},"order_type":{"type":"string","enum":["limit","market"],"description":"Limit or market"},"status":{"$ref":"#/components/schemas/OrderStatus"},"side":{"type":"string","enum":["buy","sell"],"description":"Bid (buy) or ask (sell). For perps, prefer `direction` for the position-effect label."},"price":{"$ref":"#/components/schemas/HexUint256","description":"Limit price in quote/base units with 1e18 scale"},"initial_size":{"type":"string","description":"Original signed order size (positive = Buy/Long, negative = Sell/Short)"},"filled_base_amount":{"$ref":"#/components/schemas/HexUint256","description":"Cumulative amount of base tokens filled"},"filled_quote_amount":{"$ref":"#/components/schemas/HexUint256","description":"Cumulative amount of quote tokens filled"},"fee":{"$ref":"#/components/schemas/HexUint256","description":"Accumulated trading fee. Currently always zero."},"deadline":{"$ref":"#/components/schemas/Timestamp","description":"Timestamp by which order must be included in the orderbook (microseconds)"},"end":{"$ref":"#/components/schemas/Timestamp","description":"Timestamp when order expires (microseconds)"},"effective_price":{"$ref":"#/components/schemas/HexUint256","description":"Effective price the order has been filled at so far (filled_quote / filled_base, 1e18)"},"fills":{"type":"array","items":{"$ref":"#/components/schemas/PartialFill"},"description":"Per-batch partial fills against this order"},"reduce_only":{"type":"boolean","description":"Perp only. If true, the order can only reduce existing exposure. Omitted for spot orders.","nullable":true},"ioc":{"type":"boolean","description":"Perp only. Immediate-or-cancel — any unfilled remainder is canceled at end of batch. Omitted for spot orders.","nullable":true},"direction":{"$ref":"#/components/schemas/OrderDirection","description":"Composite direction label (set for spot, and for perps once fills land or for liquidation orders).","nullable":true},"grouping":{"$ref":"#/components/schemas/TriggerGrouping","description":"Trigger-grouping mode inherited from the parent trigger. Omitted when it is the default `none`."},"trigger_type":{"$ref":"#/components/schemas/TriggerType","description":"Trigger type (`take_profit` / `stop_loss`) inherited from the parent `TriggerOrder` when this order is the synthetic produced by a fired trigger (`kind = triggered`). Omitted for every other order.","nullable":true}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"MarketType":{"type":"string","enum":["spot","perpetual"],"description":"Type of market - spot trading or perpetual futures"},"OrderKind":{"type":"string","enum":["user_signed","liquidation","triggered"],"description":"Origin of the order:\n- `user_signed`: a normal user-submitted order (every order placed via the `submitOrder` contract call)\n- `liquidation`: synthesized by the engine, per (user, pair), when an account falls below maintenance margin\n- `triggered`: the synthetic order emitted deterministically by validators when an armed TP/SL trigger crosses its threshold against the pair's mark price. Carries `trigger_type` and `grouping` inherited from the parent trigger.\n"},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"OrderStatus":{"type":"string","enum":["pending","active","filled","expired","canceled"],"description":"Current status of an order:\n- `pending`: Order submitted but not yet included in orderbook\n- `active`: Order is live in the orderbook\n- `filled`: Order completely filled\n- `expired`: Order expired (TTL exceeded)\n- `canceled`: Order was canceled by user\n"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"},"PartialFill":{"type":"object","description":"A single fill round against this order.","properties":{"base_amount":{"$ref":"#/components/schemas/HexUint256","description":"Base token amount filled in this round (1e18)"},"quote_amount":{"$ref":"#/components/schemas/HexUint256","description":"Quote token amount filled in this round (1e18)"},"timestamp":{"$ref":"#/components/schemas/Timestamp","description":"Batch settlement timestamp (microseconds)"},"price":{"$ref":"#/components/schemas/HexUint256","description":"Clearing price of the batch (1e18)"}}},"OrderDirection":{"type":"string","enum":["buy","sell","open_long","add_long","reduce_long","close_long","open_short","add_short","reduce_short","close_short","long_to_short","short_to_long","liquidation"],"description":"Composite per-order direction for history and open-orders UIs.\nSpot orders use `buy`/`sell`. Perp orders use the position-effect labels (`open_long`, `reduce_long`, `close_long`, `long_to_short`, etc.) computed from the position before/after the fill. `liquidation` is set when `kind = liquidation`.\n"},"TriggerGrouping":{"type":"string","enum":["none","asset","position"],"description":"Whether a trigger (and any synthetic order it produces) is bound to the bidder's exposure on the pair:\n- `none`: standalone — the trigger is removed only by a user cancel, TTL expiry, or its own fire; any synthetic order it produced survives independently\n- `asset`: exposure-bound — on perp markets the venue removes the armed trigger *and* any resting synthetic order it produced once the bidder's position on the pair reaches size 0; on spot markets, once the bidder's base-asset holdings reach 0\n\n`asset` was formerly named `position` (same semantics, same ABI value); nodes running older builds still emit `position` and clients should treat the two as equivalent.\n\nOmitted from an `Order` response when it is the default `none`.\n"},"TriggerType":{"type":"string","enum":["take_profit","stop_loss"],"description":"Type of a TP/SL trigger order on a perp market:\n- `take_profit`: fires when the mark price moves favorably across `trigger_price`\n- `stop_loss`: fires when the mark price moves adversely across `trigger_price`\n\nAlso set on a synthetic order (`kind = triggered`) that a fired trigger produced.\n"}}}}
```

## The Candle object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"Candle":{"type":"object","description":"OHLCV candle representing price/volume data for a time period","properties":{"timestamp":{"$ref":"#/components/schemas/Timestamp","description":"Candle timestamp in microseconds"},"open":{"$ref":"#/components/schemas/HexUint256","description":"Opening price (quote/base with 1e18 scale)"},"close":{"$ref":"#/components/schemas/HexUint256","description":"Closing price (quote/base with 1e18 scale)"},"high":{"$ref":"#/components/schemas/HexUint256","description":"Highest price (quote/base with 1e18 scale)"},"low":{"$ref":"#/components/schemas/HexUint256","description":"Lowest price (quote/base with 1e18 scale)"},"volume":{"$ref":"#/components/schemas/HexUint256","description":"Total volume traded during this candle period"}}},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"}}}}
```

## The Market object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"Market":{"type":"object","description":"Market/orderbook metadata and 24-hour statistics","properties":{"id":{"$ref":"#/components/schemas/Bytes32","description":"Unique 32-byte orderbook identifier"},"name":{"type":"string","description":"Market name in format `{base_token}/{quote_token}` (e.g. \"NVDAx/USD\")"},"base_token_address":{"$ref":"#/components/schemas/Address","description":"Contract address of the base token"},"quote_token_address":{"$ref":"#/components/schemas/Address","description":"Contract address of the quote token"},"base_token_symbol":{"type":"string","description":"Symbol of the base token (e.g., \"NVDAx\")"},"quote_token_symbol":{"type":"string","description":"Symbol of the quote token (e.g., \"USD\")"},"base_token_name":{"type":"string","description":"Full name of the base token"},"quote_token_name":{"type":"string","description":"Full name of the quote token"},"market_type":{"$ref":"#/components/schemas/MarketType"},"last_clearing_price":{"$ref":"#/components/schemas/HexUint256","description":"Last auction clearing price (quote/base with 1e18 scale)"},"auction_interval":{"type":"integer","format":"int64","description":"Length of a matching round, in microseconds."},"volume_24h":{"$ref":"#/components/schemas/HexUint256","description":"24-hour trading volume"},"high_24h":{"$ref":"#/components/schemas/HexUint256","description":"24-hour highest price"},"low_24h":{"$ref":"#/components/schemas/HexUint256","description":"24-hour lowest price"},"price_change_24h":{"type":"integer","format":"int64","description":"24-hour price change (signed integer)"},"tick_precision":{"$ref":"#/components/schemas/HexUint256","description":"Minimum price tick size, hex-encoded with `1e18` scale (e.g. `0xde0b6b3a7640000` = `1e18` = one whole tick)."},"lot_size":{"$ref":"#/components/schemas/HexUint256","description":"Minimum order size increment, hex-encoded with `1e18` scale. Order sizes must be multiples of this value."},"maker_fee":{"$ref":"#/components/schemas/HexUint256","description":"Maker fee rate (1e18-scaled)"},"taker_fee":{"$ref":"#/components/schemas/HexUint256","description":"Taker fee rate (1e18-scaled)"},"max_leverage":{"type":"integer","description":"Maximum allowed leverage. Returned for both spot and perp markets, but only meaningful for perp."},"oracle_price":{"type":"string","nullable":true,"description":"Perp markets only. Latest Pyth oracle price as a hex-encoded\nunsigned 256-bit integer (1e18-scaled), used as the mark for funding\nand liquidation. `null` for spot markets.\n"},"mark_price":{"type":"string","nullable":true,"description":"Perp markets only. True mark price (oracle-anchored) as a hex-encoded\nunsigned 256-bit integer (1e18-scaled). `null` for spot markets.\n"},"funding_rate":{"type":"string","nullable":true,"description":"Perp markets only. Per-`funding_window` funding rate as a signed\ndecimal string (1e18-scaled, may be negative). `null` for spot markets.\n"},"funding_index":{"type":"string","nullable":true,"description":"Perp markets only. Cumulative per-unit-size funding accumulator as\na signed decimal string (1e18-scaled, may be negative). `null` for\nspot markets.\n"},"funding_last_updated":{"type":"integer","format":"int64","nullable":true,"description":"Perp markets only. Microsecond Unix timestamp of the batch that produced\nthe most recent funding update. `null` for spot markets.\n"},"open_interest":{"type":"string","nullable":true,"description":"Perp markets only. Open interest in 1e18-scaled USD notional as a\nhex-encoded unsigned 256-bit integer —\n`mark_price * Σ |position.size|` across every open cross-margin\nposition on this market. `null` for spot markets.\n"}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"MarketType":{"type":"string","enum":["spot","perpetual"],"description":"Type of market - spot trading or perpetual futures"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"}}}}
```

## The TickSnapshot object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"TickSnapshot":{"type":"object","description":"Aggregated order volume at a specific price level","properties":{"volume":{"$ref":"#/components/schemas/HexUint256","description":"Total volume available at this price level (1e18, hex-encoded)"}}},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"}}}}
```

## The OrderbookSnapshot object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"OrderbookSnapshot":{"type":"object","description":"Current state of an orderbook with aggregated buy/sell levels.\nThe response field is `orderbook_id`; `clob_id` is accepted as an input alias when deserializing.\n","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32","description":"Orderbook identifier. Also accepts `clob_id` as an alias on input."},"buys":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/TickSnapshot"},"description":"Buy orders keyed by price (decimal string), sorted by price descending"},"sells":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/TickSnapshot"},"description":"Sell orders keyed by price (decimal string), sorted by price ascending"},"clearing_price":{"$ref":"#/components/schemas/HexUint256","description":"Current/last clearing price"},"grouping_precision":{"$ref":"#/components/schemas/HexUint256","description":"Price grouping precision used for aggregation (1e18, hex-encoded)"},"timestamp":{"type":"integer","description":"Snapshot timestamp in microseconds"},"new_orders_count":{"type":"integer","description":"Number of new orders since the last snapshot"},"buys_count":{"type":"integer","description":"Total number of buy orders in the orderbook (regardless of depth parameter)"},"sells_count":{"type":"integer","description":"Total number of sell orders in the orderbook (regardless of depth parameter)"},"oracle_price":{"type":"string","nullable":true,"description":"Perp orderbooks only. Pyth oracle price from the most recent perp solution's `priceProof` (1e18, hex-encoded). `null` for spot orderbooks."},"funding_rate":{"type":"string","nullable":true,"description":"Perp orderbooks only. Funding rate computed for this batch (per-`funding_window`, signed 1e18 decimal string). `null` for spot orderbooks."},"funding_index":{"type":"string","nullable":true,"description":"Perp orderbooks only. Cumulative per-unit-size funding accumulator after this batch (signed 1e18 decimal string). `null` for spot orderbooks."},"funding_last_updated":{"type":"integer","format":"int64","nullable":true,"description":"Perp orderbooks only. Microsecond timestamp of the batch that produced the funding update. `null` for spot orderbooks."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"TickSnapshot":{"type":"object","description":"Aggregated order volume at a specific price level","properties":{"volume":{"$ref":"#/components/schemas/HexUint256","description":"Total volume available at this price level (1e18, hex-encoded)"}}},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"}}}}
```

## The PodAttestation object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"PodAttestation":{"type":"object","description":"Validator attestation for a transaction","properties":{"validator_address":{"$ref":"#/components/schemas/Address","description":"Address of the attesting validator"},"sequence_number":{"type":"integer","format":"int64","description":"Sequence number of the attestation"},"batch_index":{"type":"integer","description":"Index within the attestation batch"},"timestamp":{"$ref":"#/components/schemas/Timestamp","description":"Timestamp when the attestation was created (microseconds)"},"signature":{"type":"string","description":"Hex-encoded secp256k1 ECDSA signature"}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```

## The PodMetadata object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"PodMetadata":{"type":"object","description":"Pod-specific metadata containing validator attestations for finality verification","properties":{"attestations":{"type":"array","items":{"$ref":"#/components/schemas/PodAttestation"},"description":"List of validator attestations for the transaction"},"committee_epoch":{"type":"integer","format":"int64","description":"The committee epoch during which the transaction was attested"}}},"PodAttestation":{"type":"object","description":"Validator attestation for a transaction","properties":{"validator_address":{"$ref":"#/components/schemas/Address","description":"Address of the attesting validator"},"sequence_number":{"type":"integer","format":"int64","description":"Sequence number of the attestation"},"batch_index":{"type":"integer","description":"Index within the attestation batch"},"timestamp":{"$ref":"#/components/schemas/Timestamp","description":"Timestamp when the attestation was created (microseconds)"},"signature":{"type":"string","description":"Hex-encoded secp256k1 ECDSA signature"}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```

## The TransactionReceipt object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"TransactionReceipt":{"type":"object","description":"Transaction receipt with execution status, logs, and Pod-specific metadata","properties":{"type":{"type":"string","description":"Transaction type (EIP-2718)"},"status":{"type":"string","enum":["0x0","0x1"],"description":"Execution status - \"0x1\" for success, \"0x0\" for failure"},"cumulativeGasUsed":{"$ref":"#/components/schemas/HexUint256"},"logs":{"type":"array","items":{"$ref":"#/components/schemas/Log"}},"logsBloom":{"type":"string","description":"Bloom filter for logs (hex-encoded)"},"transactionHash":{"$ref":"#/components/schemas/Bytes32"},"transactionIndex":{"type":"string","description":"Transaction index in block (hex-encoded)"},"blockHash":{"$ref":"#/components/schemas/Bytes32"},"blockNumber":{"type":"string","description":"Block number (hex-encoded)"},"gasUsed":{"$ref":"#/components/schemas/HexUint256"},"effectiveGasPrice":{"$ref":"#/components/schemas/HexUint256"},"from":{"$ref":"#/components/schemas/Address"},"to":{"$ref":"#/components/schemas/Address"},"contractAddress":{"type":"string","nullable":true,"description":"Contract address if this was a contract creation (null otherwise)"},"pod_metadata":{"$ref":"#/components/schemas/PodMetadata","description":"Pod-specific attestation data for transaction finality verification"}}},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"Log":{"type":"object","description":"Event log emitted during transaction execution","properties":{"address":{"$ref":"#/components/schemas/Address","description":"Address of the contract that emitted the log"},"topics":{"type":"array","items":{"$ref":"#/components/schemas/Bytes32"},"description":"Indexed event parameters"},"data":{"type":"string","description":"Non-indexed event data (hex-encoded)"}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"PodMetadata":{"type":"object","description":"Pod-specific metadata containing validator attestations for finality verification","properties":{"attestations":{"type":"array","items":{"$ref":"#/components/schemas/PodAttestation"},"description":"List of validator attestations for the transaction"},"committee_epoch":{"type":"integer","format":"int64","description":"The committee epoch during which the transaction was attested"}}},"PodAttestation":{"type":"object","description":"Validator attestation for a transaction","properties":{"validator_address":{"$ref":"#/components/schemas/Address","description":"Address of the attesting validator"},"sequence_number":{"type":"integer","format":"int64","description":"Sequence number of the attestation"},"batch_index":{"type":"integer","description":"Index within the attestation batch"},"timestamp":{"$ref":"#/components/schemas/Timestamp","description":"Timestamp when the attestation was created (microseconds)"},"signature":{"type":"string","description":"Hex-encoded secp256k1 ECDSA signature"}}},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```

## The Transaction object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"Transaction":{"type":"object","description":"Transaction object returned by eth_getTransactionByHash","properties":{"hash":{"$ref":"#/components/schemas/Bytes32"},"nonce":{"type":"string"},"blockHash":{"$ref":"#/components/schemas/Bytes32","nullable":true},"blockNumber":{"type":"string","nullable":true},"transactionIndex":{"type":"string","nullable":true},"from":{"$ref":"#/components/schemas/Address"},"to":{"$ref":"#/components/schemas/Address","nullable":true},"value":{"$ref":"#/components/schemas/HexUint256"},"gas":{"type":"string"},"gasPrice":{"type":"string"},"input":{"type":"string"},"v":{"type":"string"},"r":{"type":"string"},"s":{"type":"string"}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"}}}}
```

## The Log object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"Log":{"type":"object","description":"Event log emitted during transaction execution","properties":{"address":{"$ref":"#/components/schemas/Address","description":"Address of the contract that emitted the log"},"topics":{"type":"array","items":{"$ref":"#/components/schemas/Bytes32"},"description":"Indexed event parameters"},"data":{"type":"string","description":"Non-indexed event data (hex-encoded)"}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."}}}}
```

## The CandlesQuery object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"CandlesQuery":{"type":"object","description":"Query parameters for fetching historical candles","required":["resolution","from_ts"],"properties":{"resolution":{"$ref":"#/components/schemas/CandleResolution","description":"Candle time interval"},"from_ts":{"$ref":"#/components/schemas/Timestamp","description":"Start timestamp (inclusive) in microseconds"},"to_ts":{"$ref":"#/components/schemas/Timestamp","description":"End timestamp (inclusive) in microseconds. Defaults to current time if omitted."},"limit":{"type":"integer","description":"Maximum number of candles to return. No limit if omitted."}}},"CandleResolution":{"type":"string","enum":["1m","5m","15m","1h","4h","1d"],"description":"Time interval for OHLCV candles"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```

## The OrdersQuery object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"OrdersQuery":{"type":"object","description":"Query parameters for ob_getOrders (address is passed as first param)","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32","description":"Optional filter by orderbook; omit for all orderbooks"},"limit":{"type":"integer","description":"Maximum number of orders to return"},"cursor":{"type":"string","description":"Pagination cursor from previous response"},"status":{"$ref":"#/components/schemas/OrderStatus","description":"Filter orders by status"},"with_fills":{"type":"boolean","description":"When true, include each order's per-batch partial `fills` array in the response. Defaults to false."},"with_total":{"type":"boolean","description":"When true, compute and return `total_count`. Defaults to false — the count walks every order the account ever placed (expensive for high-churn accounts), and cursor pagination does not need it. Nodes running builds predating this flag ignore it and always return `total_count`."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"OrderStatus":{"type":"string","enum":["pending","active","filled","expired","canceled"],"description":"Current status of an order:\n- `pending`: Order submitted but not yet included in orderbook\n- `active`: Order is live in the orderbook\n- `filled`: Order completely filled\n- `expired`: Order expired (TTL exceeded)\n- `canceled`: Order was canceled by user\n"}}}}
```

## The FillsQuery object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"FillsQuery":{"type":"object","description":"Query parameters for ob_getFills (address is passed as first param)","required":["from_ts"],"properties":{"from_ts":{"$ref":"#/components/schemas/Timestamp","description":"Start timestamp (inclusive) in microseconds"},"to_ts":{"$ref":"#/components/schemas/Timestamp","description":"End timestamp (exclusive) in microseconds. Defaults to current time if omitted."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32","description":"Optional filter by orderbook; omit for all orderbooks"},"limit":{"type":"integer","description":"Maximum number of fills to return (max 500). Defaults to 500."}}},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."}}}}
```

## The TriggersQuery object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"TriggersQuery":{"type":"object","description":"Query parameters for ob_getTriggers (address is passed as first param). All fields optional — an empty object returns every armed trigger owned by the address, capped at the server-side limit.","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32","description":"Optional filter by orderbook; omit for all orderbooks."},"limit":{"type":"integer","description":"Maximum number of triggers to return. Clamped to `[1, 200]`."},"cursor":{"type":"string","description":"Pagination cursor — pass `next_cursor` from the previous response. Wire format `\"{orderbook_id}:{order_id}\"`."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."}}}}
```

## The BackstopTransfersQuery object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"BackstopTransfersQuery":{"type":"object","description":"Query parameters for ob_getBackstopTransfers (address is passed as first param). All fields optional.","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32","description":"Optional filter by orderbook; omit for all orderbooks."},"limit":{"type":"integer","description":"Maximum number of transfers to return. Clamped to `[1, 200]`."},"cursor":{"type":"string","description":"Pagination cursor — pass `next_cursor` from the previous response. Wire format `\"{ts}:{id}\"`."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."}}}}
```

## The FillResponse object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"FillResponse":{"type":"object","description":"A single trade fill from a batch auction settlement","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32","description":"The orderbook this fill belongs to"},"base_token":{"$ref":"#/components/schemas/Address","description":"Base token contract address"},"quote_token":{"$ref":"#/components/schemas/Address","description":"Quote token contract address"},"order_id":{"$ref":"#/components/schemas/Bytes32","description":"Identifier of the order that was filled"},"order_type":{"type":"string","enum":["limit","market"],"description":"Type of the order"},"initial_size":{"type":"string","description":"Initial order size (1e18); decimal string (signed int256). Positive for buy, negative for sell."},"fee":{"$ref":"#/components/schemas/HexUint256","description":"Accumulated fee for this order (1e18); hex-encoded. Currently always zero."},"base_amount":{"$ref":"#/components/schemas/HexUint256","description":"Base token amount filled in this settlement round (1e18); hex-encoded"},"quote_amount":{"$ref":"#/components/schemas/HexUint256","description":"Quote token amount filled in this settlement round (1e18); hex-encoded"},"timestamp":{"$ref":"#/components/schemas/Timestamp","description":"Timestamp of the batch settlement, in microseconds."},"price":{"$ref":"#/components/schemas/HexUint256","description":"Clearing price of the batch (1e18); hex-encoded"}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```

## The GetFillsResponse object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"GetFillsResponse":{"type":"object","description":"Response containing a list of fills","properties":{"fills":{"type":"array","items":{"$ref":"#/components/schemas/FillResponse"},"description":"List of fills ordered by timestamp descending"}}},"FillResponse":{"type":"object","description":"A single trade fill from a batch auction settlement","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32","description":"The orderbook this fill belongs to"},"base_token":{"$ref":"#/components/schemas/Address","description":"Base token contract address"},"quote_token":{"$ref":"#/components/schemas/Address","description":"Quote token contract address"},"order_id":{"$ref":"#/components/schemas/Bytes32","description":"Identifier of the order that was filled"},"order_type":{"type":"string","enum":["limit","market"],"description":"Type of the order"},"initial_size":{"type":"string","description":"Initial order size (1e18); decimal string (signed int256). Positive for buy, negative for sell."},"fee":{"$ref":"#/components/schemas/HexUint256","description":"Accumulated fee for this order (1e18); hex-encoded. Currently always zero."},"base_amount":{"$ref":"#/components/schemas/HexUint256","description":"Base token amount filled in this settlement round (1e18); hex-encoded"},"quote_amount":{"$ref":"#/components/schemas/HexUint256","description":"Quote token amount filled in this settlement round (1e18); hex-encoded"},"timestamp":{"$ref":"#/components/schemas/Timestamp","description":"Timestamp of the batch settlement, in microseconds."},"price":{"$ref":"#/components/schemas/HexUint256","description":"Clearing price of the batch (1e18); hex-encoded"}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```

## The TriggerOrderResponse object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"TriggerOrderResponse":{"type":"object","description":"An armed TP/SL trigger order, as returned by `ob_getTriggers`.","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"order_id":{"$ref":"#/components/schemas/Bytes32","description":"Identifier of the trigger (and of the synthetic order it produces when it fires)."},"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"Hash of the `submitTrigger` transaction that armed this trigger."},"bidder":{"$ref":"#/components/schemas/Address"},"nonce":{"type":"integer","format":"int64"},"size":{"type":"string","description":"Signed size of the synthetic order produced when the trigger fires (decimal int256). Positive = buy/long, negative = sell/short."},"limit_price":{"$ref":"#/components/schemas/HexUint256","description":"Limit price of the synthetic order produced when the trigger fires (1e18)."},"trigger_price":{"$ref":"#/components/schemas/HexUint256","description":"Mark-price threshold that arms the trigger (1e18)."},"trigger_type":{"$ref":"#/components/schemas/TriggerType"},"grouping":{"$ref":"#/components/schemas/TriggerGrouping"},"reduce_only":{"type":"boolean"},"ioc":{"type":"boolean","description":"Immediate-or-cancel — any unfilled remainder of the fired order is canceled at end of batch."},"deadline":{"$ref":"#/components/schemas/Timestamp"},"end":{"$ref":"#/components/schemas/Timestamp","description":"TTL expiry — the trigger is swept once `end < batch_deadline` (microseconds)."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"TriggerType":{"type":"string","enum":["take_profit","stop_loss"],"description":"Type of a TP/SL trigger order on a perp market:\n- `take_profit`: fires when the mark price moves favorably across `trigger_price`\n- `stop_loss`: fires when the mark price moves adversely across `trigger_price`\n\nAlso set on a synthetic order (`kind = triggered`) that a fired trigger produced.\n"},"TriggerGrouping":{"type":"string","enum":["none","asset","position"],"description":"Whether a trigger (and any synthetic order it produces) is bound to the bidder's exposure on the pair:\n- `none`: standalone — the trigger is removed only by a user cancel, TTL expiry, or its own fire; any synthetic order it produced survives independently\n- `asset`: exposure-bound — on perp markets the venue removes the armed trigger *and* any resting synthetic order it produced once the bidder's position on the pair reaches size 0; on spot markets, once the bidder's base-asset holdings reach 0\n\n`asset` was formerly named `position` (same semantics, same ABI value); nodes running older builds still emit `position` and clients should treat the two as equivalent.\n\nOmitted from an `Order` response when it is the default `none`.\n"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```

## The GetTriggersResponse object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"GetTriggersResponse":{"type":"object","description":"Paginated result of `ob_getTriggers`.","properties":{"triggers":{"type":"array","items":{"$ref":"#/components/schemas/TriggerOrderResponse"}},"total_count":{"type":"integer","description":"Count of triggers matching `(address, orderbook_id)` *before* pagination."},"next_cursor":{"type":"string","nullable":true,"description":"Pass back as `query.cursor` to fetch the next page. Wire format `\"{orderbook_id}:{order_id}\"`. Null if no more results."}}},"TriggerOrderResponse":{"type":"object","description":"An armed TP/SL trigger order, as returned by `ob_getTriggers`.","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"order_id":{"$ref":"#/components/schemas/Bytes32","description":"Identifier of the trigger (and of the synthetic order it produces when it fires)."},"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"Hash of the `submitTrigger` transaction that armed this trigger."},"bidder":{"$ref":"#/components/schemas/Address"},"nonce":{"type":"integer","format":"int64"},"size":{"type":"string","description":"Signed size of the synthetic order produced when the trigger fires (decimal int256). Positive = buy/long, negative = sell/short."},"limit_price":{"$ref":"#/components/schemas/HexUint256","description":"Limit price of the synthetic order produced when the trigger fires (1e18)."},"trigger_price":{"$ref":"#/components/schemas/HexUint256","description":"Mark-price threshold that arms the trigger (1e18)."},"trigger_type":{"$ref":"#/components/schemas/TriggerType"},"grouping":{"$ref":"#/components/schemas/TriggerGrouping"},"reduce_only":{"type":"boolean"},"ioc":{"type":"boolean","description":"Immediate-or-cancel — any unfilled remainder of the fired order is canceled at end of batch."},"deadline":{"$ref":"#/components/schemas/Timestamp"},"end":{"$ref":"#/components/schemas/Timestamp","description":"TTL expiry — the trigger is swept once `end < batch_deadline` (microseconds)."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"TriggerType":{"type":"string","enum":["take_profit","stop_loss"],"description":"Type of a TP/SL trigger order on a perp market:\n- `take_profit`: fires when the mark price moves favorably across `trigger_price`\n- `stop_loss`: fires when the mark price moves adversely across `trigger_price`\n\nAlso set on a synthetic order (`kind = triggered`) that a fired trigger produced.\n"},"TriggerGrouping":{"type":"string","enum":["none","asset","position"],"description":"Whether a trigger (and any synthetic order it produces) is bound to the bidder's exposure on the pair:\n- `none`: standalone — the trigger is removed only by a user cancel, TTL expiry, or its own fire; any synthetic order it produced survives independently\n- `asset`: exposure-bound — on perp markets the venue removes the armed trigger *and* any resting synthetic order it produced once the bidder's position on the pair reaches size 0; on spot markets, once the bidder's base-asset holdings reach 0\n\n`asset` was formerly named `position` (same semantics, same ABI value); nodes running older builds still emit `position` and clients should treat the two as equivalent.\n\nOmitted from an `Order` response when it is the default `none`.\n"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```

## The BackstopTransferResponse object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"BackstopTransferResponse":{"type":"object","description":"A perp position swept to the backstop during liquidation, as returned by `ob_getBackstopTransfers`.","properties":{"user":{"$ref":"#/components/schemas/Address","description":"Account whose position was swept."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32","description":"The orderbook the swept position belonged to. Omitted when not recorded."},"size":{"type":"string","description":"Signed position size moved to the backstop (decimal int256, 1e18). Positive = long, negative = short."},"cash":{"type":"string","description":"Signed cash moved with the position (decimal int256, 1e18)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Mark price at the sweep (1e18); hex-encoded."},"equity":{"type":"string","description":"Account equity at the moment of the sweep (decimal int256, 1e18)."},"timestamp":{"$ref":"#/components/schemas/Timestamp","description":"Timestamp of the batch that produced the sweep, in microseconds."}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```

## The GetBackstopTransfersResponse object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"GetBackstopTransfersResponse":{"type":"object","description":"Paginated result of `ob_getBackstopTransfers`.","properties":{"transfers":{"type":"array","items":{"$ref":"#/components/schemas/BackstopTransferResponse"},"description":"List of backstop transfers ordered by timestamp descending."},"total_count":{"type":"integer","description":"Count of transfers matching `(address, orderbook_id)` *before* pagination."},"next_cursor":{"type":"string","nullable":true,"description":"Pass back as `query.cursor` to fetch the next page. Wire format `\"{ts}:{id}\"`. Null if no more results."}}},"BackstopTransferResponse":{"type":"object","description":"A perp position swept to the backstop during liquidation, as returned by `ob_getBackstopTransfers`.","properties":{"user":{"$ref":"#/components/schemas/Address","description":"Account whose position was swept."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32","description":"The orderbook the swept position belonged to. Omitted when not recorded."},"size":{"type":"string","description":"Signed position size moved to the backstop (decimal int256, 1e18). Positive = long, negative = short."},"cash":{"type":"string","description":"Signed cash moved with the position (decimal int256, 1e18)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Mark price at the sweep (1e18); hex-encoded."},"equity":{"type":"string","description":"Account equity at the moment of the sweep (decimal int256, 1e18)."},"timestamp":{"$ref":"#/components/schemas/Timestamp","description":"Timestamp of the batch that produced the sweep, in microseconds."}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```

## The OraclePrice object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"OraclePrice":{"type":"object","description":"Latest oracle and mark prices recorded for a perp orderbook by the indexer.","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"oracle_price":{"$ref":"#/components/schemas/HexUint256","description":"Latest Pyth oracle price (1e18). `0` until the orderbook has run a perp batch."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Most recent non-zero clearing price (1e18). `0` until the orderbook has run a perp batch."},"as_of":{"$ref":"#/components/schemas/Timestamp","description":"Deadline of the batch that produced this row (microseconds). Epoch until the orderbook has run a perp batch."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```

## The FundingRate object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"FundingRate":{"type":"object","description":"Funding state for a perp orderbook, with the latest mark and oracle prices for context. Returned by `ob_getFundingRates`.","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"funding_rate":{"type":"string","description":"Per-`funding_window` funding rate (signed decimal int256, 1e18; may be negative)."},"funding_index":{"type":"string","description":"Cumulative per-unit-size funding accumulator (signed decimal int256, 1e18; may be negative)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Most recent mark price for the pair (1e18)."},"oracle_price":{"$ref":"#/components/schemas/HexUint256","description":"Latest Pyth oracle price (1e18)."},"as_of":{"$ref":"#/components/schemas/Timestamp","description":"Deadline of the batch that produced this funding update (microseconds). Epoch until the orderbook has run a perp batch."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```

## The RankedPosition object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"RankedPosition":{"type":"object","description":"One account's full positions snapshot, as an entry in `GetRankedPositionsResponse.ranked`.","properties":{"account":{"$ref":"#/components/schemas/Address"},"positions":{"$ref":"#/components/schemas/PositionsResponse"}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"PositionsResponse":{"type":"object","description":"Account positions across all orderbooks with aggregate PnL.","properties":{"positions":{"type":"array","items":{"$ref":"#/components/schemas/Position"},"description":"Heterogeneous list of spot holdings and open perp positions."},"total_unrealized_pnl":{"type":"string","description":"Sum of `unrealized_pnl` across every spot holding and perp position (signed, 1e18 USD)."},"total_realized_pnl":{"type":"string","description":"Lifetime portfolio-wide spot realized PnL plus the account-level perp realized-PnL counter. Both are cumulative across the account's history — closing a perp does not zero its contribution (signed, 1e18 USD).\n"},"perps_equity":{"type":"string","description":"Cash adjusted for unsettled funding plus unrealized PnL across all open perp positions. Excludes spot holdings (signed, 1e18 USD)."},"account_value":{"type":"string","description":"`perps_equity` plus the mark value of all spot holdings (signed, 1e18 USD)."},"cash":{"type":"string","description":"Deposited collateral adjusted for unsettled funding. Signed — can be negative if the account is underwater (1e18 USD)."},"withdrawable_cash":{"$ref":"#/components/schemas/HexUint256","description":"Free margin — `cash` minus the initial margin reserved by open positions (1e18 USD)."},"net_deposits":{"type":"string","description":"Net native collateral deposited minus withdrawn (signed, 1e18 USD). Negative once realized profit is withdrawn; lifetime PnL is `account_value − net_deposits`."}}},"Position":{"description":"Tagged union: a single entry in `PositionsResponse.positions`. The `kind` field selects between a `SpotHolding` (one per token) or a `PerpPosition` (one per pair).\n","oneOf":[{"$ref":"#/components/schemas/SpotHolding"},{"$ref":"#/components/schemas/PerpPosition"}],"discriminator":{"propertyName":"kind","mapping":{"spot":"#/components/schemas/SpotHolding","perp":"#/components/schemas/PerpPosition"}}},"SpotHolding":{"type":"object","description":"A token balance with cost-basis tracking. One per token the wallet has touched on a spot market.","properties":{"kind":{"type":"string","enum":["spot"],"description":"Discriminator for the `Position` union."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"balance":{"$ref":"#/components/schemas/HexUint256","description":"Total base tokens held for this market (free + locked, 1e18)."},"free_balance":{"$ref":"#/components/schemas/HexUint256","description":"Spendable portion of `balance` after sell-side order locks (1e18)."},"locked_balance":{"$ref":"#/components/schemas/HexUint256","description":"Base tokens locked in open sell orders (`balance - free_balance`, 1e18)."},"cost_basis":{"$ref":"#/components/schemas/HexUint256","description":"Total quote spent to acquire `balance` (1e18 USD)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Last clearing price for this token's market (1e18)."},"unrealized_pnl":{"type":"string","description":"`(mark - avg_cost) × balance` (signed, 1e18 USD)."},"realized_pnl":{"type":"string","description":"Lifetime realized PnL on the user's spot trading (signed, 1e18 USD; portfolio-wide for v1)."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"PerpPosition":{"type":"object","description":"A leveraged perp position. One per (user, pair).","properties":{"kind":{"type":"string","enum":["perp"],"description":"Discriminator for the `Position` union."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"side":{"$ref":"#/components/schemas/PerpPositionSide"},"size":{"type":"string","description":"Signed position size in base units (1e18). Positive = long, negative = short."},"notional":{"$ref":"#/components/schemas/HexUint256","description":"`|size| × mark_price / 1e18` — dollar value of exposure (1e18)."},"entry_price":{"$ref":"#/components/schemas/HexUint256","description":"Volume-weighted average entry price; updated only on opening fills (1e18)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Latest mark price for the pair, post batch clearing (1e18)."},"margin":{"$ref":"#/components/schemas/HexUint256","description":"Allocated initial margin; cumulative across opens/increases, released proportionally on partial closes (1e18)."},"leverage":{"$ref":"#/components/schemas/HexUint256","description":"`notional × 1e18 / margin`. Effective leverage (0 if `margin` is 0)."},"funding_accrued":{"type":"string","description":"`(market.funding − position.entry_funding) × size` (signed, 1e18 USD)."},"liquidation_price":{"$ref":"#/components/schemas/HexUint256","description":"Mark price at which this position would be liquidated against its own `margin` and the market's maintenance-margin rate. Funding ignored. 0 when position is empty."},"unrealized_pnl":{"type":"string","description":"`((mark − entry) − (funding − entry_funding)) × size` (signed, 1e18 USD)."},"realized_pnl":{"type":"string","description":"Lifetime realized PnL on this position (signed, 1e18 USD). Resets to 0 when the position closes — the next open of the same pair starts fresh."},"stop_loss":{"$ref":"#/components/schemas/HexUint256","description":"Reserved — stop-loss not yet supported.","nullable":true},"take_profit":{"$ref":"#/components/schemas/HexUint256","description":"Reserved — take-profit not yet supported.","nullable":true}}},"PerpPositionSide":{"type":"string","enum":["long","short"],"description":"Side of a perpetual position, derived from the sign of `size`."}}}}
```

## The RankedAccount object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"RankedAccount":{"type":"object","description":"An account's positions plus its zero-based rank (0 = top) in the full combined-PnL ordering.","properties":{"account":{"$ref":"#/components/schemas/Address"},"rank":{"type":"integer","description":"Zero-based rank in the full ordering (0 = top), independent of the returned page."},"positions":{"$ref":"#/components/schemas/PositionsResponse"}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"PositionsResponse":{"type":"object","description":"Account positions across all orderbooks with aggregate PnL.","properties":{"positions":{"type":"array","items":{"$ref":"#/components/schemas/Position"},"description":"Heterogeneous list of spot holdings and open perp positions."},"total_unrealized_pnl":{"type":"string","description":"Sum of `unrealized_pnl` across every spot holding and perp position (signed, 1e18 USD)."},"total_realized_pnl":{"type":"string","description":"Lifetime portfolio-wide spot realized PnL plus the account-level perp realized-PnL counter. Both are cumulative across the account's history — closing a perp does not zero its contribution (signed, 1e18 USD).\n"},"perps_equity":{"type":"string","description":"Cash adjusted for unsettled funding plus unrealized PnL across all open perp positions. Excludes spot holdings (signed, 1e18 USD)."},"account_value":{"type":"string","description":"`perps_equity` plus the mark value of all spot holdings (signed, 1e18 USD)."},"cash":{"type":"string","description":"Deposited collateral adjusted for unsettled funding. Signed — can be negative if the account is underwater (1e18 USD)."},"withdrawable_cash":{"$ref":"#/components/schemas/HexUint256","description":"Free margin — `cash` minus the initial margin reserved by open positions (1e18 USD)."},"net_deposits":{"type":"string","description":"Net native collateral deposited minus withdrawn (signed, 1e18 USD). Negative once realized profit is withdrawn; lifetime PnL is `account_value − net_deposits`."}}},"Position":{"description":"Tagged union: a single entry in `PositionsResponse.positions`. The `kind` field selects between a `SpotHolding` (one per token) or a `PerpPosition` (one per pair).\n","oneOf":[{"$ref":"#/components/schemas/SpotHolding"},{"$ref":"#/components/schemas/PerpPosition"}],"discriminator":{"propertyName":"kind","mapping":{"spot":"#/components/schemas/SpotHolding","perp":"#/components/schemas/PerpPosition"}}},"SpotHolding":{"type":"object","description":"A token balance with cost-basis tracking. One per token the wallet has touched on a spot market.","properties":{"kind":{"type":"string","enum":["spot"],"description":"Discriminator for the `Position` union."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"balance":{"$ref":"#/components/schemas/HexUint256","description":"Total base tokens held for this market (free + locked, 1e18)."},"free_balance":{"$ref":"#/components/schemas/HexUint256","description":"Spendable portion of `balance` after sell-side order locks (1e18)."},"locked_balance":{"$ref":"#/components/schemas/HexUint256","description":"Base tokens locked in open sell orders (`balance - free_balance`, 1e18)."},"cost_basis":{"$ref":"#/components/schemas/HexUint256","description":"Total quote spent to acquire `balance` (1e18 USD)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Last clearing price for this token's market (1e18)."},"unrealized_pnl":{"type":"string","description":"`(mark - avg_cost) × balance` (signed, 1e18 USD)."},"realized_pnl":{"type":"string","description":"Lifetime realized PnL on the user's spot trading (signed, 1e18 USD; portfolio-wide for v1)."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"PerpPosition":{"type":"object","description":"A leveraged perp position. One per (user, pair).","properties":{"kind":{"type":"string","enum":["perp"],"description":"Discriminator for the `Position` union."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"side":{"$ref":"#/components/schemas/PerpPositionSide"},"size":{"type":"string","description":"Signed position size in base units (1e18). Positive = long, negative = short."},"notional":{"$ref":"#/components/schemas/HexUint256","description":"`|size| × mark_price / 1e18` — dollar value of exposure (1e18)."},"entry_price":{"$ref":"#/components/schemas/HexUint256","description":"Volume-weighted average entry price; updated only on opening fills (1e18)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Latest mark price for the pair, post batch clearing (1e18)."},"margin":{"$ref":"#/components/schemas/HexUint256","description":"Allocated initial margin; cumulative across opens/increases, released proportionally on partial closes (1e18)."},"leverage":{"$ref":"#/components/schemas/HexUint256","description":"`notional × 1e18 / margin`. Effective leverage (0 if `margin` is 0)."},"funding_accrued":{"type":"string","description":"`(market.funding − position.entry_funding) × size` (signed, 1e18 USD)."},"liquidation_price":{"$ref":"#/components/schemas/HexUint256","description":"Mark price at which this position would be liquidated against its own `margin` and the market's maintenance-margin rate. Funding ignored. 0 when position is empty."},"unrealized_pnl":{"type":"string","description":"`((mark − entry) − (funding − entry_funding)) × size` (signed, 1e18 USD)."},"realized_pnl":{"type":"string","description":"Lifetime realized PnL on this position (signed, 1e18 USD). Resets to 0 when the position closes — the next open of the same pair starts fresh."},"stop_loss":{"$ref":"#/components/schemas/HexUint256","description":"Reserved — stop-loss not yet supported.","nullable":true},"take_profit":{"$ref":"#/components/schemas/HexUint256","description":"Reserved — take-profit not yet supported.","nullable":true}}},"PerpPositionSide":{"type":"string","enum":["long","short"],"description":"Side of a perpetual position, derived from the sign of `size`."}}}}
```

## The GetRankedPositionsResponse object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"GetRankedPositionsResponse":{"type":"object","description":"Paginated leaderboard of accounts ordered by combined realized + unrealized PnL descending.","properties":{"ranked":{"type":"array","items":{"$ref":"#/components/schemas/RankedPosition"},"description":"The requested `[offset, offset + limit)` window, ordered by combined PnL descending."},"total":{"type":"integer","description":"Full count of ranked accounts before pagination."},"queried":{"$ref":"#/components/schemas/RankedAccount","nullable":true,"description":"Populated only when the request supplies an `address` — that account's positions and rank. Null if no address was given, or the account has no PnL-bearing state."}}},"RankedPosition":{"type":"object","description":"One account's full positions snapshot, as an entry in `GetRankedPositionsResponse.ranked`.","properties":{"account":{"$ref":"#/components/schemas/Address"},"positions":{"$ref":"#/components/schemas/PositionsResponse"}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"PositionsResponse":{"type":"object","description":"Account positions across all orderbooks with aggregate PnL.","properties":{"positions":{"type":"array","items":{"$ref":"#/components/schemas/Position"},"description":"Heterogeneous list of spot holdings and open perp positions."},"total_unrealized_pnl":{"type":"string","description":"Sum of `unrealized_pnl` across every spot holding and perp position (signed, 1e18 USD)."},"total_realized_pnl":{"type":"string","description":"Lifetime portfolio-wide spot realized PnL plus the account-level perp realized-PnL counter. Both are cumulative across the account's history — closing a perp does not zero its contribution (signed, 1e18 USD).\n"},"perps_equity":{"type":"string","description":"Cash adjusted for unsettled funding plus unrealized PnL across all open perp positions. Excludes spot holdings (signed, 1e18 USD)."},"account_value":{"type":"string","description":"`perps_equity` plus the mark value of all spot holdings (signed, 1e18 USD)."},"cash":{"type":"string","description":"Deposited collateral adjusted for unsettled funding. Signed — can be negative if the account is underwater (1e18 USD)."},"withdrawable_cash":{"$ref":"#/components/schemas/HexUint256","description":"Free margin — `cash` minus the initial margin reserved by open positions (1e18 USD)."},"net_deposits":{"type":"string","description":"Net native collateral deposited minus withdrawn (signed, 1e18 USD). Negative once realized profit is withdrawn; lifetime PnL is `account_value − net_deposits`."}}},"Position":{"description":"Tagged union: a single entry in `PositionsResponse.positions`. The `kind` field selects between a `SpotHolding` (one per token) or a `PerpPosition` (one per pair).\n","oneOf":[{"$ref":"#/components/schemas/SpotHolding"},{"$ref":"#/components/schemas/PerpPosition"}],"discriminator":{"propertyName":"kind","mapping":{"spot":"#/components/schemas/SpotHolding","perp":"#/components/schemas/PerpPosition"}}},"SpotHolding":{"type":"object","description":"A token balance with cost-basis tracking. One per token the wallet has touched on a spot market.","properties":{"kind":{"type":"string","enum":["spot"],"description":"Discriminator for the `Position` union."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"balance":{"$ref":"#/components/schemas/HexUint256","description":"Total base tokens held for this market (free + locked, 1e18)."},"free_balance":{"$ref":"#/components/schemas/HexUint256","description":"Spendable portion of `balance` after sell-side order locks (1e18)."},"locked_balance":{"$ref":"#/components/schemas/HexUint256","description":"Base tokens locked in open sell orders (`balance - free_balance`, 1e18)."},"cost_basis":{"$ref":"#/components/schemas/HexUint256","description":"Total quote spent to acquire `balance` (1e18 USD)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Last clearing price for this token's market (1e18)."},"unrealized_pnl":{"type":"string","description":"`(mark - avg_cost) × balance` (signed, 1e18 USD)."},"realized_pnl":{"type":"string","description":"Lifetime realized PnL on the user's spot trading (signed, 1e18 USD; portfolio-wide for v1)."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"PerpPosition":{"type":"object","description":"A leveraged perp position. One per (user, pair).","properties":{"kind":{"type":"string","enum":["perp"],"description":"Discriminator for the `Position` union."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"side":{"$ref":"#/components/schemas/PerpPositionSide"},"size":{"type":"string","description":"Signed position size in base units (1e18). Positive = long, negative = short."},"notional":{"$ref":"#/components/schemas/HexUint256","description":"`|size| × mark_price / 1e18` — dollar value of exposure (1e18)."},"entry_price":{"$ref":"#/components/schemas/HexUint256","description":"Volume-weighted average entry price; updated only on opening fills (1e18)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Latest mark price for the pair, post batch clearing (1e18)."},"margin":{"$ref":"#/components/schemas/HexUint256","description":"Allocated initial margin; cumulative across opens/increases, released proportionally on partial closes (1e18)."},"leverage":{"$ref":"#/components/schemas/HexUint256","description":"`notional × 1e18 / margin`. Effective leverage (0 if `margin` is 0)."},"funding_accrued":{"type":"string","description":"`(market.funding − position.entry_funding) × size` (signed, 1e18 USD)."},"liquidation_price":{"$ref":"#/components/schemas/HexUint256","description":"Mark price at which this position would be liquidated against its own `margin` and the market's maintenance-margin rate. Funding ignored. 0 when position is empty."},"unrealized_pnl":{"type":"string","description":"`((mark − entry) − (funding − entry_funding)) × size` (signed, 1e18 USD)."},"realized_pnl":{"type":"string","description":"Lifetime realized PnL on this position (signed, 1e18 USD). Resets to 0 when the position closes — the next open of the same pair starts fresh."},"stop_loss":{"$ref":"#/components/schemas/HexUint256","description":"Reserved — stop-loss not yet supported.","nullable":true},"take_profit":{"$ref":"#/components/schemas/HexUint256","description":"Reserved — take-profit not yet supported.","nullable":true}}},"PerpPositionSide":{"type":"string","enum":["long","short"],"description":"Side of a perpetual position, derived from the sign of `size`."},"RankedAccount":{"type":"object","description":"An account's positions plus its zero-based rank (0 = top) in the full combined-PnL ordering.","properties":{"account":{"$ref":"#/components/schemas/Address"},"rank":{"type":"integer","description":"Zero-based rank in the full ordering (0 = top), independent of the returned page."},"positions":{"$ref":"#/components/schemas/PositionsResponse"}}}}}}
```

## The SubscriptionParams object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"SubscriptionParams":{"type":"object","description":"Options object (second `eth_subscribe` param). All fields are optional except that\n`pod_positions` / `pod_triggers` require `account` (alias `bidder`). Which fields take\neffect depends on the subscription type:\n- `orderbook_ids` (alias `clob_ids`) — `pod_orderbook`, `pod_orders`, `pod_orders_v2`,\n  `pod_candles`, `pod_markets`; ignored by `pod_positions` / `pod_triggers`.\n- `depth` — `pod_orderbook` only.\n- `bidder` (alias `account`) — optional for `pod_orders` / `pod_orders_v2`; **required** for\n  `pod_positions` and `pod_triggers`.\n- `bidders` — `pod_orders_v2` only, to follow several accounts on one subscription.\n  Mutually exclusive with `bidder`.\n- `since` — all channels (catch-up watermark, microseconds).\n- `since_book` — `pod_orders_v2` only, completing its `(batch, book)` resume cursor.\n","properties":{"depth":{"type":"integer","description":"`pod_orderbook` only: maximum price levels per side to include in snapshots. Omit for all levels."},"orderbook_ids":{"type":"array","items":{"$ref":"#/components/schemas/Bytes32"},"description":"Orderbook (clob) IDs to restrict the subscription to (accepted alias: `clob_ids`). Empty or omitted = all orderbooks. Honored by `pod_orderbook`, `pod_orders`, `pod_candles`, `pod_markets`; ignored by the account-scoped channels."},"clob_ids":{"type":"array","items":{"$ref":"#/components/schemas/Bytes32"},"description":"Accepted alias for `orderbook_ids`."},"bidder":{"$ref":"#/components/schemas/Address","description":"Account filter (accepted alias: `account`). For `pod_orders`, when set, streams only this bidder's updates (omit for all bidders). For `pod_positions` / `pod_triggers` this is **required** — the account whose positions / triggers to stream. On `pod_orders_v2` it is the single-account form of `bidders`, and sending both is an error."},"bidders":{"type":"array","items":{"$ref":"#/components/schemas/Address"},"description":"`pod_orders_v2` only: follow several accounts on one subscription, streaming\nonly rows owned by them. One subscription instead of one per account — each\nsubscription costs the server a copy of every batch, a notification and a\nsocket write whether or not your accounts traded, so this is markedly\ncheaper than N of them.\n\nTreated as a **set**: order is irrelevant and repeats are collapsed, so the\n64-account limit counts *distinct* accounts. Exceeding it is an error, as is\nsending it together with `bidder` (which is the single-account form) or on\nany other channel — a filter that silently did not apply would hand you the\nwhole book.\n\n**This changes the frame shape.** With more than one account the frame\ncarries the `accts` table and every row carries an `a` index, exactly as an\nunfiltered stream does, because otherwise its rows would not be\nattributable. With exactly one account (whether via `bidders` or `bidder`)\nboth are omitted, since every row belongs to you. Decode on the presence of\n`accts`, not on whether you sent a filter.\n"},"since":{"type":"integer","format":"int64","description":"Catch-up watermark: a solution time in microseconds. Delta channels replay buffered ticks after it; state channels emit one current snapshot then stream live. Omit for live-only. If a delta channel's `since` predates the retained buffer, the subscription is rejected."},"since_book":{"$ref":"#/components/schemas/Bytes32","description":"`pod_orders_v2` only: the `book` of the last frame accepted at `since`, which together with it forms the resume cursor. A batch is delivered as one frame per orderbook, so a client can hold part of a batch; replay skips every book at or below this one within `since`, then delivers later batches whole. Omit when the whole of `since` arrived (always true when subscribed to a single orderbook)."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"}}}}
```

## The EthSubscriptionMessage object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"EthSubscriptionMessage":{"type":"object","description":"An asynchronous `eth_subscription` notification pushed over the WebSocket after\n`eth_subscribe`. The `params.result` payload depends on the subscription type:\n- `pod_orderbook` → an `OrderbookSnapshot`.\n- `pod_orders` → an array of `OrderUpdate`.\n- `pod_candles` → a `CandleTick`.\n- `pod_markets` → a `MarketDynamicEntry`.\n- `pod_positions` → a `PositionsUpdate`.\n- `pod_triggers` → a `TriggersUpdate`.\n","properties":{"jsonrpc":{"type":"string","enum":["2.0"]},"method":{"type":"string","enum":["eth_subscription"]},"params":{"type":"object","properties":{"subscription":{"type":"string","description":"The subscription ID this message belongs to."},"result":{"description":"The streamed payload — shape determined by the subscription type.","oneOf":[{"$ref":"#/components/schemas/OrderbookSnapshot"},{"type":"array","items":{"$ref":"#/components/schemas/OrderUpdate"}},{"$ref":"#/components/schemas/CandleTick"},{"$ref":"#/components/schemas/MarketDynamicEntry"},{"$ref":"#/components/schemas/PositionsUpdate"},{"$ref":"#/components/schemas/TriggersUpdate"}]}}}}},"OrderbookSnapshot":{"type":"object","description":"Current state of an orderbook with aggregated buy/sell levels.\nThe response field is `orderbook_id`; `clob_id` is accepted as an input alias when deserializing.\n","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32","description":"Orderbook identifier. Also accepts `clob_id` as an alias on input."},"buys":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/TickSnapshot"},"description":"Buy orders keyed by price (decimal string), sorted by price descending"},"sells":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/TickSnapshot"},"description":"Sell orders keyed by price (decimal string), sorted by price ascending"},"clearing_price":{"$ref":"#/components/schemas/HexUint256","description":"Current/last clearing price"},"grouping_precision":{"$ref":"#/components/schemas/HexUint256","description":"Price grouping precision used for aggregation (1e18, hex-encoded)"},"timestamp":{"type":"integer","description":"Snapshot timestamp in microseconds"},"new_orders_count":{"type":"integer","description":"Number of new orders since the last snapshot"},"buys_count":{"type":"integer","description":"Total number of buy orders in the orderbook (regardless of depth parameter)"},"sells_count":{"type":"integer","description":"Total number of sell orders in the orderbook (regardless of depth parameter)"},"oracle_price":{"type":"string","nullable":true,"description":"Perp orderbooks only. Pyth oracle price from the most recent perp solution's `priceProof` (1e18, hex-encoded). `null` for spot orderbooks."},"funding_rate":{"type":"string","nullable":true,"description":"Perp orderbooks only. Funding rate computed for this batch (per-`funding_window`, signed 1e18 decimal string). `null` for spot orderbooks."},"funding_index":{"type":"string","nullable":true,"description":"Perp orderbooks only. Cumulative per-unit-size funding accumulator after this batch (signed 1e18 decimal string). `null` for spot orderbooks."},"funding_last_updated":{"type":"integer","format":"int64","nullable":true,"description":"Perp orderbooks only. Microsecond timestamp of the batch that produced the funding update. `null` for spot orderbooks."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"TickSnapshot":{"type":"object","description":"Aggregated order volume at a specific price level","properties":{"volume":{"$ref":"#/components/schemas/HexUint256","description":"Total volume available at this price level (1e18, hex-encoded)"}}},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"OrderUpdate":{"type":"object","description":"A single change to an order, pushed in the `pod_orders` notification array. It is a\n`type`-tagged union: the `type` field selects the variant and the remaining fields depend\non it.\n- `new` / `invalid`: the full `Order` fields are inlined alongside `type` (an `invalid`\n  order was rejected at execution and never entered the book; the reason is on its\n  `status`).\n- `expired` / `canceled`: only `type` and `order_id` are present.\n- `modified`: a resting order's price and/or size was changed in place by an `update`\n  intent — `type`, `order_id`, and the new `new_price` / `new_size` are present.\n- `fill`: the `OrderFillUpdate` fields are inlined alongside `type`.\n","required":["type"],"properties":{"type":{"type":"string","enum":["new","invalid","expired","canceled","modified","fill"],"description":"Discriminator selecting the variant."},"order_id":{"$ref":"#/components/schemas/Bytes32","description":"Present for `expired`, `canceled`, and `modified` — the affected order id."},"new_price":{"$ref":"#/components/schemas/HexUint256","description":"`modified` only: the order's price after the change (1e18)."},"new_size":{"$ref":"#/components/schemas/HexUint256","description":"`modified` only: the order's remaining base size after the change (1e18, unsigned magnitude — side is unchanged from the original `new`)."}}},"CandleTick":{"type":"object","description":"Per-tick candle hint streamed on the `pod_candles` subscription — one object per orderbook\ncleared this settlement. It is not a closed OHLCV bar (use `ob_getCandles` for those); the\nclient folds it into the forming bar.\n","required":["orderbook","timestamp_us","price","volume"],"properties":{"orderbook":{"$ref":"#/components/schemas/Bytes32"},"timestamp_us":{"type":"integer","format":"int64","description":"Batch deadline (settlement time) in microseconds."},"price":{"type":"string","description":"Clearing price for this tick (decimal, 1e18)."},"volume":{"type":"string","description":"Total volume cleared this tick (decimal, 1e18)."}}},"MarketDynamicEntry":{"type":"object","description":"Live market statistics for one orderbook, streamed on the `pod_markets` subscription (one\nobject per orderbook). Optional fields are omitted (not null) when unset — e.g. perp-only\nfields on a spot market, or stats with no data yet.\n","required":["orderbook_id","volume_24h"],"properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"last_clearing_price":{"type":"string","description":"Most recent clearing price (decimal, 1e18). Omitted if the market has not cleared."},"volume_24h":{"type":"string","description":"Rolling 24h traded volume (decimal, 1e18)."},"high_24h":{"type":"string","description":"24h high clearing price (decimal, 1e18). Omitted if unavailable."},"low_24h":{"type":"string","description":"24h low clearing price (decimal, 1e18). Omitted if unavailable."},"price_change_24h":{"type":"integer","format":"int128","description":"24h price change (signed, 1e18), as a JSON number. Omitted if unavailable."},"oracle_price":{"type":"string","description":"Perp only: latest oracle price (decimal, 1e18)."},"mark_price":{"type":"string","description":"Perp only: current mark price (decimal, 1e18)."},"funding_rate":{"type":"string","description":"Perp only: current funding rate (decimal)."},"funding_index":{"type":"string","description":"Perp only: cumulative funding index (decimal)."},"funding_last_updated_us":{"type":"integer","format":"int64","description":"Perp only: last funding update time (microseconds)."},"open_interest":{"type":"string","description":"Perp only: open interest (decimal, 1e18)."}}},"PositionsUpdate":{"type":"object","description":"A `pod_positions` notification — the account's full positions snapshot, pushed for a settlement that touched the account.","required":["account","data"],"properties":{"account":{"$ref":"#/components/schemas/Address"},"data":{"$ref":"#/components/schemas/PositionsResponse"}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"PositionsResponse":{"type":"object","description":"Account positions across all orderbooks with aggregate PnL.","properties":{"positions":{"type":"array","items":{"$ref":"#/components/schemas/Position"},"description":"Heterogeneous list of spot holdings and open perp positions."},"total_unrealized_pnl":{"type":"string","description":"Sum of `unrealized_pnl` across every spot holding and perp position (signed, 1e18 USD)."},"total_realized_pnl":{"type":"string","description":"Lifetime portfolio-wide spot realized PnL plus the account-level perp realized-PnL counter. Both are cumulative across the account's history — closing a perp does not zero its contribution (signed, 1e18 USD).\n"},"perps_equity":{"type":"string","description":"Cash adjusted for unsettled funding plus unrealized PnL across all open perp positions. Excludes spot holdings (signed, 1e18 USD)."},"account_value":{"type":"string","description":"`perps_equity` plus the mark value of all spot holdings (signed, 1e18 USD)."},"cash":{"type":"string","description":"Deposited collateral adjusted for unsettled funding. Signed — can be negative if the account is underwater (1e18 USD)."},"withdrawable_cash":{"$ref":"#/components/schemas/HexUint256","description":"Free margin — `cash` minus the initial margin reserved by open positions (1e18 USD)."},"net_deposits":{"type":"string","description":"Net native collateral deposited minus withdrawn (signed, 1e18 USD). Negative once realized profit is withdrawn; lifetime PnL is `account_value − net_deposits`."}}},"Position":{"description":"Tagged union: a single entry in `PositionsResponse.positions`. The `kind` field selects between a `SpotHolding` (one per token) or a `PerpPosition` (one per pair).\n","oneOf":[{"$ref":"#/components/schemas/SpotHolding"},{"$ref":"#/components/schemas/PerpPosition"}],"discriminator":{"propertyName":"kind","mapping":{"spot":"#/components/schemas/SpotHolding","perp":"#/components/schemas/PerpPosition"}}},"SpotHolding":{"type":"object","description":"A token balance with cost-basis tracking. One per token the wallet has touched on a spot market.","properties":{"kind":{"type":"string","enum":["spot"],"description":"Discriminator for the `Position` union."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"balance":{"$ref":"#/components/schemas/HexUint256","description":"Total base tokens held for this market (free + locked, 1e18)."},"free_balance":{"$ref":"#/components/schemas/HexUint256","description":"Spendable portion of `balance` after sell-side order locks (1e18)."},"locked_balance":{"$ref":"#/components/schemas/HexUint256","description":"Base tokens locked in open sell orders (`balance - free_balance`, 1e18)."},"cost_basis":{"$ref":"#/components/schemas/HexUint256","description":"Total quote spent to acquire `balance` (1e18 USD)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Last clearing price for this token's market (1e18)."},"unrealized_pnl":{"type":"string","description":"`(mark - avg_cost) × balance` (signed, 1e18 USD)."},"realized_pnl":{"type":"string","description":"Lifetime realized PnL on the user's spot trading (signed, 1e18 USD; portfolio-wide for v1)."}}},"PerpPosition":{"type":"object","description":"A leveraged perp position. One per (user, pair).","properties":{"kind":{"type":"string","enum":["perp"],"description":"Discriminator for the `Position` union."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"side":{"$ref":"#/components/schemas/PerpPositionSide"},"size":{"type":"string","description":"Signed position size in base units (1e18). Positive = long, negative = short."},"notional":{"$ref":"#/components/schemas/HexUint256","description":"`|size| × mark_price / 1e18` — dollar value of exposure (1e18)."},"entry_price":{"$ref":"#/components/schemas/HexUint256","description":"Volume-weighted average entry price; updated only on opening fills (1e18)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Latest mark price for the pair, post batch clearing (1e18)."},"margin":{"$ref":"#/components/schemas/HexUint256","description":"Allocated initial margin; cumulative across opens/increases, released proportionally on partial closes (1e18)."},"leverage":{"$ref":"#/components/schemas/HexUint256","description":"`notional × 1e18 / margin`. Effective leverage (0 if `margin` is 0)."},"funding_accrued":{"type":"string","description":"`(market.funding − position.entry_funding) × size` (signed, 1e18 USD)."},"liquidation_price":{"$ref":"#/components/schemas/HexUint256","description":"Mark price at which this position would be liquidated against its own `margin` and the market's maintenance-margin rate. Funding ignored. 0 when position is empty."},"unrealized_pnl":{"type":"string","description":"`((mark − entry) − (funding − entry_funding)) × size` (signed, 1e18 USD)."},"realized_pnl":{"type":"string","description":"Lifetime realized PnL on this position (signed, 1e18 USD). Resets to 0 when the position closes — the next open of the same pair starts fresh."},"stop_loss":{"$ref":"#/components/schemas/HexUint256","description":"Reserved — stop-loss not yet supported.","nullable":true},"take_profit":{"$ref":"#/components/schemas/HexUint256","description":"Reserved — take-profit not yet supported.","nullable":true}}},"PerpPositionSide":{"type":"string","enum":["long","short"],"description":"Side of a perpetual position, derived from the sign of `size`."},"TriggersUpdate":{"type":"object","description":"A `pod_triggers` notification — the account's armed TP/SL triggers, pushed for a settlement that touched the account. Carries the `GetTriggersResponse` fields inlined alongside `account`.","required":["account","triggers","total_count"],"properties":{"account":{"$ref":"#/components/schemas/Address"},"triggers":{"type":"array","items":{"$ref":"#/components/schemas/TriggerOrderResponse"}},"total_count":{"type":"integer","description":"Count of triggers for the account before pagination."},"next_cursor":{"type":"string","nullable":true,"description":"Pagination cursor, wire format `\"{orderbook_id}:{order_id}\"`. Null if no more results."}}},"TriggerOrderResponse":{"type":"object","description":"An armed TP/SL trigger order, as returned by `ob_getTriggers`.","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"order_id":{"$ref":"#/components/schemas/Bytes32","description":"Identifier of the trigger (and of the synthetic order it produces when it fires)."},"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"Hash of the `submitTrigger` transaction that armed this trigger."},"bidder":{"$ref":"#/components/schemas/Address"},"nonce":{"type":"integer","format":"int64"},"size":{"type":"string","description":"Signed size of the synthetic order produced when the trigger fires (decimal int256). Positive = buy/long, negative = sell/short."},"limit_price":{"$ref":"#/components/schemas/HexUint256","description":"Limit price of the synthetic order produced when the trigger fires (1e18)."},"trigger_price":{"$ref":"#/components/schemas/HexUint256","description":"Mark-price threshold that arms the trigger (1e18)."},"trigger_type":{"$ref":"#/components/schemas/TriggerType"},"grouping":{"$ref":"#/components/schemas/TriggerGrouping"},"reduce_only":{"type":"boolean"},"ioc":{"type":"boolean","description":"Immediate-or-cancel — any unfilled remainder of the fired order is canceled at end of batch."},"deadline":{"$ref":"#/components/schemas/Timestamp"},"end":{"$ref":"#/components/schemas/Timestamp","description":"TTL expiry — the trigger is swept once `end < batch_deadline` (microseconds)."}}},"TriggerType":{"type":"string","enum":["take_profit","stop_loss"],"description":"Type of a TP/SL trigger order on a perp market:\n- `take_profit`: fires when the mark price moves favorably across `trigger_price`\n- `stop_loss`: fires when the mark price moves adversely across `trigger_price`\n\nAlso set on a synthetic order (`kind = triggered`) that a fired trigger produced.\n"},"TriggerGrouping":{"type":"string","enum":["none","asset","position"],"description":"Whether a trigger (and any synthetic order it produces) is bound to the bidder's exposure on the pair:\n- `none`: standalone — the trigger is removed only by a user cancel, TTL expiry, or its own fire; any synthetic order it produced survives independently\n- `asset`: exposure-bound — on perp markets the venue removes the armed trigger *and* any resting synthetic order it produced once the bidder's position on the pair reaches size 0; on spot markets, once the bidder's base-asset holdings reach 0\n\n`asset` was formerly named `position` (same semantics, same ABI value); nodes running older builds still emit `position` and clients should treat the two as equivalent.\n\nOmitted from an `Order` response when it is the default `none`.\n"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```

## The OrdersFrameV2 object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"OrdersFrameV2":{"type":"object","description":"One `pod_orders_v2` notification: everything that happened to one orderbook in one auction\nbatch.\n\nThe batch and the orderbook are named once, orders created in the batch appear once in\n`orders`, and `events` describes what happened, referencing an order by `o` (an index into\n`orders`) or by `id` (an order resting from an earlier batch). Ignore event kinds and fields\nyou do not recognise — new kinds are added without a new channel version.\n","required":["book","batch","orders","events"],"properties":{"book":{"$ref":"#/components/schemas/Bytes32","description":"The orderbook these actions happened on."},"batch":{"type":"integer","format":"int64","description":"Deadline of the batch the actions **landed in**, in microseconds. For an order this is at\nor before the `deadline` it was signed for, because an intent may be included in an\nearlier batch than the one it targets. Also the first half of the resume cursor\n(`since`); the second is this frame's `book` (`since_book`).\n"},"accts":{"type":"array","items":{"$ref":"#/components/schemas/Address"},"description":"Owner addresses, referenced by index from `orders[].a` and from events that name an\norder by `id`.\n\nOmitted only when the subscription names exactly one account (`bidder`, or a\none-element `bidders`), where every row belongs to you and an index would say\nnothing. A subscription naming *several* accounts carries the table just like an\nunfiltered one. Decode on this field's presence rather than on the filter you sent.\n"},"orders":{"type":"array","items":{"$ref":"#/components/schemas/OrderEntityV2"},"description":"Orders created in this batch, each appearing exactly once."},"events":{"type":"array","items":{"$ref":"#/components/schemas/OrderEventV2"},"description":"What happened, in a deterministic order: new/rejected orders, then fills ascending by\norder id, then cancellations, expirations and modifications, then backstop sweeps.\n"}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"OrderEntityV2":{"type":"object","description":"An order as admitted, in a `pod_orders_v2` frame: the facts that do not change. Its status is\n**not** here — that is implied by the events referencing it, which is what lets new event\nkinds be added without changing this object.\n\nOptional fields are omitted at their default rather than sent, so a plain user-signed limit\norder is small. Each omission means a specific thing, noted per field.\n","required":["id","tx","n","px","sz"],"properties":{"id":{"$ref":"#/components/schemas/Bytes32","description":"Resting order id, as used by cancel/update intents and the REST order APIs.\n\nDerived as `keccak256(abi_encode(signer, nonce, sequence))`, where `signer` is the key\nthat signed the transaction, `nonce` is that transaction's nonce (this entity's `n`), and\n`sequence` is the order's position inside a `submitBatch` envelope — `0` for a\nsingle-intent transaction. So you can compute the id yourself before broadcasting and\nmatch your own orders to this stream the first time it mentions them, without waiting on\na receipt.\n\n**For a delegated order, derive from the delegate's address, not the master's.** The id\nkeys on the signer so two delegates of one master cannot collide, whereas `a`/`accts`\nreport the *owner*. The two differ exactly when a delegate placed the order.\n"},"tx":{"$ref":"#/components/schemas/Bytes32","description":"Hash of the creating transaction, or of its parent `submitBatch` envelope. Zero for engine-generated orders."},"a":{"type":"integer","description":"Index into the frame's `accts`. Present if and only if `accts` is — see there."},"n":{"type":"integer","format":"int64","description":"Nonce of the **transaction** that created the order — the signing key's nonce, not a\nper-order counter. For a delegated order that is the *delegate's* nonce, not the\nmaster's.\n\nTwo orders from one `submitBatch` therefore share both `n` and `tx`, and differ only in\n`id`: `n` belongs to the envelope, not to the intents inside it. Use `id` to tell them\napart.\n"},"px":{"type":"string","description":"Limit price in quote/base units, 1e18-scaled, as a decimal string."},"sz":{"type":"string","description":"Signed order size, 1e18-scaled, decimal. Positive = buy/long, negative = sell/short — the sign carries the side, so there is no separate side field."},"end":{"type":"integer","format":"int64","description":"TTL expiry in microseconds. **Omitted means the order never expires** (rather than unknown)."},"kind":{"type":"string","enum":["liquidation","triggered","adl","adl_counterparty","backstop_transfer"],"description":"How the order came about. **Omitted means user-signed.**"},"type":{"type":"string","enum":["market"],"description":"**Omitted means a limit order.**"},"reduce_only":{"type":"boolean","description":"Omitted means false."},"ioc":{"type":"boolean","description":"Immediate-or-cancel. Omitted means false."},"trigger":{"type":"string","enum":["take_profit","stop_loss"],"description":"Which trigger produced this order. Omitted unless it is a fired trigger's synthetic."},"grouping":{"type":"string","enum":["asset"],"description":"Trigger grouping inherited from the parent trigger. Omitted when ungrouped."}}},"OrderEventV2":{"type":"object","description":"One transition in a `pod_orders_v2` frame, discriminated by `k`.\n\nEvery event names the order it concerns by exactly one of `o` (an index into this frame's\n`orders`) or `id` (an order resting from an earlier batch, whose owner is `a`). **Ignore\nvalues of `k` you do not recognise**: new kinds will be added without a new channel version.\n","required":["k"],"properties":{"k":{"type":"string","enum":["new","reject","fill","cancel","expire","modify","modify_reject"],"description":"- `new` — the order entered the book.\n- `reject` — dropped during execution, never rested; `why` carries the reason.\n- `fill` — matched, wholly or partly.\n- `cancel` — removed by a cancel intent or by the engine.\n- `expire` — removed on reaching its TTL.\n- `modify` — a resting order's price and/or size changed in place.\n- `modify_reject` — an amendment the engine refused. The order is untouched; `code` says why.\n"},"o":{"type":"integer","description":"Index into this frame's `orders`. Present when the order was created in this batch."},"id":{"$ref":"#/components/schemas/Bytes32","description":"Order id. Present instead of `o` when the order has been resting since an earlier batch."},"a":{"type":"integer","description":"Index into the frame's `accts`, accompanying `id`. Present if and only if `accts` is."},"why":{"type":"string","description":"On `reject`, why the engine dropped the order. On `modify_reject`, detail the `code`\ncannot carry — the amounts on `insufficient_balance`, `invalid_price` and\n`notional_below_minimum`, the pair on `unknown_market`, the whole reason on\n`unspecified`. Absent for every other code, where it would restate the code.\n"},"by":{"type":"integer","description":"`modify_reject` only: index into the frame's `accts` for the account that *asked*, which\nis deliberately not `a`. A refusal says nothing about who owns the order, and on\n`not_order_owner` the requester is precisely who does not. Absent when the subscription\nnames a single account.\n"},"req_px":{"type":"string","description":"`modify_reject` only: the price that was asked for, 1e18-scaled decimal. Echoed so a client with several amendments outstanding on one order can tell which this answers."},"req_sz":{"type":"string","description":"`modify_reject` only: the size that was asked for, 1e18-scaled decimal, unsigned."},"code":{"type":"string","enum":["insufficient_balance","invalid_price","zero_size","notional_below_minimum","unknown_market","order_not_found","not_order_owner","stale_nonce","wrong_pair","engine_managed_order","price_above_maximum","price_off_tick","market_order_must_be_ioc","size_above_maximum","size_off_lot","notional_overflow","notional_above_cap","unspecified"],"description":"`modify_reject` only: the stable reason identifier — branch on this, not on `why`.\nTreat a value you do not recognise as `unspecified`: the set grows as the engine names\nreasons, and `unspecified` itself means it has not named this one yet.\n"},"b":{"type":"string","description":"`fill` only. Base filled **by this fill**, 1e18-scaled decimal — this batch's amount, not a running total."},"q":{"type":"string","description":"`fill` only. Quote filled by this fill, 1e18-scaled decimal."},"tb":{"type":"string","description":"Total base filled over the order's life, 1e18-scaled decimal. On `fill`, the running\ntotal **so far**; on `cancel` and `expire`, the final total the order left the book with.\n\nOn a `fill` it is sent alongside `b` rather than instead of it: `b` is what you apply,\n`tb` is what you check your running figure against, so a divergence surfaces on the next\nfill instead of drifting. On a terminal event it is the settled figure, so you need no\naccumulation at all — see the terminal-totals rule on the method description.\n\nZero is sent rather than the field being omitted, so an order that never filled is\nreported as such rather than being indistinguishable from a field you failed to read.\n"},"tq":{"type":"string","description":"Total quote filled over the order's life, 1e18-scaled decimal. Running total on `fill`, final total on `cancel`/`expire`, as `tb`."},"tf":{"type":"string","description":"Total fee charged over the order's life, 1e18-scaled decimal. Running total on `fill`,\nfinal total on `cancel`/`expire`, as `tb`.\n\nThere is no per-fill fee counterpart — no such figure exists at this boundary to send. For\nthe fee attributable to one fill, subtract the previous `tf` seen for that order, or zero\non its first fill.\n"},"st":{"type":"string","enum":["filled","canceled","margin_canceled","expired"],"description":"`fill` only, and only on the fill that **closed** the order, carrying the status it closed with. Its absence means the order is still working."},"pa":{"type":"string","description":"`fill`: the owner's position after this fill, 1e18-scaled **signed** decimal.\n\nPresent when a fill moved a position — so absent on spot, which has none, and absent\non the two fills the engine fabricates without moving one (the backstop sweep, and the\nzero-size fill a cap-to-filled amendment emits to carry `st`). Do **not** read its\nabsence as \"spot\": take market type from the market. A client tracking positions treats\nan absent `pa` as unchanged, which it is.\nThe position *before* is not sent because it is derivable — `pa - sign(sz) * b`, the same\narithmetic the engine used to produce the pair — and the transition between the two is\nwhat says whether the fill opened, added to, reduced, closed or flipped the position. A\nraw position rather than a label so a client tracking positions off this stream can also\nassert its running figure against it, the way `tb`/`tq` anchor the amounts.\n"},"px":{"type":"string","description":"`modify` only: the order's price after the change, 1e18-scaled decimal."},"sz":{"type":"string","description":"`modify` only: the order's size after the change, 1e18-scaled decimal."}}}}}}
```

## The OrderEntityV2 object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"OrderEntityV2":{"type":"object","description":"An order as admitted, in a `pod_orders_v2` frame: the facts that do not change. Its status is\n**not** here — that is implied by the events referencing it, which is what lets new event\nkinds be added without changing this object.\n\nOptional fields are omitted at their default rather than sent, so a plain user-signed limit\norder is small. Each omission means a specific thing, noted per field.\n","required":["id","tx","n","px","sz"],"properties":{"id":{"$ref":"#/components/schemas/Bytes32","description":"Resting order id, as used by cancel/update intents and the REST order APIs.\n\nDerived as `keccak256(abi_encode(signer, nonce, sequence))`, where `signer` is the key\nthat signed the transaction, `nonce` is that transaction's nonce (this entity's `n`), and\n`sequence` is the order's position inside a `submitBatch` envelope — `0` for a\nsingle-intent transaction. So you can compute the id yourself before broadcasting and\nmatch your own orders to this stream the first time it mentions them, without waiting on\na receipt.\n\n**For a delegated order, derive from the delegate's address, not the master's.** The id\nkeys on the signer so two delegates of one master cannot collide, whereas `a`/`accts`\nreport the *owner*. The two differ exactly when a delegate placed the order.\n"},"tx":{"$ref":"#/components/schemas/Bytes32","description":"Hash of the creating transaction, or of its parent `submitBatch` envelope. Zero for engine-generated orders."},"a":{"type":"integer","description":"Index into the frame's `accts`. Present if and only if `accts` is — see there."},"n":{"type":"integer","format":"int64","description":"Nonce of the **transaction** that created the order — the signing key's nonce, not a\nper-order counter. For a delegated order that is the *delegate's* nonce, not the\nmaster's.\n\nTwo orders from one `submitBatch` therefore share both `n` and `tx`, and differ only in\n`id`: `n` belongs to the envelope, not to the intents inside it. Use `id` to tell them\napart.\n"},"px":{"type":"string","description":"Limit price in quote/base units, 1e18-scaled, as a decimal string."},"sz":{"type":"string","description":"Signed order size, 1e18-scaled, decimal. Positive = buy/long, negative = sell/short — the sign carries the side, so there is no separate side field."},"end":{"type":"integer","format":"int64","description":"TTL expiry in microseconds. **Omitted means the order never expires** (rather than unknown)."},"kind":{"type":"string","enum":["liquidation","triggered","adl","adl_counterparty","backstop_transfer"],"description":"How the order came about. **Omitted means user-signed.**"},"type":{"type":"string","enum":["market"],"description":"**Omitted means a limit order.**"},"reduce_only":{"type":"boolean","description":"Omitted means false."},"ioc":{"type":"boolean","description":"Immediate-or-cancel. Omitted means false."},"trigger":{"type":"string","enum":["take_profit","stop_loss"],"description":"Which trigger produced this order. Omitted unless it is a fired trigger's synthetic."},"grouping":{"type":"string","enum":["asset"],"description":"Trigger grouping inherited from the parent trigger. Omitted when ungrouped."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."}}}}
```

## The OrderEventV2 object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"OrderEventV2":{"type":"object","description":"One transition in a `pod_orders_v2` frame, discriminated by `k`.\n\nEvery event names the order it concerns by exactly one of `o` (an index into this frame's\n`orders`) or `id` (an order resting from an earlier batch, whose owner is `a`). **Ignore\nvalues of `k` you do not recognise**: new kinds will be added without a new channel version.\n","required":["k"],"properties":{"k":{"type":"string","enum":["new","reject","fill","cancel","expire","modify","modify_reject"],"description":"- `new` — the order entered the book.\n- `reject` — dropped during execution, never rested; `why` carries the reason.\n- `fill` — matched, wholly or partly.\n- `cancel` — removed by a cancel intent or by the engine.\n- `expire` — removed on reaching its TTL.\n- `modify` — a resting order's price and/or size changed in place.\n- `modify_reject` — an amendment the engine refused. The order is untouched; `code` says why.\n"},"o":{"type":"integer","description":"Index into this frame's `orders`. Present when the order was created in this batch."},"id":{"$ref":"#/components/schemas/Bytes32","description":"Order id. Present instead of `o` when the order has been resting since an earlier batch."},"a":{"type":"integer","description":"Index into the frame's `accts`, accompanying `id`. Present if and only if `accts` is."},"why":{"type":"string","description":"On `reject`, why the engine dropped the order. On `modify_reject`, detail the `code`\ncannot carry — the amounts on `insufficient_balance`, `invalid_price` and\n`notional_below_minimum`, the pair on `unknown_market`, the whole reason on\n`unspecified`. Absent for every other code, where it would restate the code.\n"},"by":{"type":"integer","description":"`modify_reject` only: index into the frame's `accts` for the account that *asked*, which\nis deliberately not `a`. A refusal says nothing about who owns the order, and on\n`not_order_owner` the requester is precisely who does not. Absent when the subscription\nnames a single account.\n"},"req_px":{"type":"string","description":"`modify_reject` only: the price that was asked for, 1e18-scaled decimal. Echoed so a client with several amendments outstanding on one order can tell which this answers."},"req_sz":{"type":"string","description":"`modify_reject` only: the size that was asked for, 1e18-scaled decimal, unsigned."},"code":{"type":"string","enum":["insufficient_balance","invalid_price","zero_size","notional_below_minimum","unknown_market","order_not_found","not_order_owner","stale_nonce","wrong_pair","engine_managed_order","price_above_maximum","price_off_tick","market_order_must_be_ioc","size_above_maximum","size_off_lot","notional_overflow","notional_above_cap","unspecified"],"description":"`modify_reject` only: the stable reason identifier — branch on this, not on `why`.\nTreat a value you do not recognise as `unspecified`: the set grows as the engine names\nreasons, and `unspecified` itself means it has not named this one yet.\n"},"b":{"type":"string","description":"`fill` only. Base filled **by this fill**, 1e18-scaled decimal — this batch's amount, not a running total."},"q":{"type":"string","description":"`fill` only. Quote filled by this fill, 1e18-scaled decimal."},"tb":{"type":"string","description":"Total base filled over the order's life, 1e18-scaled decimal. On `fill`, the running\ntotal **so far**; on `cancel` and `expire`, the final total the order left the book with.\n\nOn a `fill` it is sent alongside `b` rather than instead of it: `b` is what you apply,\n`tb` is what you check your running figure against, so a divergence surfaces on the next\nfill instead of drifting. On a terminal event it is the settled figure, so you need no\naccumulation at all — see the terminal-totals rule on the method description.\n\nZero is sent rather than the field being omitted, so an order that never filled is\nreported as such rather than being indistinguishable from a field you failed to read.\n"},"tq":{"type":"string","description":"Total quote filled over the order's life, 1e18-scaled decimal. Running total on `fill`, final total on `cancel`/`expire`, as `tb`."},"tf":{"type":"string","description":"Total fee charged over the order's life, 1e18-scaled decimal. Running total on `fill`,\nfinal total on `cancel`/`expire`, as `tb`.\n\nThere is no per-fill fee counterpart — no such figure exists at this boundary to send. For\nthe fee attributable to one fill, subtract the previous `tf` seen for that order, or zero\non its first fill.\n"},"st":{"type":"string","enum":["filled","canceled","margin_canceled","expired"],"description":"`fill` only, and only on the fill that **closed** the order, carrying the status it closed with. Its absence means the order is still working."},"pa":{"type":"string","description":"`fill`: the owner's position after this fill, 1e18-scaled **signed** decimal.\n\nPresent when a fill moved a position — so absent on spot, which has none, and absent\non the two fills the engine fabricates without moving one (the backstop sweep, and the\nzero-size fill a cap-to-filled amendment emits to carry `st`). Do **not** read its\nabsence as \"spot\": take market type from the market. A client tracking positions treats\nan absent `pa` as unchanged, which it is.\nThe position *before* is not sent because it is derivable — `pa - sign(sz) * b`, the same\narithmetic the engine used to produce the pair — and the transition between the two is\nwhat says whether the fill opened, added to, reduced, closed or flipped the position. A\nraw position rather than a label so a client tracking positions off this stream can also\nassert its running figure against it, the way `tb`/`tq` anchor the amounts.\n"},"px":{"type":"string","description":"`modify` only: the order's price after the change, 1e18-scaled decimal."},"sz":{"type":"string","description":"`modify` only: the order's size after the change, 1e18-scaled decimal."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."}}}}
```

## The OrderUpdate object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"OrderUpdate":{"type":"object","description":"A single change to an order, pushed in the `pod_orders` notification array. It is a\n`type`-tagged union: the `type` field selects the variant and the remaining fields depend\non it.\n- `new` / `invalid`: the full `Order` fields are inlined alongside `type` (an `invalid`\n  order was rejected at execution and never entered the book; the reason is on its\n  `status`).\n- `expired` / `canceled`: only `type` and `order_id` are present.\n- `modified`: a resting order's price and/or size was changed in place by an `update`\n  intent — `type`, `order_id`, and the new `new_price` / `new_size` are present.\n- `fill`: the `OrderFillUpdate` fields are inlined alongside `type`.\n","required":["type"],"properties":{"type":{"type":"string","enum":["new","invalid","expired","canceled","modified","fill"],"description":"Discriminator selecting the variant."},"order_id":{"$ref":"#/components/schemas/Bytes32","description":"Present for `expired`, `canceled`, and `modified` — the affected order id."},"new_price":{"$ref":"#/components/schemas/HexUint256","description":"`modified` only: the order's price after the change (1e18)."},"new_size":{"$ref":"#/components/schemas/HexUint256","description":"`modified` only: the order's remaining base size after the change (1e18, unsigned magnitude — side is unchanged from the original `new`)."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"}}}}
```

## The OrderFillUpdate object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"OrderFillUpdate":{"type":"object","description":"A fill applied to a resting order in a settlement round, as carried by the `fill` variant of `OrderUpdate`.","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"order_id":{"$ref":"#/components/schemas/Bytes32","description":"Identifier of the filled order."},"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"Hash of the transaction that created the filled order."},"bidder":{"$ref":"#/components/schemas/Address","description":"Owner of the filled order. Use this to attribute the fill client-side."},"status":{"$ref":"#/components/schemas/OrderStatus","description":"Order status after this fill (`filled` or `active` if partially filled)."},"base_amount":{"$ref":"#/components/schemas/HexUint256","description":"Base tokens filled in this round (1e18)."},"quote_amount":{"$ref":"#/components/schemas/HexUint256","description":"Quote tokens filled in this round (1e18)."},"filled_base_amount":{"$ref":"#/components/schemas/HexUint256","description":"Cumulative base filled across all rounds (1e18)."},"filled_quote_amount":{"$ref":"#/components/schemas/HexUint256","description":"Cumulative quote filled across all rounds (1e18)."},"effective_price":{"$ref":"#/components/schemas/HexUint256","description":"Effective fill price so far (filled_quote / filled_base, 1e18)."},"fee":{"$ref":"#/components/schemas/HexUint256","description":"Cumulative fee for the order (1e18). Currently always zero."},"position_before":{"type":"string","nullable":true,"description":"Perp only — signed position (1e18) before the first fill on this order."},"position_after":{"type":"string","nullable":true,"description":"Perp only — signed position (1e18) after this fill."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"OrderStatus":{"type":"string","enum":["pending","active","filled","expired","canceled"],"description":"Current status of an order:\n- `pending`: Order submitted but not yet included in orderbook\n- `active`: Order is live in the orderbook\n- `filled`: Order completely filled\n- `expired`: Order expired (TTL exceeded)\n- `canceled`: Order was canceled by user\n"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"}}}}
```

## The PerpPositionSide object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"PerpPositionSide":{"type":"string","enum":["long","short"],"description":"Side of a perpetual position, derived from the sign of `size`."}}}}
```

## The SpotHolding object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"SpotHolding":{"type":"object","description":"A token balance with cost-basis tracking. One per token the wallet has touched on a spot market.","properties":{"kind":{"type":"string","enum":["spot"],"description":"Discriminator for the `Position` union."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"balance":{"$ref":"#/components/schemas/HexUint256","description":"Total base tokens held for this market (free + locked, 1e18)."},"free_balance":{"$ref":"#/components/schemas/HexUint256","description":"Spendable portion of `balance` after sell-side order locks (1e18)."},"locked_balance":{"$ref":"#/components/schemas/HexUint256","description":"Base tokens locked in open sell orders (`balance - free_balance`, 1e18)."},"cost_basis":{"$ref":"#/components/schemas/HexUint256","description":"Total quote spent to acquire `balance` (1e18 USD)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Last clearing price for this token's market (1e18)."},"unrealized_pnl":{"type":"string","description":"`(mark - avg_cost) × balance` (signed, 1e18 USD)."},"realized_pnl":{"type":"string","description":"Lifetime realized PnL on the user's spot trading (signed, 1e18 USD; portfolio-wide for v1)."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"}}}}
```

## The PerpPosition object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"PerpPosition":{"type":"object","description":"A leveraged perp position. One per (user, pair).","properties":{"kind":{"type":"string","enum":["perp"],"description":"Discriminator for the `Position` union."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"side":{"$ref":"#/components/schemas/PerpPositionSide"},"size":{"type":"string","description":"Signed position size in base units (1e18). Positive = long, negative = short."},"notional":{"$ref":"#/components/schemas/HexUint256","description":"`|size| × mark_price / 1e18` — dollar value of exposure (1e18)."},"entry_price":{"$ref":"#/components/schemas/HexUint256","description":"Volume-weighted average entry price; updated only on opening fills (1e18)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Latest mark price for the pair, post batch clearing (1e18)."},"margin":{"$ref":"#/components/schemas/HexUint256","description":"Allocated initial margin; cumulative across opens/increases, released proportionally on partial closes (1e18)."},"leverage":{"$ref":"#/components/schemas/HexUint256","description":"`notional × 1e18 / margin`. Effective leverage (0 if `margin` is 0)."},"funding_accrued":{"type":"string","description":"`(market.funding − position.entry_funding) × size` (signed, 1e18 USD)."},"liquidation_price":{"$ref":"#/components/schemas/HexUint256","description":"Mark price at which this position would be liquidated against its own `margin` and the market's maintenance-margin rate. Funding ignored. 0 when position is empty."},"unrealized_pnl":{"type":"string","description":"`((mark − entry) − (funding − entry_funding)) × size` (signed, 1e18 USD)."},"realized_pnl":{"type":"string","description":"Lifetime realized PnL on this position (signed, 1e18 USD). Resets to 0 when the position closes — the next open of the same pair starts fresh."},"stop_loss":{"$ref":"#/components/schemas/HexUint256","description":"Reserved — stop-loss not yet supported.","nullable":true},"take_profit":{"$ref":"#/components/schemas/HexUint256","description":"Reserved — take-profit not yet supported.","nullable":true}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"PerpPositionSide":{"type":"string","enum":["long","short"],"description":"Side of a perpetual position, derived from the sign of `size`."},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"}}}}
```

## The Position object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"Position":{"description":"Tagged union: a single entry in `PositionsResponse.positions`. The `kind` field selects between a `SpotHolding` (one per token) or a `PerpPosition` (one per pair).\n","oneOf":[{"$ref":"#/components/schemas/SpotHolding"},{"$ref":"#/components/schemas/PerpPosition"}],"discriminator":{"propertyName":"kind","mapping":{"spot":"#/components/schemas/SpotHolding","perp":"#/components/schemas/PerpPosition"}}},"SpotHolding":{"type":"object","description":"A token balance with cost-basis tracking. One per token the wallet has touched on a spot market.","properties":{"kind":{"type":"string","enum":["spot"],"description":"Discriminator for the `Position` union."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"balance":{"$ref":"#/components/schemas/HexUint256","description":"Total base tokens held for this market (free + locked, 1e18)."},"free_balance":{"$ref":"#/components/schemas/HexUint256","description":"Spendable portion of `balance` after sell-side order locks (1e18)."},"locked_balance":{"$ref":"#/components/schemas/HexUint256","description":"Base tokens locked in open sell orders (`balance - free_balance`, 1e18)."},"cost_basis":{"$ref":"#/components/schemas/HexUint256","description":"Total quote spent to acquire `balance` (1e18 USD)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Last clearing price for this token's market (1e18)."},"unrealized_pnl":{"type":"string","description":"`(mark - avg_cost) × balance` (signed, 1e18 USD)."},"realized_pnl":{"type":"string","description":"Lifetime realized PnL on the user's spot trading (signed, 1e18 USD; portfolio-wide for v1)."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"PerpPosition":{"type":"object","description":"A leveraged perp position. One per (user, pair).","properties":{"kind":{"type":"string","enum":["perp"],"description":"Discriminator for the `Position` union."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"side":{"$ref":"#/components/schemas/PerpPositionSide"},"size":{"type":"string","description":"Signed position size in base units (1e18). Positive = long, negative = short."},"notional":{"$ref":"#/components/schemas/HexUint256","description":"`|size| × mark_price / 1e18` — dollar value of exposure (1e18)."},"entry_price":{"$ref":"#/components/schemas/HexUint256","description":"Volume-weighted average entry price; updated only on opening fills (1e18)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Latest mark price for the pair, post batch clearing (1e18)."},"margin":{"$ref":"#/components/schemas/HexUint256","description":"Allocated initial margin; cumulative across opens/increases, released proportionally on partial closes (1e18)."},"leverage":{"$ref":"#/components/schemas/HexUint256","description":"`notional × 1e18 / margin`. Effective leverage (0 if `margin` is 0)."},"funding_accrued":{"type":"string","description":"`(market.funding − position.entry_funding) × size` (signed, 1e18 USD)."},"liquidation_price":{"$ref":"#/components/schemas/HexUint256","description":"Mark price at which this position would be liquidated against its own `margin` and the market's maintenance-margin rate. Funding ignored. 0 when position is empty."},"unrealized_pnl":{"type":"string","description":"`((mark − entry) − (funding − entry_funding)) × size` (signed, 1e18 USD)."},"realized_pnl":{"type":"string","description":"Lifetime realized PnL on this position (signed, 1e18 USD). Resets to 0 when the position closes — the next open of the same pair starts fresh."},"stop_loss":{"$ref":"#/components/schemas/HexUint256","description":"Reserved — stop-loss not yet supported.","nullable":true},"take_profit":{"$ref":"#/components/schemas/HexUint256","description":"Reserved — take-profit not yet supported.","nullable":true}}},"PerpPositionSide":{"type":"string","enum":["long","short"],"description":"Side of a perpetual position, derived from the sign of `size`."}}}}
```

## The PositionsResponse object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"PositionsResponse":{"type":"object","description":"Account positions across all orderbooks with aggregate PnL.","properties":{"positions":{"type":"array","items":{"$ref":"#/components/schemas/Position"},"description":"Heterogeneous list of spot holdings and open perp positions."},"total_unrealized_pnl":{"type":"string","description":"Sum of `unrealized_pnl` across every spot holding and perp position (signed, 1e18 USD)."},"total_realized_pnl":{"type":"string","description":"Lifetime portfolio-wide spot realized PnL plus the account-level perp realized-PnL counter. Both are cumulative across the account's history — closing a perp does not zero its contribution (signed, 1e18 USD).\n"},"perps_equity":{"type":"string","description":"Cash adjusted for unsettled funding plus unrealized PnL across all open perp positions. Excludes spot holdings (signed, 1e18 USD)."},"account_value":{"type":"string","description":"`perps_equity` plus the mark value of all spot holdings (signed, 1e18 USD)."},"cash":{"type":"string","description":"Deposited collateral adjusted for unsettled funding. Signed — can be negative if the account is underwater (1e18 USD)."},"withdrawable_cash":{"$ref":"#/components/schemas/HexUint256","description":"Free margin — `cash` minus the initial margin reserved by open positions (1e18 USD)."},"net_deposits":{"type":"string","description":"Net native collateral deposited minus withdrawn (signed, 1e18 USD). Negative once realized profit is withdrawn; lifetime PnL is `account_value − net_deposits`."}}},"Position":{"description":"Tagged union: a single entry in `PositionsResponse.positions`. The `kind` field selects between a `SpotHolding` (one per token) or a `PerpPosition` (one per pair).\n","oneOf":[{"$ref":"#/components/schemas/SpotHolding"},{"$ref":"#/components/schemas/PerpPosition"}],"discriminator":{"propertyName":"kind","mapping":{"spot":"#/components/schemas/SpotHolding","perp":"#/components/schemas/PerpPosition"}}},"SpotHolding":{"type":"object","description":"A token balance with cost-basis tracking. One per token the wallet has touched on a spot market.","properties":{"kind":{"type":"string","enum":["spot"],"description":"Discriminator for the `Position` union."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"balance":{"$ref":"#/components/schemas/HexUint256","description":"Total base tokens held for this market (free + locked, 1e18)."},"free_balance":{"$ref":"#/components/schemas/HexUint256","description":"Spendable portion of `balance` after sell-side order locks (1e18)."},"locked_balance":{"$ref":"#/components/schemas/HexUint256","description":"Base tokens locked in open sell orders (`balance - free_balance`, 1e18)."},"cost_basis":{"$ref":"#/components/schemas/HexUint256","description":"Total quote spent to acquire `balance` (1e18 USD)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Last clearing price for this token's market (1e18)."},"unrealized_pnl":{"type":"string","description":"`(mark - avg_cost) × balance` (signed, 1e18 USD)."},"realized_pnl":{"type":"string","description":"Lifetime realized PnL on the user's spot trading (signed, 1e18 USD; portfolio-wide for v1)."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"PerpPosition":{"type":"object","description":"A leveraged perp position. One per (user, pair).","properties":{"kind":{"type":"string","enum":["perp"],"description":"Discriminator for the `Position` union."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"side":{"$ref":"#/components/schemas/PerpPositionSide"},"size":{"type":"string","description":"Signed position size in base units (1e18). Positive = long, negative = short."},"notional":{"$ref":"#/components/schemas/HexUint256","description":"`|size| × mark_price / 1e18` — dollar value of exposure (1e18)."},"entry_price":{"$ref":"#/components/schemas/HexUint256","description":"Volume-weighted average entry price; updated only on opening fills (1e18)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Latest mark price for the pair, post batch clearing (1e18)."},"margin":{"$ref":"#/components/schemas/HexUint256","description":"Allocated initial margin; cumulative across opens/increases, released proportionally on partial closes (1e18)."},"leverage":{"$ref":"#/components/schemas/HexUint256","description":"`notional × 1e18 / margin`. Effective leverage (0 if `margin` is 0)."},"funding_accrued":{"type":"string","description":"`(market.funding − position.entry_funding) × size` (signed, 1e18 USD)."},"liquidation_price":{"$ref":"#/components/schemas/HexUint256","description":"Mark price at which this position would be liquidated against its own `margin` and the market's maintenance-margin rate. Funding ignored. 0 when position is empty."},"unrealized_pnl":{"type":"string","description":"`((mark − entry) − (funding − entry_funding)) × size` (signed, 1e18 USD)."},"realized_pnl":{"type":"string","description":"Lifetime realized PnL on this position (signed, 1e18 USD). Resets to 0 when the position closes — the next open of the same pair starts fresh."},"stop_loss":{"$ref":"#/components/schemas/HexUint256","description":"Reserved — stop-loss not yet supported.","nullable":true},"take_profit":{"$ref":"#/components/schemas/HexUint256","description":"Reserved — take-profit not yet supported.","nullable":true}}},"PerpPositionSide":{"type":"string","enum":["long","short"],"description":"Side of a perpetual position, derived from the sign of `size`."}}}}
```

## The Secp256k1PublicKey object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"Secp256k1PublicKey":{"type":"string","pattern":"^[0-9a-fA-F]{66}$","description":"A 33-byte compressed secp256k1 public key, lowercase hex, with **no** `0x` prefix (66 hex characters)."}}}}
```

## The VoterResponse object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"VoterResponse":{"type":"object","description":"A validator that cast a vote, resolved from the committee vote bitmap.","required":["validator_index","validator_address"],"properties":{"validator_index":{"type":"integer","description":"Index of the validator within the committee."},"validator_address":{"$ref":"#/components/schemas/Address"}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"}}}}
```

## The TxVotesResponse object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"TxVotesResponse":{"type":"object","description":"The set of validators that voted for one specific transaction hash at a given (account, nonce).","required":["tx_hash","voters"],"properties":{"tx_hash":{"$ref":"#/components/schemas/Bytes32"},"voters":{"type":"array","items":{"$ref":"#/components/schemas/VoterResponse"}}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"VoterResponse":{"type":"object","description":"A validator that cast a vote, resolved from the committee vote bitmap.","required":["validator_index","validator_address"],"properties":{"validator_index":{"type":"integer","description":"Index of the validator within the committee."},"validator_address":{"$ref":"#/components/schemas/Address"}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"}}}}
```

## The AccountNonceVotesResponse object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"AccountNonceVotesResponse":{"type":"object","description":"Votes observed for a given (account, nonce), as tracked by this node's vote accounting. Returned by `pod_getVotes` and embedded in a pending `pod_getTxStatus`.","required":["account","nonce","txs","bot_voters","total_tx_votes","quorum"],"properties":{"account":{"$ref":"#/components/schemas/Address"},"nonce":{"type":"integer","format":"int64"},"txs":{"type":"array","items":{"$ref":"#/components/schemas/TxVotesResponse"},"description":"Voter sets per transaction hash seen at this (account, nonce)."},"bot_voters":{"type":"array","items":{"$ref":"#/components/schemas/VoterResponse"},"description":"Validators that voted BOT (bottom / no-op) at this (account, nonce)."},"total_tx_votes":{"type":"integer","description":"Distinct validators that voted for any tx (each counted once even when equivocating)."},"quorum":{"type":"integer","description":"Votes required for a certificate (n − f)."}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"TxVotesResponse":{"type":"object","description":"The set of validators that voted for one specific transaction hash at a given (account, nonce).","required":["tx_hash","voters"],"properties":{"tx_hash":{"$ref":"#/components/schemas/Bytes32"},"voters":{"type":"array","items":{"$ref":"#/components/schemas/VoterResponse"}}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"VoterResponse":{"type":"object","description":"A validator that cast a vote, resolved from the committee vote bitmap.","required":["validator_index","validator_address"],"properties":{"validator_index":{"type":"integer","description":"Index of the validator within the committee."},"validator_address":{"$ref":"#/components/schemas/Address"}}}}}}
```

## The ProcessedDepositsResponse object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"ProcessedDepositsResponse":{"type":"object","description":"The bridge deposit replay-protection set. Every deposit id strictly below `watermark` has\nbeen processed; `above_watermark` lists the processed ids at or above it. The relayer uses\nthis to drop already-processed deposits from a batch before (re)submitting it.\n","required":["watermark","above_watermark"],"properties":{"watermark":{"$ref":"#/components/schemas/HexUint256"},"above_watermark":{"type":"array","items":{"$ref":"#/components/schemas/HexUint256"},"description":"Processed deposit ids `>= watermark`, sorted ascending."}}},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"}}}}
```

## The TargetTx object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"TargetTx":{"type":"object","description":"A transaction an account must recover past before it can make progress again.","required":["hash","nonce"],"properties":{"hash":{"$ref":"#/components/schemas/Bytes32"},"nonce":{"type":"integer","format":"int64"}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."}}}}
```

## The AccountInfoResponse object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"AccountInfoResponse":{"type":"object","description":"An account's finalized/expected nonces and last finalized tx, as this node sees them.","required":["next_finalized_nonce","expected_nonce","last_finalized_tx"],"properties":{"next_finalized_nonce":{"type":"integer","format":"int64","description":"The next nonce to finalize; every lower nonce is already finalized."},"expected_nonce":{"type":"integer","format":"int64","description":"The next nonce the account is expected to submit."},"last_finalized_tx":{"$ref":"#/components/schemas/Bytes32"}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."}}}}
```

## The Precompile object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"Precompile":{"type":"object","description":"An enshrined precompile contract (bridge, CLOB, recovery, ...).","required":["address","name"],"properties":{"address":{"$ref":"#/components/schemas/Address"},"name":{"type":"string"}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"}}}}
```

## The PrecompileInfo object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"PrecompileInfo":{"type":"object","description":"A precompile plus its callable interface. The `Precompile` fields (`address`, `name`) are flattened to the top level alongside `interface`.","required":["address","name","interface"],"properties":{"address":{"$ref":"#/components/schemas/Address"},"name":{"type":"string"},"interface":{"type":"string","description":"The precompile's callable interface (human-readable descriptor)."}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"}}}}
```

## The SolverBatchInfo object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"SolverBatchInfo":{"type":"object","description":"Identifies a solver solution batch by its auction deadline and transaction hash.","required":["deadline","tx_hash"],"properties":{"deadline":{"$ref":"#/components/schemas/Timestamp"},"tx_hash":{"$ref":"#/components/schemas/Bytes32"}}},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."}}}}
```

## The SolverStateResponse object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"SolverStateResponse":{"type":"object","description":"The solver node's current state. Only meaningful when queried against the solver node.","required":["solver_address","solver_pub_key","next_finalized_nonce","next_solution_votes"],"properties":{"solver_address":{"$ref":"#/components/schemas/Address"},"solver_pub_key":{"$ref":"#/components/schemas/Secp256k1PublicKey"},"next_finalized_nonce":{"type":"integer","format":"int64"},"last_executed_batch":{"$ref":"#/components/schemas/SolverBatchInfo","nullable":true,"description":"The most recently executed solution batch, or null if none."},"last_generated_batch":{"$ref":"#/components/schemas/SolverBatchInfo","nullable":true,"description":"The most recently generated (proposed) solution batch, or null if none."},"next_solution_votes":{"type":"object","additionalProperties":{"type":"array","items":{"type":"integer"}},"description":"Votes for the next solution: an object mapping each candidate solution tx hash (bytes32, hex string key) to the list of validator indices that voted for it."}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"Secp256k1PublicKey":{"type":"string","pattern":"^[0-9a-fA-F]{66}$","description":"A 33-byte compressed secp256k1 public key, lowercase hex, with **no** `0x` prefix (66 hex characters)."},"SolverBatchInfo":{"type":"object","description":"Identifies a solver solution batch by its auction deadline and transaction hash.","required":["deadline","tx_hash"],"properties":{"deadline":{"$ref":"#/components/schemas/Timestamp"},"tx_hash":{"$ref":"#/components/schemas/Bytes32"}}},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."}}}}
```

## The PodStatus object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"PodStatus":{"type":"object","description":"Operational status of the node.","required":["read_only"],"properties":{"read_only":{"type":"boolean","description":"When true, the node rejects `sendRawTransaction` submissions (both `eth_` and `pod_`)."}}}}}}
```

## The ValidatorVoteKind object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"ValidatorVoteKind":{"type":"object","description":"A validator's vote at a single nonce. Tagged union on `kind`:\n- `tx`: voted for a specific transaction hash — `tx_hash` is present.\n- `bot`: cast a BOT (bottom / no-op) vote — only `kind` is present.\n- `not_seen`: no vote observed from this validator at this nonce — only `kind` is present.\n","required":["kind"],"properties":{"kind":{"type":"string","enum":["tx","bot","not_seen"]},"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"Present only when `kind` is `tx`."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."}}}}
```

## The ValidatorNonceVote object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"ValidatorNonceVote":{"type":"object","description":"A single validator's vote at one pending nonce.","required":["nonce","vote"],"properties":{"nonce":{"type":"integer","format":"int64"},"vote":{"$ref":"#/components/schemas/ValidatorVoteKind"}}},"ValidatorVoteKind":{"type":"object","description":"A validator's vote at a single nonce. Tagged union on `kind`:\n- `tx`: voted for a specific transaction hash — `tx_hash` is present.\n- `bot`: cast a BOT (bottom / no-op) vote — only `kind` is present.\n- `not_seen`: no vote observed from this validator at this nonce — only `kind` is present.\n","required":["kind"],"properties":{"kind":{"type":"string","enum":["tx","bot","not_seen"]},"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"Present only when `kind` is `tx`."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."}}}}
```

## The ValidatorAccountStatusResponse object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"ValidatorAccountStatusResponse":{"type":"object","description":"How one validator has voted for one account across its pending nonces, as seen by this node.","required":["validator_index","validator_address","account","account_next_finalized_nonce","account_expected_nonce","quorum","pending_nonces"],"properties":{"validator_index":{"type":"integer"},"validator_address":{"$ref":"#/components/schemas/Address"},"account":{"$ref":"#/components/schemas/Address"},"account_next_finalized_nonce":{"type":"integer","format":"int64","description":"This node's `next_finalized_nonce` for the account (votes at lower nonces are already gone)."},"account_expected_nonce":{"type":"integer","format":"int64","description":"This node's `expected_nonce` for the account."},"quorum":{"type":"integer","description":"Votes required for a certificate (n − f)."},"pending_nonces":{"type":"array","items":{"$ref":"#/components/schemas/ValidatorNonceVote"},"description":"One entry per pending nonce in `[next_finalized_nonce, expected_nonce)`. Capped at 256 entries; if the gap is larger the oldest nonces are omitted."}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"ValidatorNonceVote":{"type":"object","description":"A single validator's vote at one pending nonce.","required":["nonce","vote"],"properties":{"nonce":{"type":"integer","format":"int64"},"vote":{"$ref":"#/components/schemas/ValidatorVoteKind"}}},"ValidatorVoteKind":{"type":"object","description":"A validator's vote at a single nonce. Tagged union on `kind`:\n- `tx`: voted for a specific transaction hash — `tx_hash` is present.\n- `bot`: cast a BOT (bottom / no-op) vote — only `kind` is present.\n- `not_seen`: no vote observed from this validator at this nonce — only `kind` is present.\n","required":["kind"],"properties":{"kind":{"type":"string","enum":["tx","bot","not_seen"]},"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"Present only when `kind` is `tx`."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."}}}}
```

## The FinalizedTxStatus object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"FinalizedTxStatus":{"type":"object","description":"Execution outcome of a finalized transaction. In `pod_getTxStatus` these fields are flattened alongside the `finalized` status tag.","required":["tx_hash","account","nonce","success","gas_used"],"properties":{"tx_hash":{"$ref":"#/components/schemas/Bytes32"},"account":{"$ref":"#/components/schemas/Address"},"nonce":{"type":"integer","format":"int64"},"success":{"type":"boolean"},"gas_used":{"type":"integer","format":"int64"}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"}}}}
```

## The PendingTxStatus object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"PendingTxStatus":{"type":"object","description":"In-flight status of a not-yet-finalized transaction. In `pod_getTxStatus` these fields are flattened alongside the `pending` status tag.","required":["tx_hash","account","nonce","account_next_finalized_nonce","account_expected_nonce","quorum","votes"],"properties":{"tx_hash":{"$ref":"#/components/schemas/Bytes32"},"account":{"$ref":"#/components/schemas/Address"},"nonce":{"type":"integer","format":"int64"},"account_next_finalized_nonce":{"type":"integer","format":"int64"},"account_expected_nonce":{"type":"integer","format":"int64"},"quorum":{"type":"integer","description":"Votes needed for a certificate (n − f)."},"votes":{"$ref":"#/components/schemas/AccountNonceVotesResponse"}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"AccountNonceVotesResponse":{"type":"object","description":"Votes observed for a given (account, nonce), as tracked by this node's vote accounting. Returned by `pod_getVotes` and embedded in a pending `pod_getTxStatus`.","required":["account","nonce","txs","bot_voters","total_tx_votes","quorum"],"properties":{"account":{"$ref":"#/components/schemas/Address"},"nonce":{"type":"integer","format":"int64"},"txs":{"type":"array","items":{"$ref":"#/components/schemas/TxVotesResponse"},"description":"Voter sets per transaction hash seen at this (account, nonce)."},"bot_voters":{"type":"array","items":{"$ref":"#/components/schemas/VoterResponse"},"description":"Validators that voted BOT (bottom / no-op) at this (account, nonce)."},"total_tx_votes":{"type":"integer","description":"Distinct validators that voted for any tx (each counted once even when equivocating)."},"quorum":{"type":"integer","description":"Votes required for a certificate (n − f)."}}},"TxVotesResponse":{"type":"object","description":"The set of validators that voted for one specific transaction hash at a given (account, nonce).","required":["tx_hash","voters"],"properties":{"tx_hash":{"$ref":"#/components/schemas/Bytes32"},"voters":{"type":"array","items":{"$ref":"#/components/schemas/VoterResponse"}}}},"VoterResponse":{"type":"object","description":"A validator that cast a vote, resolved from the committee vote bitmap.","required":["validator_index","validator_address"],"properties":{"validator_index":{"type":"integer","description":"Index of the validator within the committee."},"validator_address":{"$ref":"#/components/schemas/Address"}}}}}}
```

## The TxStatusResponse object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"TxStatusResponse":{"type":"object","description":"Full pipeline status of a transaction, returned by `pod_getTxStatus`. It is a `status`-tagged\nunion; the fields present depend on `status`:\n- `not_found`: unknown to this node (no cached tx and no receipt) — only `status` is present.\n- `pending`: in-flight — the `PendingTxStatus` fields are inlined alongside `status`.\n- `finalized`: executed — the `FinalizedTxStatus` fields are inlined alongside `status`.\n","required":["status"],"properties":{"status":{"type":"string","enum":["not_found","pending","finalized"],"description":"Discriminator selecting the variant."},"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"Present for `pending` and `finalized`."},"account":{"$ref":"#/components/schemas/Address","description":"Present for `pending` and `finalized`."},"nonce":{"type":"integer","format":"int64","description":"Present for `pending` and `finalized`."},"account_next_finalized_nonce":{"type":"integer","format":"int64","description":"`pending` only."},"account_expected_nonce":{"type":"integer","format":"int64","description":"`pending` only."},"quorum":{"type":"integer","description":"`pending` only: votes needed for a certificate (n − f)."},"votes":{"$ref":"#/components/schemas/AccountNonceVotesResponse","description":"`pending` only: the votes observed at this (account, nonce)."},"success":{"type":"boolean","description":"`finalized` only: whether execution succeeded."},"gas_used":{"type":"integer","format":"int64","description":"`finalized` only."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"AccountNonceVotesResponse":{"type":"object","description":"Votes observed for a given (account, nonce), as tracked by this node's vote accounting. Returned by `pod_getVotes` and embedded in a pending `pod_getTxStatus`.","required":["account","nonce","txs","bot_voters","total_tx_votes","quorum"],"properties":{"account":{"$ref":"#/components/schemas/Address"},"nonce":{"type":"integer","format":"int64"},"txs":{"type":"array","items":{"$ref":"#/components/schemas/TxVotesResponse"},"description":"Voter sets per transaction hash seen at this (account, nonce)."},"bot_voters":{"type":"array","items":{"$ref":"#/components/schemas/VoterResponse"},"description":"Validators that voted BOT (bottom / no-op) at this (account, nonce)."},"total_tx_votes":{"type":"integer","description":"Distinct validators that voted for any tx (each counted once even when equivocating)."},"quorum":{"type":"integer","description":"Votes required for a certificate (n − f)."}}},"TxVotesResponse":{"type":"object","description":"The set of validators that voted for one specific transaction hash at a given (account, nonce).","required":["tx_hash","voters"],"properties":{"tx_hash":{"$ref":"#/components/schemas/Bytes32"},"voters":{"type":"array","items":{"$ref":"#/components/schemas/VoterResponse"}}}},"VoterResponse":{"type":"object","description":"A validator that cast a vote, resolved from the committee vote bitmap.","required":["validator_index","validator_address"],"properties":{"validator_index":{"type":"integer","description":"Index of the validator within the committee."},"validator_address":{"$ref":"#/components/schemas/Address"}}}}}}
```

## The ValidatorStatusResponse object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"ValidatorStatusResponse":{"type":"object","description":"This node's own in-memory validator state. `validator_index` / `validator_address` are\npresent on a validator node and null on a full node. Values reflect the queried node's local\nstate, not a consensus view.\n","required":["append_log_sequence","current_ppt","quorum","committee_size"],"properties":{"validator_index":{"type":"integer","nullable":true},"validator_address":{"$ref":"#/components/schemas/Address","nullable":true},"append_log_sequence":{"type":"integer","format":"int64","description":"The node's current append-log sequence number."},"current_ppt":{"$ref":"#/components/schemas/Timestamp","description":"This node's local past-perfect time (microseconds)."},"last_executed_batch":{"$ref":"#/components/schemas/Timestamp","nullable":true,"description":"Deadline of the last executed solution batch (microseconds), or null if none."},"next_solution_deadline":{"$ref":"#/components/schemas/Timestamp","nullable":true,"description":"`last_executed_batch + auction_interval`, or null if no batch has executed yet."},"quorum":{"type":"integer","description":"Votes required for a certificate (n − f)."},"committee_size":{"type":"integer"}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```

## The ValidatorDiagnostics object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"ValidatorDiagnostics":{"type":"object","description":"Per-validator vote state for a single account, as seen by the queried node. Part of `AccountDiagnosticsResponse`.","required":["validator_index","validator_address","current_vote","equivocating"],"properties":{"validator_index":{"type":"integer"},"validator_address":{"$ref":"#/components/schemas/Address"},"highest_attested_nonce":{"type":"integer","format":"int64","nullable":true,"description":"Highest nonce in the current pending window where this validator has voted. Null when there are no pending nonces or the validator has not voted."},"current_vote":{"$ref":"#/components/schemas/ValidatorVoteKind","description":"Vote cast at the latest pending nonce (`expected_nonce − 1`); `not_seen` if none."},"equivocating":{"type":"boolean","description":"True if this validator voted for two different tx hashes at the same nonce."}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"ValidatorVoteKind":{"type":"object","description":"A validator's vote at a single nonce. Tagged union on `kind`:\n- `tx`: voted for a specific transaction hash — `tx_hash` is present.\n- `bot`: cast a BOT (bottom / no-op) vote — only `kind` is present.\n- `not_seen`: no vote observed from this validator at this nonce — only `kind` is present.\n","required":["kind"],"properties":{"kind":{"type":"string","enum":["tx","bot","not_seen"]},"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"Present only when `kind` is `tx`."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."}}}}
```

## The AccountDiagnosticsResponse object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"AccountDiagnosticsResponse":{"type":"object","description":"Full diagnostic snapshot of a single account across all committee validators, returned by `pod_getAccountDiagnostics`.","required":["account","next_finalized_nonce","expected_nonce","last_finalized_tx","is_locked","quorum","validators","needs_recovery","has_clob_order_pending_solution","equivocating"],"properties":{"account":{"$ref":"#/components/schemas/Address"},"next_finalized_nonce":{"type":"integer","format":"int64"},"expected_nonce":{"type":"integer","format":"int64"},"last_finalized_tx":{"$ref":"#/components/schemas/Bytes32"},"is_locked":{"type":"boolean","description":"True when the account is locked (a tx is pending decision)."},"quorum":{"type":"integer","description":"Votes required for a certificate (n − f)."},"validators":{"type":"array","items":{"$ref":"#/components/schemas/ValidatorDiagnostics"},"description":"Per-validator vote state."},"needs_recovery":{"type":"boolean"},"recovery_target":{"$ref":"#/components/schemas/TargetTx","nullable":true,"description":"The tx the account needs to recover past, if any."},"has_clob_order_pending_solution":{"type":"boolean","description":"True if this account has at least one order in the CLOB's pending-solution window."},"equivocating":{"type":"boolean","description":"True if two competing tx hashes at the same nonce both reached the certificate threshold (n − 3f)."}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"ValidatorDiagnostics":{"type":"object","description":"Per-validator vote state for a single account, as seen by the queried node. Part of `AccountDiagnosticsResponse`.","required":["validator_index","validator_address","current_vote","equivocating"],"properties":{"validator_index":{"type":"integer"},"validator_address":{"$ref":"#/components/schemas/Address"},"highest_attested_nonce":{"type":"integer","format":"int64","nullable":true,"description":"Highest nonce in the current pending window where this validator has voted. Null when there are no pending nonces or the validator has not voted."},"current_vote":{"$ref":"#/components/schemas/ValidatorVoteKind","description":"Vote cast at the latest pending nonce (`expected_nonce − 1`); `not_seen` if none."},"equivocating":{"type":"boolean","description":"True if this validator voted for two different tx hashes at the same nonce."}}},"ValidatorVoteKind":{"type":"object","description":"A validator's vote at a single nonce. Tagged union on `kind`:\n- `tx`: voted for a specific transaction hash — `tx_hash` is present.\n- `bot`: cast a BOT (bottom / no-op) vote — only `kind` is present.\n- `not_seen`: no vote observed from this validator at this nonce — only `kind` is present.\n","required":["kind"],"properties":{"kind":{"type":"string","enum":["tx","bot","not_seen"]},"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"Present only when `kind` is `tx`."}}},"TargetTx":{"type":"object","description":"A transaction an account must recover past before it can make progress again.","required":["hash","nonce"],"properties":{"hash":{"$ref":"#/components/schemas/Bytes32"},"nonce":{"type":"integer","format":"int64"}}}}}}
```

## The MarketDynamicEntry object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"MarketDynamicEntry":{"type":"object","description":"Live market statistics for one orderbook, streamed on the `pod_markets` subscription (one\nobject per orderbook). Optional fields are omitted (not null) when unset — e.g. perp-only\nfields on a spot market, or stats with no data yet.\n","required":["orderbook_id","volume_24h"],"properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"last_clearing_price":{"type":"string","description":"Most recent clearing price (decimal, 1e18). Omitted if the market has not cleared."},"volume_24h":{"type":"string","description":"Rolling 24h traded volume (decimal, 1e18)."},"high_24h":{"type":"string","description":"24h high clearing price (decimal, 1e18). Omitted if unavailable."},"low_24h":{"type":"string","description":"24h low clearing price (decimal, 1e18). Omitted if unavailable."},"price_change_24h":{"type":"integer","format":"int128","description":"24h price change (signed, 1e18), as a JSON number. Omitted if unavailable."},"oracle_price":{"type":"string","description":"Perp only: latest oracle price (decimal, 1e18)."},"mark_price":{"type":"string","description":"Perp only: current mark price (decimal, 1e18)."},"funding_rate":{"type":"string","description":"Perp only: current funding rate (decimal)."},"funding_index":{"type":"string","description":"Perp only: cumulative funding index (decimal)."},"funding_last_updated_us":{"type":"integer","format":"int64","description":"Perp only: last funding update time (microseconds)."},"open_interest":{"type":"string","description":"Perp only: open interest (decimal, 1e18)."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."}}}}
```

## The CandleTick object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"CandleTick":{"type":"object","description":"Per-tick candle hint streamed on the `pod_candles` subscription — one object per orderbook\ncleared this settlement. It is not a closed OHLCV bar (use `ob_getCandles` for those); the\nclient folds it into the forming bar.\n","required":["orderbook","timestamp_us","price","volume"],"properties":{"orderbook":{"$ref":"#/components/schemas/Bytes32"},"timestamp_us":{"type":"integer","format":"int64","description":"Batch deadline (settlement time) in microseconds."},"price":{"type":"string","description":"Clearing price for this tick (decimal, 1e18)."},"volume":{"type":"string","description":"Total volume cleared this tick (decimal, 1e18)."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."}}}}
```

## The PositionsUpdate object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"PositionsUpdate":{"type":"object","description":"A `pod_positions` notification — the account's full positions snapshot, pushed for a settlement that touched the account.","required":["account","data"],"properties":{"account":{"$ref":"#/components/schemas/Address"},"data":{"$ref":"#/components/schemas/PositionsResponse"}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"PositionsResponse":{"type":"object","description":"Account positions across all orderbooks with aggregate PnL.","properties":{"positions":{"type":"array","items":{"$ref":"#/components/schemas/Position"},"description":"Heterogeneous list of spot holdings and open perp positions."},"total_unrealized_pnl":{"type":"string","description":"Sum of `unrealized_pnl` across every spot holding and perp position (signed, 1e18 USD)."},"total_realized_pnl":{"type":"string","description":"Lifetime portfolio-wide spot realized PnL plus the account-level perp realized-PnL counter. Both are cumulative across the account's history — closing a perp does not zero its contribution (signed, 1e18 USD).\n"},"perps_equity":{"type":"string","description":"Cash adjusted for unsettled funding plus unrealized PnL across all open perp positions. Excludes spot holdings (signed, 1e18 USD)."},"account_value":{"type":"string","description":"`perps_equity` plus the mark value of all spot holdings (signed, 1e18 USD)."},"cash":{"type":"string","description":"Deposited collateral adjusted for unsettled funding. Signed — can be negative if the account is underwater (1e18 USD)."},"withdrawable_cash":{"$ref":"#/components/schemas/HexUint256","description":"Free margin — `cash` minus the initial margin reserved by open positions (1e18 USD)."},"net_deposits":{"type":"string","description":"Net native collateral deposited minus withdrawn (signed, 1e18 USD). Negative once realized profit is withdrawn; lifetime PnL is `account_value − net_deposits`."}}},"Position":{"description":"Tagged union: a single entry in `PositionsResponse.positions`. The `kind` field selects between a `SpotHolding` (one per token) or a `PerpPosition` (one per pair).\n","oneOf":[{"$ref":"#/components/schemas/SpotHolding"},{"$ref":"#/components/schemas/PerpPosition"}],"discriminator":{"propertyName":"kind","mapping":{"spot":"#/components/schemas/SpotHolding","perp":"#/components/schemas/PerpPosition"}}},"SpotHolding":{"type":"object","description":"A token balance with cost-basis tracking. One per token the wallet has touched on a spot market.","properties":{"kind":{"type":"string","enum":["spot"],"description":"Discriminator for the `Position` union."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"balance":{"$ref":"#/components/schemas/HexUint256","description":"Total base tokens held for this market (free + locked, 1e18)."},"free_balance":{"$ref":"#/components/schemas/HexUint256","description":"Spendable portion of `balance` after sell-side order locks (1e18)."},"locked_balance":{"$ref":"#/components/schemas/HexUint256","description":"Base tokens locked in open sell orders (`balance - free_balance`, 1e18)."},"cost_basis":{"$ref":"#/components/schemas/HexUint256","description":"Total quote spent to acquire `balance` (1e18 USD)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Last clearing price for this token's market (1e18)."},"unrealized_pnl":{"type":"string","description":"`(mark - avg_cost) × balance` (signed, 1e18 USD)."},"realized_pnl":{"type":"string","description":"Lifetime realized PnL on the user's spot trading (signed, 1e18 USD; portfolio-wide for v1)."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"PerpPosition":{"type":"object","description":"A leveraged perp position. One per (user, pair).","properties":{"kind":{"type":"string","enum":["perp"],"description":"Discriminator for the `Position` union."},"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"side":{"$ref":"#/components/schemas/PerpPositionSide"},"size":{"type":"string","description":"Signed position size in base units (1e18). Positive = long, negative = short."},"notional":{"$ref":"#/components/schemas/HexUint256","description":"`|size| × mark_price / 1e18` — dollar value of exposure (1e18)."},"entry_price":{"$ref":"#/components/schemas/HexUint256","description":"Volume-weighted average entry price; updated only on opening fills (1e18)."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Latest mark price for the pair, post batch clearing (1e18)."},"margin":{"$ref":"#/components/schemas/HexUint256","description":"Allocated initial margin; cumulative across opens/increases, released proportionally on partial closes (1e18)."},"leverage":{"$ref":"#/components/schemas/HexUint256","description":"`notional × 1e18 / margin`. Effective leverage (0 if `margin` is 0)."},"funding_accrued":{"type":"string","description":"`(market.funding − position.entry_funding) × size` (signed, 1e18 USD)."},"liquidation_price":{"$ref":"#/components/schemas/HexUint256","description":"Mark price at which this position would be liquidated against its own `margin` and the market's maintenance-margin rate. Funding ignored. 0 when position is empty."},"unrealized_pnl":{"type":"string","description":"`((mark − entry) − (funding − entry_funding)) × size` (signed, 1e18 USD)."},"realized_pnl":{"type":"string","description":"Lifetime realized PnL on this position (signed, 1e18 USD). Resets to 0 when the position closes — the next open of the same pair starts fresh."},"stop_loss":{"$ref":"#/components/schemas/HexUint256","description":"Reserved — stop-loss not yet supported.","nullable":true},"take_profit":{"$ref":"#/components/schemas/HexUint256","description":"Reserved — take-profit not yet supported.","nullable":true}}},"PerpPositionSide":{"type":"string","enum":["long","short"],"description":"Side of a perpetual position, derived from the sign of `size`."}}}}
```

## The TriggersUpdate object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"TriggersUpdate":{"type":"object","description":"A `pod_triggers` notification — the account's armed TP/SL triggers, pushed for a settlement that touched the account. Carries the `GetTriggersResponse` fields inlined alongside `account`.","required":["account","triggers","total_count"],"properties":{"account":{"$ref":"#/components/schemas/Address"},"triggers":{"type":"array","items":{"$ref":"#/components/schemas/TriggerOrderResponse"}},"total_count":{"type":"integer","description":"Count of triggers for the account before pagination."},"next_cursor":{"type":"string","nullable":true,"description":"Pagination cursor, wire format `\"{orderbook_id}:{order_id}\"`. Null if no more results."}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address (20 bytes, hex-encoded with 0x prefix)"},"TriggerOrderResponse":{"type":"object","description":"An armed TP/SL trigger order, as returned by `ob_getTriggers`.","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"order_id":{"$ref":"#/components/schemas/Bytes32","description":"Identifier of the trigger (and of the synthetic order it produces when it fires)."},"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"Hash of the `submitTrigger` transaction that armed this trigger."},"bidder":{"$ref":"#/components/schemas/Address"},"nonce":{"type":"integer","format":"int64"},"size":{"type":"string","description":"Signed size of the synthetic order produced when the trigger fires (decimal int256). Positive = buy/long, negative = sell/short."},"limit_price":{"$ref":"#/components/schemas/HexUint256","description":"Limit price of the synthetic order produced when the trigger fires (1e18)."},"trigger_price":{"$ref":"#/components/schemas/HexUint256","description":"Mark-price threshold that arms the trigger (1e18)."},"trigger_type":{"$ref":"#/components/schemas/TriggerType"},"grouping":{"$ref":"#/components/schemas/TriggerGrouping"},"reduce_only":{"type":"boolean"},"ioc":{"type":"boolean","description":"Immediate-or-cancel — any unfilled remainder of the fired order is canceled at end of batch."},"deadline":{"$ref":"#/components/schemas/Timestamp"},"end":{"$ref":"#/components/schemas/Timestamp","description":"TTL expiry — the trigger is swept once `end < batch_deadline` (microseconds)."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value (hex-encoded with 0x prefix). Used for transaction hashes, orderbook IDs, etc."},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"TriggerType":{"type":"string","enum":["take_profit","stop_loss"],"description":"Type of a TP/SL trigger order on a perp market:\n- `take_profit`: fires when the mark price moves favorably across `trigger_price`\n- `stop_loss`: fires when the mark price moves adversely across `trigger_price`\n\nAlso set on a synthetic order (`kind = triggered`) that a fired trigger produced.\n"},"TriggerGrouping":{"type":"string","enum":["none","asset","position"],"description":"Whether a trigger (and any synthetic order it produces) is bound to the bidder's exposure on the pair:\n- `none`: standalone — the trigger is removed only by a user cancel, TTL expiry, or its own fire; any synthetic order it produced survives independently\n- `asset`: exposure-bound — on perp markets the venue removes the armed trigger *and* any resting synthetic order it produced once the bidder's position on the pair reaches size 0; on spot markets, once the bidder's base-asset holdings reach 0\n\n`asset` was formerly named `position` (same semantics, same ABI value); nodes running older builds still emit `position` and clients should treat the two as equivalent.\n\nOmitted from an `Order` response when it is the default `none`.\n"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```


# JSON-RPC Errors

Errors returned by the Pod RPC server follow the standard [JSON-RPC 2.0](https://www.jsonrpc.org/specification#error_object) error format. In addition to the standard codes (`-32600`, `-32602`, `-32603`, etc.), Pod defines a small set of domain-specific codes for transaction validation, execution reverts, and account recovery.

## Error response format

Every error is returned as a JSON-RPC 2.0 error object:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "transaction validation failed",
    "data": "Insufficient balance"
  }
}
```

| Field     | Type                               | Description                                                                |
| --------- | ---------------------------------- | -------------------------------------------------------------------------- |
| `code`    | integer                            | Numeric error code (see below).                                            |
| `message` | string                             | Short, human-readable description of the error category.                   |
| `data`    | string / object / array (optional) | Extra context. Its shape depends on the error code — see each entry below. |

## Pod error codes

| Code                | Message                         | Meaning                                                                                                                                                                     |
| ------------------- | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `3`                 | `execution reverted`            | A contract-level (enshrined application) execution failed. `data` is an ABI-encoded revert.                                                                                 |
| `-32000`            | `transaction validation failed` | A protocol-level validation check failed (nonce, balance, chain ID, gas price, …).                                                                                          |
| `-32003`            | `Transaction rejected: …`       | A quorum of validators rejected the transaction.                                                                                                                            |
| `999`               | `Account locked`                | The account is locked pending recovery. `data` carries the recovery target.                                                                                                 |
| `-32020` … `-32023` | (see below)                     | A websocket subscription was closed by the server. Delivered as a notification, not a response — see [Subscription close notifications](#subscription-close-notifications). |

### `3` — execution reverted

Returned when an enshrined application (the order book, optimistic auctions, ERC-20 tokens, the bridge, or minting) rejects a transaction at execution time. The response mirrors the EIP-1474 / geth-style execution revert so that standard wallets and libraries (viem, ethers, alloy) decode the reason automatically.

`data` is a hex string: the 4-byte `Error(string)` selector (`0x08c379a0`) followed by the ABI-encoded reason string.

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 3,
    "message": "execution reverted",
    "data": "0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000204..."
  }
}
```

The decoded reason string is one of the contract-level [validation messages](#transaction-validation-messages) below (e.g. `CLOB validation failed: …`).

### `-32000` — transaction validation failed

Returned when a protocol-level check fails before the transaction is attested. `data` is a plain string holding the specific reason — one of the [validation messages](#transaction-validation-messages) below.

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "transaction validation failed",
    "data": "Future nonce: tx nonce 7, expected 5"
  }
}
```

### `-32003` — transaction rejected

Returned when at least `f + 1` validators reject a transaction (the rejection quorum). The `message` summarizes the distinct reasons; `data` is an array of objects, one per rejection.

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32003,
    "message": "Transaction rejected: Insufficient balance, Invalid chain ID: 1",
    "data": [
      { "error": "Insufficient balance" },
      { "error": "Invalid chain ID: 1" }
    ]
  }
}
```

### `999` — account locked

Returned when you submit a transaction for an account that is locked due to a pending recovery. `data` identifies the recovery target — see [Recover a locked account](/guides-references/guides/recover-locked-account).

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 999,
    "message": "Account locked",
    "data": {
      "recovery_target": "0x…",
      "recovery_target_nonce": 12
    }
  }
}
```

| `data` field            | Type   | Description                              |
| ----------------------- | ------ | ---------------------------------------- |
| `recovery_target`       | hash   | Transaction hash of the recovery target. |
| `recovery_target_nonce` | number | Nonce of the recovery target.            |

## Subscription close notifications

The codes above answer a request. A websocket subscription created with [`eth_subscribe`](https://github.com/podnetwork/pod-sdk/tree/main/doc/api-reference/json-rpc/openapi.yaml) can also be ended by the *server*, and that arrives as a notification rather than a response: same `eth_subscription` method as a normal update, but carrying `error` in place of `result`.

```json
{
  "jsonrpc": "2.0",
  "method": "eth_subscription",
  "params": {
    "subscription": "0x9c1f…",
    "error": {
      "code": -32020,
      "message": "subscription lagged behind the tick broadcast",
      "data": { "resumable": true, "missed": 42, "resume_since": 1718900000000000 }
    }
  }
}
```

The subscription is over once this arrives; nothing further is sent for it. The connection itself stays open, so any other subscription on it keeps working.

| Code     | Message                                            | What happened, and what to do                                                                                                                      |
| -------- | -------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `-32020` | `subscription lagged behind the tick broadcast`    | The server dropped ticks before this subscriber read them, rather than serve a stream with a gap in it. Resubscribe with `since` = `resume_since`. |
| `-32021` | `node is shutting down`                            | The node is going away. Reconnect (to another node, if you have one) and resubscribe with `since` = `resume_since`.                                |
| `-32022` | `subscriber did not accept a notification in time` | The connection would not take a notification within the server's send timeout. Resubscribe with `since` = `resume_since` once you can keep up.     |
| `-32023` | `failed to serialize a subscription notification`  | A server-side bug. **Do not** retry in a loop — an immediate resubscribe will likely reproduce it. Please report it.                               |

| `data` field        | Type    | Description                                                                                                                                                                                                                                                                            |
| ------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `resumable`         | boolean | Whether resubscribing recovers the stream. `false` only for `-32023`.                                                                                                                                                                                                                  |
| `resume_since`      | number  | Solution time (µs) of the newest tick this subscription is square on — every update it owed you was delivered (a tick that matched none of your filters owed nothing, so it counts). Pass it back as `since`. Absent if it is square on nothing yet; then reuse your original `since`. |
| `resume_since_book` | string  | `pod_orders_v2` only, and only when the batch it stopped in was partly delivered: the last `book` you were sent. Pass it back as `since_book` alongside `resume_since`. Absent when the batch landed whole.                                                                            |
| `missed`            | number  | `-32020` only: how many ticks the broadcast dropped.                                                                                                                                                                                                                                   |

`resume_since` names a whole tick, because `since` selects whole ticks. So if the subscription closed midway through one, resuming redelivers that tick in full and you may see a few deltas twice. That is deliberate — a repeated delta is something a client can dedupe, whereas one that was never sent is unrecoverable.

`pod_orders_v2` is the exception, because it can resume inside a tick. A batch settles many orderbooks and is delivered as one frame each, so a close there also carries `resume_since_book`; pass both back and you receive exactly the frames you never got, with nothing replayed. That is the case the two-part cursor exists for — a close midway through a batch is precisely when you cannot tell where you got to, since frames the connection already accepted may not have reached your code yet.

A close is the **only** signal that a delta stream lost data — the stream itself never has holes. Treat the absence of updates as an idle market only while the subscription is open.

> **Client support.** Not every websocket client surfaces this frame, so check yours before relying on the reason being readable.
>
> * **`alloy` (Rust)** rejects a subscription notification carrying `error` and treats it as a connection error: it tears the websocket down and reconnects rather than surfacing the payload. You observe the close as a reconnect.
> * **`jsonrpsee` (Rust)** removes the subscription and discards the payload, so the stream ends with no reason attached.
> * **The pod TypeScript SDK** (`@pod-network/trade-sdk`) delivers it to `subscribe`'s `onError` as a `PodSubscriptionClosedError` — `code`, `resumable`, `missed` and `resumeSince` mapped to properties, with the full payload on `raw` — and drops the subscription. On a resumable close it has already advanced that subscription's `since` to `resume_since`, so `sub.resubscribe()` is enough. It does not yet support `pod_orders_v2`, so `resume_since_book` reaches it only via `raw`.
>
> With the Rust clients, read the raw websocket frame to act on the reason. The subscription is over regardless of whether your client reports it.

## Transaction validation messages

The reason carried in `data` (for code `-32000`) or encoded inside the revert (for code `3`) is one of the following. Messages with `{…}` placeholders are filled in with the offending values.

### Protocol-level (returned with code `-32000`)

| Message                                                                   | When it occurs                                               |
| ------------------------------------------------------------------------- | ------------------------------------------------------------ |
| `Invalid chain ID: {chain_id}`                                            | The transaction's chain ID does not match the network.       |
| `Transaction is blacklisted`                                              | The transaction is on the blocklist.                         |
| `Account has pending transaction`                                         | The account already has an unexecuted (pending) transaction. |
| `Future nonce: tx nonce {tx_nonce}, expected {expected}`                  | The nonce is higher than the account's next expected nonce.  |
| `Past nonce: tx nonce {tx_nonce}, expected {expected}`                    | The nonce is lower than expected (already used).             |
| `Insufficient balance`                                                    | The account cannot cover the transaction.                    |
| `Underpriced tx: max_fee_per_gas {max_fee_per_gas} < base fee {base_fee}` | `maxFeePerGas` is below the current base fee.                |
| `Recovery validation failed: {reason}`                                    | A recovery transaction failed validation.                    |

### Contract-level (returned with code `3`, inside the revert)

| Message                                          | When it occurs                                    |
| ------------------------------------------------ | ------------------------------------------------- |
| `CLOB validation failed: {reason}`               | Order book transaction validation failed.         |
| `Optimistic auction validation failed: {reason}` | Optimistic auction validation failed.             |
| `ERC20 validation failed: {reason}`              | ERC-20 token operation validation failed.         |
| `Bridge validation failed: {reason}`             | Bridge / cross-chain operation validation failed. |
| `Mint validation failed: {reason}`               | Mint operation validation failed.                 |

## Standard JSON-RPC codes

Pod also returns the standard codes defined by the JSON-RPC 2.0 specification:

| Code     | Meaning         | Typical cause                                                              |
| -------- | --------------- | -------------------------------------------------------------------------- |
| `-32600` | Invalid Request | Malformed request, or an unauthorized call to an admin-only method.        |
| `-32602` | Invalid Params  | Parameters could not be parsed (e.g. a malformed hash or raw transaction). |
| `-32603` | Internal Error  | An internal server error while servicing the request.                      |


# Precompiles

Pod uses precompiles for enshrined applications and internal protocol operations. Precompiles are built into the protocol rather than deployed as user contracts, so they can access internal state (validator signatures, timestamps, merkle proofs) and execute without contract call overhead.

## Precompile Addresses

| Signature                                                                                             | Address                                      | Description                                                           |
| ----------------------------------------------------------------------------------------------------- | -------------------------------------------- | --------------------------------------------------------------------- |
| [Orderbook](/guides-references/references/applications-precompiles/orderbook)                         | `0x50d0000000000000000000000000000000000002` | Central limit order book for spot and perpetual markets               |
| [Bridge](/guides-references/references/applications-precompiles/bridge)                               | `0x50d0000000000000000000000000000000000001` | ERC-20 token bridging between Pod and Ethereum                        |
| [Optimistic Auctions](/guides-references/references/applications-precompiles/wip-optimistic-auctions) | `0x50d0000000000000000000000000000000000004` | Censorship-resistant auction for intents (settlement happens off-Pod) |
| [Recovery](/guides-references/references/applications-precompiles/recovery)                           | `0x50d0000000000000000000000000000000000003` | Recover a locked account by finalizing the target transaction chain   |

## Interacting with Precompiles

You interact with Pod's precompiles the same way you would interact with any smart contract on Ethereum - by encoding function calls against a Solidity ABI and sending them via `eth_call` (reads) or `eth_sendRawTransaction` (writes).

### Reading State

Query the deposited balance of a token in the orderbook contract using `eth_call`.

{% tabs %}
{% tab title="JavaScript (ethers.js)" %}

```javascript
import { ethers } from "ethers";

const provider = new ethers.JsonRpcProvider("https://rpc.podtestnet.dev");

const ORDERBOOK = "0x50d0000000000000000000000000000000000002";
const abi = ["function balanceOf(address token, address account) view returns (uint256)"];
const orderbook = new ethers.Contract(ORDERBOOK, abi, provider);

const USDT = "0x0000000000000000000000000000000000000001";
const ACCOUNT = "0xYourAddress";
const balance = await orderbook.balanceOf(USDT, ACCOUNT);
console.log("Balance:", balance.toString());
```

{% endtab %}

{% tab title="Python (web3.py)" %}

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider("https://rpc.podtestnet.dev"))

ORDERBOOK = "0x50d0000000000000000000000000000000000002"
abi = [{"inputs": [{"name": "token", "type": "address"},
                   {"name": "account", "type": "address"}],
        "name": "balanceOf",
        "outputs": [{"name": "", "type": "uint256"}],
        "stateMutability": "view", "type": "function"}]

orderbook = w3.eth.contract(address=ORDERBOOK, abi=abi)

USDT = "0x0000000000000000000000000000000000000001"
ACCOUNT = "0xYourAddress"
balance = orderbook.functions.balanceOf(USDT, ACCOUNT).call()
print("Balance:", balance)
```

{% endtab %}

{% tab title="Rust (alloy)" %}

```rust
use alloy::{providers::ProviderBuilder, sol};

sol! {
    #[sol(rpc)]
    contract Orderbook {
        function balanceOf(address token, address account) public view returns (uint256);
    }
}

#[tokio::main]
async fn main() -> eyre::Result<()> {
    let provider = ProviderBuilder::new()
        .on_http("https://rpc.podtestnet.dev".parse()?);

    let orderbook = Orderbook::new(
        "0x50d0000000000000000000000000000000000002".parse()?,
        &provider,
    );

    let usdt: Address = "0x0000000000000000000000000000000000000001".parse()?;
    let account: Address = "0xYourAddress".parse()?;
    let balance = orderbook.balanceOf(usdt, account).call().await?;
    println!("Balance: {}", balance._0);

    Ok(())
}
```

{% endtab %}
{% endtabs %}

### Submitting Transactions

Send a signed transaction to place a buy order on the orderbook via `eth_sendRawTransaction`.

{% tabs %}
{% tab title="JavaScript (ethers.js)" %}

```javascript
import { ethers } from "ethers";

const provider = new ethers.JsonRpcProvider("https://rpc.podtestnet.dev");
const signer = new ethers.Wallet(process.env.PRIVATE_KEY, provider);

const ORDERBOOK = "0x50d0000000000000000000000000000000000002";
const abi = [
  `function submitOrder(
    bytes32 orderbookId, int256 size, uint256 price,
    uint8 orderType, uint128 deadline, uint128 ttl,
    bool reduceOnly, bool ioc
  )`
];
const orderbook = new ethers.Contract(ORDERBOOK, abi, signer);

const orderbookId = "0x0000000000000000000000000000000000000000000000000000000000000001"; // NVDAx-USD spot
const size = ethers.parseEther("1");            // buy 1 unit
const price = ethers.parseEther("5000");        // limit price
const orderType = 0;                            // 0 = Limit, 1 = Market
// Deadline: next auction tick ~10s out — must be a multiple of the market's
// auction interval (500 ms on testnet) or validators reject the order.
const AUCTION_INTERVAL = 500_000n;              // microseconds
const deadline = ((BigInt(Date.now()) * 1000n + 10_000_000n + AUCTION_INTERVAL - 1n)
  / AUCTION_INTERVAL) * AUCTION_INTERVAL;
const ttl = 60n * 1_000_000n;                  // 60 seconds in microseconds

const tx = await orderbook.submitOrder(
  orderbookId, size, price, orderType, deadline, ttl,
  false,    // reduceOnly (perp only)
  false,    // ioc — immediate-or-cancel
);
console.log("Order tx:", tx.hash);
```

{% endtab %}

{% tab title="Python (web3.py)" %}

```python
from web3 import Web3
import time, os

w3 = Web3(Web3.HTTPProvider("https://rpc.podtestnet.dev"))
account = w3.eth.account.from_key(os.environ["PRIVATE_KEY"])

ORDERBOOK = "0x50d0000000000000000000000000000000000002"
abi = [{"inputs": [
    {"name": "orderbookId", "type": "bytes32"},
    {"name": "size", "type": "int256"},
    {"name": "price", "type": "uint256"},
    {"name": "orderType", "type": "uint8"},
    {"name": "deadline", "type": "uint128"},
    {"name": "ttl", "type": "uint128"},
    {"name": "reduceOnly", "type": "bool"},
    {"name": "ioc", "type": "bool"}],
    "name": "submitOrder", "outputs": [],
    "stateMutability": "nonpayable", "type": "function"}]

orderbook = w3.eth.contract(address=ORDERBOOK, abi=abi)

# Deadline: next auction tick ~10s out — must be a multiple of the market's
# auction interval (500 ms on testnet) or validators reject the order.
AUCTION_INTERVAL = 500_000  # microseconds
now_us = int(time.time() * 1_000_000)
deadline = (now_us + 10_000_000 + AUCTION_INTERVAL - 1) // AUCTION_INTERVAL * AUCTION_INTERVAL

tx = orderbook.functions.submitOrder(
    bytes.fromhex("00" * 31 + "01"),            # orderbook id
    10**18,                                      # size: buy 1 unit
    5000 * 10**18,                               # limit price
    0,                                           # order type: 0 = Limit
    deadline,                                    # deadline in microseconds
    60 * 1_000_000,                              # ttl: 60 seconds
    False,                                       # reduce only (perp only)
    False,                                       # ioc (immediate-or-cancel)
).build_transaction({
    "from": account.address,
    "nonce": w3.eth.get_transaction_count(account.address),
})

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print("Order tx:", tx_hash.hex())
```

{% endtab %}

{% tab title="Rust (alloy)" %}

```rust
use alloy::{
    network::EthereumWallet,
    providers::ProviderBuilder,
    signers::local::PrivateKeySigner,
    sol,
    primitives::{U256, I256, FixedBytes},
};

sol! {
    #[sol(rpc)]
    contract Orderbook {
        enum OrderType { Limit, Market }
        function submitOrder(
            bytes32 orderbookId, int256 size, uint256 price,
            OrderType orderType, uint128 deadline, uint128 ttl,
            bool reduceOnly, bool ioc
        ) public;
    }
}

#[tokio::main]
async fn main() -> eyre::Result<()> {
    let signer: PrivateKeySigner = std::env::var("PRIVATE_KEY")?.parse()?;
    let wallet = EthereumWallet::from(signer);

    let provider = ProviderBuilder::new()
        .wallet(wallet)
        .on_http("https://rpc.podtestnet.dev".parse()?);

    let orderbook = Orderbook::new(
        "0x50d0000000000000000000000000000000000002".parse()?,
        &provider,
    );

    // Deadline: next auction tick ~10s out — must be a multiple of the market's
    // auction interval (500 ms on testnet) or validators reject the order.
    const AUCTION_INTERVAL_US: u128 = 500_000;
    let now_us = std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)?
        .as_micros();
    let deadline = (now_us + 10_000_000).div_ceil(AUCTION_INTERVAL_US) * AUCTION_INTERVAL_US;

    let one_e18 = U256::from(10).pow(U256::from(18));

    let tx = orderbook.submitOrder(
        FixedBytes::left_padding_from(&[1]),     // orderbook id
        I256::from_raw(one_e18),                 // size: buy 1 unit
        U256::from(5000) * one_e18,              // limit price
        Orderbook::OrderType::Limit,             // order type
        deadline,                                 // deadline (auction-tick aligned)
        60 * 1_000_000,                          // ttl: 60 seconds
        false,                                    // reduceOnly (perp only)
        false,                                    // ioc — immediate-or-cancel
    ).send().await?;

    println!("Order tx: {:?}", tx.tx_hash());
    Ok(())
}
```

{% endtab %}
{% endtabs %}


# Orderbook

The **Orderbook precompile** is the on-chain execution surface for native markets — both **spot** and **perpetual**. The same contract, calls, and balances are shared across both market types; a market's behavior is determined by the `MarketType` set at creation.

Use it for **placing/canceling/updating orders**, **depositing/withdrawing funds**, **opening leveraged perpetual positions**, **arming take-profit / stop-loss triggers**, and **reading balances and order state**.

{% hint style="info" %}
**Orderbook precompile address:** `0x50d0000000000000000000000000000000000002`
{% endhint %}

{% hint style="warning" %}
**All timestamps sent to the orderbook are in microseconds**, not milliseconds or seconds. This applies to every `deadline` and `ttl` on this precompile.
{% endhint %}

{% hint style="info" %}
**Orders are identified by a computed `order_id`, not the tx hash.** A resting order is keyed by

```
order_id = keccak256(abi.encode(address signer, uint64 nonce, uint32 sequence))
```

where `signer` is the order owner, `nonce` is the `submitOrder` transaction's nonce, and `sequence` is the intent's position inside a `submitBatch` envelope (`0` for a standalone `submitOrder`). Wherever a call references an existing order — `cancel(canceledOrder, …)` and `update(updatedOrder, …)` — pass this `order_id`. You can compute it yourself with the formula above, or read it back from `ob_getOrders`, which returns it as `order_id` (the originating `submitOrder` tx hash is exposed separately as `tx_hash`).
{% endhint %}

{% hint style="warning" %}
**`deadline`** is the latest batch the intent is allowed to be included in — the intent can land in any batch up to and including the one whose end matches `deadline`. It must be aligned to the market's `auction_interval` (a multiple of it), or the validator rejects the intent with `"CLOB validation failed: Deadline is not aligned to auction interval"`. Compute it as:

```
deadline = ceil((now + LAG) / auction_interval) * auction_interval
```

`LAG` is the headroom you add to `now` so the intent reaches enough validators before its target batch. It is capped at **10 minutes**; aim for **at least 1 minute** under normal conditions, smaller when you want to target a specific upcoming batch.

The alignment rule applies to **every deadline-bearing call** on this precompile — `deposit` and `withdraw` as much as orders, cancels, updates and triggers. All of them pass through the same validator check, so an unaligned deposit deadline is rejected just like an unaligned order deadline.

See [Batch Deadline](https://github.com/podnetwork/pod-sdk/tree/main/doc/protocol/orderbook.md#batch-deadline) in the protocol reference for the full discussion of `deadline` semantics and the trade-offs around `LAG`.
{% endhint %}

### Batch envelope

`submitBatch` packs several single-intent calls (1–64) into a single signed transaction that lands atomically in one auction tick. Each entry in `inner` is the full ABI-encoded calldata of a single-intent function (`submitOrder`, `cancel`, `update`, `submitTrigger`, `deposit`, …) — encoded exactly as a standalone call, including its 4-byte selector. Every sub-intent **must carry the same `deadline`** (the uniform-deadline invariant), and nested batches are rejected. For the full rules and a worked example, see [Submit a batch order](/guides-references/guides/submit-a-batch-order).

### Delegation envelope

`delegated` lets a **delegate** key perform an orderbook call on behalf of a **master** account. The transaction is signed by the delegate; `signature` is the master's 65-byte `r ‖ s ‖ v` EIP-712 signature over `DelegationAuth { delegate, validUntil }` (domain `{ name: "pod delegation", version: "1", chainId }`), where `delegate` must equal the transaction's signer, and `inner` is the full ABI-encoded calldata of the wrapped call, including its 4-byte selector. The certificate is verified statelessly on every transaction — no registration, no on-chain state — and the intent is accepted only while `validUntil >= deadline` of the inner call (both in microseconds).

The inner intent is **owned by the master** (balances, resting-order owner, cancel/update/withdraw target) while its `order_id` keys on the delegate (the tx signer); a delegated `deposit`/`withdraw` has its `recipient` overridden to the master. Any deadline-bearing call can be wrapped — single intents or a whole `submitBatch` — but `submitSolutions`, `createOrderBook`, and nested `delegated` are rejected. Delegated calls are gas-exempt. For the concept and security model see [Key Delegation](https://github.com/podnetwork/pod-sdk/tree/main/doc/protocol/key-delegation.md) in the protocol reference; for a worked example see [Delegate a trading key](/guides-references/guides/delegate-a-trading-key).

### Solidity interface (ABI)

```solidity
/**
 * @title Orderbook
 * @notice A central limit order book for trading assets.
 * @dev Handles order placement, cancellation, and fund management.
 */
contract Orderbook {

    enum Side { Buy, Sell }
    enum OrderType { Limit, Market }
    enum MarketType { Spot, Perp }

    // Trigger kind for a TP/SL trigger (perp markets only).
    enum TriggerType { TakeProfit, StopLoss }

    // Exposure-association for a trigger.
    // None: standalone — removed only by a user cancel, TTL expiry, or its own fire.
    // Asset: binds the trigger to the asset the market type implies — on perp
    //        markets the venue cancels the armed trigger (and any resting synthetic
    //        order it already produced) at the end of the batch in which the
    //        bidder's position on the pair reaches size 0; on spot markets it
    //        cancels the armed trigger when the bidder's base-asset holdings hit 0.
    //        (Renamed from `Position`; same ABI value — older nodes report it as
    //        `position` in RPC responses.)
    enum TriggerGrouping { None, Asset }

    // --- Order Management ---

    /**
     * Submits a new order to the orderbook.
     * The direction of the trade (Bid/Ask) is determined by the sign of the size.
     * @param orderbookId The unique identifier of the specific market (e.g., ETH-USDC).
     * @param size The size of the order. Positive (+) for Buy/Bid, Negative (-) for Sell/Ask.
     * @param price The limit price for the order.
     * @param orderType The order type (Limit or Market).
     * @param deadline The timestamp limit for this order to be included in a batch in microseconds. Must be a multiple of the market's `auction_interval`.
     * @param ttl The "Time To Live" duration in microseconds; how long the order remains active in the book.
     * @param reduceOnly If true, this order will only reduce an existing position. Perp markets only.
     * @param ioc If true, the order is Immediate-Or-Cancel: any unmatched portion is cancelled at the end of the batch instead of resting on the book.
     */
    function submitOrder(
        bytes32 orderbookId,
        int256 size,
        uint256 price,
        OrderType orderType,
        uint128 deadline,
        uint128 ttl,
        bool reduceOnly,
        bool ioc
    ) public {}

    /**
     * @notice Cancels an existing open order.
     * @param orderbookId The unique identifier of the market the order belongs to.
     * @param canceledOrder The `order_id` of the order to cancel — the computed
     *        `keccak256(abi.encode(signer, nonce, sequence))`, also returned as `order_id` by
     *        `ob_getOrders`. This is NOT the `submitOrder` tx hash.
     * @param deadline The Unix timestamp after which this cancellation request is invalid in microseconds. Must be a multiple of the market's `auction_interval`.
     */
    function cancel(
        bytes32 orderbookId,
        bytes32 canceledOrder,
        uint128 deadline
    ) public {}

    /**
     * @notice Updates an existing open order.
     * @param orderbookId The unique identifier of the market the order belongs to.
     * @param updatedOrder The `order_id` of the order to update — the computed
     *        `keccak256(abi.encode(signer, nonce, sequence))`, also returned as `order_id` by
     *        `ob_getOrders`. This is NOT the `submitOrder` tx hash.
     * @param newSize The new size for the order.
     * @param newPrice The new price for the order.
     * @param token The token used to cover any additional collateral required by the update.
     * @param deadline The Unix timestamp after which this update is invalid in microseconds. Must be a multiple of the market's `auction_interval`.
     */
    function update(
        bytes32 orderbookId,
        bytes32 updatedOrder,
        uint256 newSize,
        uint256 newPrice,
        address token,
        uint128 deadline
    ) public {}

    // --- Data Retrieval ---

    /**
     * @notice Token balance for an account, as a signed integer.
     * @param token The address of the token to check.
     * @param account The address of the account to check.
     * @return Native USD: cash adjusted for unsettled funding (negative if the account is underwater).
     *         Other tokens: the raw spot balance.
     */
    function balanceOf(address token, address account) public view returns (int256) {}

    /**
     * @notice Withdrawable balance for an account.
     * @param token The address of the token to check.
     * @param account The address of the account to check.
     * @return Native USD: perps equity minus reserved initial margin (never negative).
     *         Other tokens: the raw spot balance (no margin deducted).
     */
    function withdrawableBalance(address token, address account) public view returns (uint256) {}

    // --- Fund Management ---

    /**
     * @notice Deposits tokens into the exchange to be used for trading.
     * @param token The address of the token to deposit.
     * @param recipient The address that will be credited with the deposit.
     * @param amount The amount of tokens to deposit (in atomic units).
     * @param deadline The Unix timestamp after which the deposit is invalid in microseconds. Must be a multiple of the `auction_interval`.
     */
    function deposit(
        address token,
        address recipient,
        uint256 amount,
        uint128 deadline
    ) public {}

    /**
     * @notice Withdraws tokens from the exchange to an external wallet.
     * @param token The address of the ERC20 token to withdraw.
     * @param recipient The address receiving the withdrawn tokens.
     * @param amount The amount of tokens to withdraw.
     * @param deadline The Unix timestamp after which the withdrawal is invalid in microseconds. Must be a multiple of the `auction_interval`.
     */
    function withdraw(
        address token,
        address recipient,
        uint256 amount,
        uint128 deadline
    ) public {}

    // --- TP/SL triggers (perp markets only) ---

    /**
     * @notice Arms a take-profit / stop-loss trigger on a perp market.
     * @dev The trigger rests on the venue until it fires, is cancelled, or its TTL
     *      expires. It fires when the pair's mark price crosses `triggerPrice` in the
     *      direction implied by the order side (sign of `size`) and `triggerType`:
     *
     *        | Side | Type       | Fires when             |
     *        |------|------------|------------------------|
     *        | Buy  | TakeProfit | mark price <= trigger  |
     *        | Buy  | StopLoss   | mark price >= trigger  |
     *        | Sell | TakeProfit | mark price >= trigger  |
     *        | Sell | StopLoss   | mark price <= trigger  |
     *
     *      On firing the venue emits a synthetic limit order (price `limitPrice`,
     *      size `size`) that is admitted into the matching batch like any other order.
     * @param orderbookId The unique identifier of the perp market.
     * @param size The signed base amount of the order produced when the trigger fires.
     *        Positive (+) for Buy/long, negative (-) for Sell/short.
     * @param limitPrice The limit price of the synthetic order produced when the trigger fires.
     * @param triggerPrice The mark-price threshold that fires the trigger.
     * @param triggerType TakeProfit or StopLoss.
     * @param grouping Whether the trigger is bound to the bidder's exposure on the pair (see TriggerGrouping).
     * @param deadline The latest batch this intent may be included in, in microseconds. Must be a multiple of the market's `auction_interval`.
     * @param ttl The "Time To Live" duration in microseconds; how long the armed trigger remains active.
     * @param reduceOnly If true, the synthetic order will only reduce an existing position.
     * @param ioc If true, the synthetic order is Immediate-Or-Cancel: any unmatched portion is cancelled at the end of the batch it fires in.
     */
    function submitTrigger(
        bytes32 orderbookId,
        int256 size,
        uint256 limitPrice,
        uint256 triggerPrice,
        TriggerType triggerType,
        TriggerGrouping grouping,
        uint128 deadline,
        uint128 ttl,
        bool reduceOnly,
        bool ioc
    ) public {}

    /**
     * @notice Cancels an armed trigger.
     * @param orderbookId The unique identifier of the market the trigger belongs to.
     * @param triggerOrder The `order_id` of the trigger to cancel — the computed
     *        `keccak256(abi.encode(signer, nonce, sequence))`, also returned as `order_id`
     *        by `ob_getTriggers`. This is NOT the `submitTrigger` tx hash.
     * @param deadline The latest batch this intent may be included in, in microseconds. Must be a multiple of the market's `auction_interval`.
     */
    function cancelTrigger(
        bytes32 orderbookId,
        bytes32 triggerOrder,
        uint128 deadline
    ) public {}

    /**
     * @notice Updates an armed trigger. The `grouping` mode is immutable and cannot be changed.
     * @param orderbookId The unique identifier of the market the trigger belongs to.
     * @param triggerOrder The `order_id` of the trigger to update — the computed
     *        `keccak256(abi.encode(signer, nonce, sequence))`, also returned as `order_id`
     *        by `ob_getTriggers`. This is NOT the `submitTrigger` tx hash.
     * @param newSize The new signed base amount of the order produced when the trigger fires.
     * @param newLimitPrice The new limit price of the synthetic order.
     * @param newTriggerPrice The new mark-price threshold that fires the trigger.
     * @param deadline The latest batch this intent may be included in, in microseconds. Must be a multiple of the market's `auction_interval`.
     */
    function updateTrigger(
        bytes32 orderbookId,
        bytes32 triggerOrder,
        int256 newSize,
        uint256 newLimitPrice,
        uint256 newTriggerPrice,
        uint128 deadline
    ) public {}

    // --- Batch envelope ---

    /**
     * @notice Carries multiple single-intent calls in one signed transaction.
     * @dev Each `inner[i]` is the full ABI-encoded calldata of one of the other
     *      single-intent functions on this contract — `submitOrder`, `cancel`,
     *      `update`, `submitTrigger`, `cancelTrigger`, `updateTrigger`,
     *      `deposit`, or `withdraw`. The whole envelope is atomic: it lands in a
     *      single auction tick, so every sub-intent must carry the **same**
     *      `deadline`. Constraints (enforced at validation):
     *      - 1 to 64 sub-intents (the cap is configurable by the operator).
     *      - All sub-intents share one `deadline` (uniform-deadline invariant).
     *      - Nested batches are rejected — `inner[i]` may not itself be a `submitBatch`.
     * @param inner The ABI-encoded calldata of each sub-intent, in order.
     */
    function submitBatch(bytes[] calldata inner) public {}

    // --- Delegation envelope ---

    /**
     * @notice Performs an orderbook call on behalf of a master account. The
     *         transaction is signed by the delegate; the master's authorization
     *         travels inside the call and is verified on every transaction.
     * @dev `signature` is the master's 65-byte `r‖s‖v` EIP-712 signature (v = 27/28)
     *      over `DelegationAuth { address delegate; uint64 validUntil; }` with domain
     *      `{ name: "pod delegation", version: "1", chainId }`, where `delegate` must
     *      equal the transaction's signer. Constraints (enforced at validation):
     *      - `validUntil` must be >= the inner call's `deadline` (both microseconds).
     *      - `inner` must be a deadline-bearing call — a single intent or a
     *        `submitBatch`. `submitSolutions`, `createOrderBook`, and nested
     *        `delegated` are rejected; view functions cannot be wrapped.
     *      - A delegated `deposit`/`withdraw` has its `recipient` overridden to `master`.
     *      The inner intent is owned by `master` (balances, resting-order owner,
     *      cancel/update/withdraw target), while its `order_id` keys on the delegate
     *      (the tx signer). Delegated calls are gas-exempt.
     * @param master The account the wrapped call is performed on behalf of.
     * @param validUntil Expiry of the delegation certificate, in microseconds.
     * @param signature The master's 65-byte EIP-712 signature authorizing the delegate.
     * @param inner The full ABI-encoded calldata of the wrapped call, including its selector.
     */
    function delegated(
        address master,
        uint64 validUntil,
        bytes calldata signature,
        bytes calldata inner
    ) public {}
}
```


# Optimistic Auctions

The optimistic auctions precompile is a minimal auction contract for intents. Bidders submit bids into auction instances on Pod, but settlement happens elsewhere - on Ethereum, an L2, or any other chain with an on-chain consumer contract. Pod acts as a censorship-resistant bulletin board: it collects bids before a deadline and uses [past perfection](https://docs.v2.pod.network/documentation/core/timestamping#past-perfection) to guarantee that the bid set is complete once the deadline passes.

For background on how optimistic auctions work, see [Optimistic Auctions](https://docs.v2.pod.network/documentation/markets/optimistic-auctions).

**Precompile address:** `0x50d0000000000000000000000000000000000004`

## Interface

```solidity
interface IOptimisticAuction {
    /// @notice Emitted when a new bid is submitted for an auction instance.
    event BidSubmitted(
        uint256 indexed auction_id,
        address indexed bidder,
        uint64 indexed deadline,
        uint256 value,
        bytes data
    );

    /// @notice Submit a bid into a specific auction instance.
    ///         If the auction_id does not exist yet, it is created implicitly.
    /// @param auction_id Logical auction identifier. Bids with the same id compete together.
    /// @param deadline Unix timestamp in microseconds. After this, the bid is invalid.
    /// @param value Application-defined numeric value associated with the bid.
    /// @param data Opaque payload, commonly encodes an intent or order.
    function submitBid(
        uint256 auction_id,
        uint64 deadline,
        uint256 value,
        bytes calldata data
    ) external;
}
```

{% hint style="warning" %}
**Microseconds, not milliseconds.** Deadlines are Unix timestamps in microseconds.
{% endhint %}


# Bridge

The bridge precompile allows users to initiate withdrawals from Pod to other chains. Tokens withdrawn via the bridge precompile are burned on Pod and can be claimed on the destination chain's bridge contract using a validator proof.

For how the bridge works end-to-end, see [Native Bridge](https://docs.v2.pod.network/documentation/native-bridge). For step-by-step guides, see [Bridge to Pod](/guides-references/guides/bridge-to-pod) and [Bridge from Pod](/guides-references/guides/bridge-from-pod).

**Precompile address:** `0x50d0000000000000000000000000000000000001`

## Interface

```solidity
interface IPodBridge {
    /// @notice Emitted when tokens are withdrawn for bridging to another chain.
    event Withdraw(
        bytes32 indexed id,
        address indexed from,
        address indexed to,
        address token,
        uint256 amount,
        uint256 chainId
    );

    /// @notice Initiate a withdrawal to another chain. Burns tokens on Pod and emits
    ///         a Withdraw event. Use the transaction hash to obtain a claim proof
    ///         via pod_getBridgeClaimProof.
    /// @param token Token address on Pod. Use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native token.
    /// @param amount Amount of tokens to bridge.
    /// @param to Recipient address on the target chain.
    /// @param chainId Target chain ID where the claim will happen. Prevents replay across chains.
    /// @return id Unique withdraw identifier.
    function withdraw(
        address token,
        uint256 amount,
        address to,
        uint256 chainId
    ) external returns (bytes32 id);
}
```

## Decimal Scaling

All tokens on Pod are represented with 18 decimals, regardless of their decimals on the target chain (e.g. USDC has 6 decimals on Ethereum but 18 on Pod).

When calling `withdraw` to bridge from Pod to another chain, the `amount` must be specified in the **target chain token's units**, not in Pod's 18-decimal representation. For example, to bridge 1 USDC to Ethereum, pass `1000000` (1e6), not `1000000000000000000` (1e18).

## Native Token Withdrawals

When withdrawing the native token (ETH), **`tx.value` must be `0`**. The bridge deducts the balance internally — do not send value with the transaction.


# Recovery

The recovery precompile allows users to recover a locked account by finalizing the target transaction chain. Accounts can become locked when conflicting transactions are submitted at the same nonce.

For background on why accounts get locked and how the recovery protocol works, see [Local Ordering](https://docs.v2.pod.network/documentation/network-architecture/local-ordering#account-locking-and-recovery). For a step-by-step guide, see [Recover a locked account](/guides-references/guides/recover-locked-account).

**Precompile address:** `0x50d0000000000000000000000000000000000003`

## Interface

```solidity
interface IRecovery {
    /// @notice Recover a locked account by finalizing the target transaction chain.
    /// @param txHash The hash of the target transaction to recover to (obtained via pod_getRecoveryTargetTx).
    /// @param nonce The nonce of the target transaction (obtained via pod_getRecoveryTargetTx).
    function recover(bytes32 txHash, uint64 nonce) external;
}
```

## Usage

1. Call `pod_getRecoveryTargetTx(account)` on the full node to get the target transaction hash and nonce.
2. Send a transaction to the recovery precompile calling `recover(txHash, nonce)` with the values from step 1.

The protocol will finalize the target transaction chain, recover your account state, and increment the nonce. You can then send a new transaction with the next nonce.


# CowSwap Solver Auctions

[CowSwap](https://cow.fi) runs a solver auction to determine which solver settles each batch of user swap intents. Solvers compete by submitting bids that reflect the quality of their proposed solution. The winning solver executes the settlement on Ethereum.

Currently, the auction is orchestrated by a centralized service (autopilot) operated by the CoW DAO team. Pod Network is working with CoW to remove this central point of failure by running the solver auction on Pod.

For background on the auction mechanism, see [Optimistic Auctions](https://docs.v2.pod.network/documentation/markets/optimistic-auctions).

## How It Works

1. **Solver competition** - Solvers submit bids to Pod's [optimistic auctions precompile](https://docs.v2.pod.network/guides-references/references/precompiles/optimistic-auctions). Each bid includes the solver's score - a measure of solution quality (e.g. surplus delivered to users).
2. **Bid set finalization** - After the auction deadline, [past perfection](https://docs.v2.pod.network/documentation/core/timestamping#past-perfection) guarantees the bid set is complete. No bids can be added or suppressed after this point.
3. **Winner announcement** - The winning solver (highest score) announces the result to the CoW Protocol settlement contract on Ethereum, along with a finality certificate from Pod proving the bid was part of the auction.
4. **Optimistic settlement** - The winner executes the settlement on Ethereum. If the solver submitted a false claim (e.g. a higher-scoring bid exists in the set), any other solver can dispute by providing the correct winning bid with its Pod finality certificate. The settlement contract verifies both certificates and resolves the dispute on-chain.

## References

* [Decentralising the CoW Protocol Solver Auction](https://forum.cow.fi/t/decentralising-the-cow-protocol-solver-auction/3014) - CoW Protocol forum post describing the integration design
* [Octopod: Decentralized Sealed-Bid Auctions on Pod](https://drive.google.com/file/d/1uNVX4gBadHniYD9xKk1LzObFq8yzSmf7/view) - formal auction protocol


# RollupBoost Priority Auctions

[RollupBoost](https://writings.flashbots.net/introducing-rollup-boost) is a block-building pipeline for rollups developed by Flashbots. It separates block building from sequencing - the sequencer delegates block construction to a builder running inside a TEE (Trusted Execution Environment). The TEE ensures bid privacy and correct ordering by priority fee, but the builder can still censor bids since it controls which bids it receives.

This example demonstrates how RollupBoost could leverage Pod to add censorship resistance to the priority auction. Searchers submit bids to Pod instead of directly to the builder. The TEE builder then fetches the verified bid set from Pod, guaranteeing that no bids were censored.

For background on the auction mechanism, see [Optimistic Auctions](https://docs.v2.pod.network/documentation/markets/optimistic-auctions).

## How It Works

1. **Bid submission** - Searchers submit priority bids to Pod's [optimistic auctions precompile](https://docs.v2.pod.network/guides-references/references/precompiles/optimistic-auctions). Each bid contains the L2 transaction (or bundle) and a priority fee. The `auction_id` identifies the L2 block slot being auctioned.
2. **Past perfect verification** - After the auction deadline, the TEE builder calls `pod_waitPastPerfectTime` on a Pod full node. This blocks until the past perfect certificate is available, which cryptographically guarantees the bid set is complete. The builder verifies the certificate inside the TEE.
3. **Bid set retrieval** - The builder queries `BidSubmitted` event logs from Pod to fetch all bids for the auction. Because the past perfect certificate has been verified, the builder knows this set is complete - any bid submitted sufficiently before the deadline is guaranteed to be included.
4. **Block construction** - The builder sorts bids by priority fee and includes them in the L2 block. The TEE attestation proves the builder used the verified bid set and followed the ordering rules.

A working implementation is available at [`examples/optimism-tx-auction`](https://github.com/nicblockchain/optimism-tx-auction).

## References

* [From Fair Ordering to Fair Inclusion](https://pod.network/blog/from-fair-ordering-to-fair-inclusion) - how Pod adds verifiable inclusion to the RollupBoost stack
* [RollupBoost + Pod L2 Demo](https://collective.flashbots.net/t/l2-demo-of-pod/4459) - live demo on DevNet
* [Introducing RollupBoost](https://writings.flashbots.net/introducing-rollup-boost) - Flashbots blog post introducing RollupBoost


# Trading Competition

A three-week trading competition hosted at [**test.pod.network**](https://test.pod.network). Highest absolute P\&L at the end wins a **Rolex Submariner Ref: 124060**.

|                  |                                                       |
| ---------------- | ----------------------------------------------------- |
| **Starts**       | Wednesday, June 3, 2026, 12PM UTC                     |
| **Ends**         | Wednesday, June 24, 2026, 12PM UTC                    |
| **Site**         | [test.pod.network](https://test.pod.network)          |
| **Prize**        | Rolex Submariner Ref: 124060                          |
| **Registration** | Open to anyone meeting the eligibility criteria below |

{% hint style="warning" %}
**Testnet reset at start.** At the start of the competition the Pod testnet will be reset. All balances and positions from before the start will be wiped.
{% endhint %}

## Eligibility

To register, your X (Twitter) account must satisfy at least one of:

* X premium account, **or**
* More than 100 followers

One person may register **one account only**. Any sybil behavior (multiple registrations by the same person, coordinated accounts, etc.) will be disqualified.

One X account can be linked to **one wallet** only.

## Starting balance

Every registered participant gets paper testnet USD to trade with. The starting balance depends on when and how you joined:

| Participant                              | Starting balance |
| ---------------------------------------- | ---------------- |
| Registered and deposited on the waitlist | **$10,500 USD**  |
| Registered but no waitlist deposit       | **$10,000 USD**  |

{% hint style="info" %}
**Paper money only.** Competition balances cannot be withdrawn from the network or transferred between accounts. They exist purely for the duration of the competition.
{% endhint %}

## How winners are decided

At the end of the three weeks, each registered account is scored by **absolute P\&L** — the change in total account value (cash + open positions, marked to market) from the participant's starting balance.

The highest absolute P\&L wins the Rolex Submariner Ref: 124060. The winner will be contacted by **DM from the official Pod X account** to their verified X account to arrange delivery of the prize.

## Rules summary

* One person, one account. Sybil entries are disqualified.
* One X account is linked to one wallet for the duration of the competition.
* Paper testnet balances are non-withdrawable and non-transferable.
* The testnet resets at the start — there is no carryover from prior testnet activity.

## Legal

By registering, participants agree to the [Official Rules](https://app.pod.network/terms?tab=challenge), the [Terms of Use](https://pod.network/terms), and the [Privacy Policy](https://pod.network/terms?tab=privacy). The Official Rules govern the competition and prevail in case of any conflict with the summary above.

## Next steps


# Page


