# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
This site has an agentic ask interface you may use to query the documentation dynamically by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.v2.pod.network/index.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

---

# 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**.

Trading Competition closed as of June 24, 2026. Follow [Pod Network](https://x.com/poddotnetwork) for the winners.

|                  |                                                       |
| ---------------- | ----------------------------------------------------- |
| **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 |


# 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), liquidation and margin engines, and pricing oracles. 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, how value crosses the boundary

**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


# 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 the recipient's balance 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 calls `withdraw` on the Pod bridge precompile, which burns the balance on Pod, and once the withdrawal is finalized anyone can claim the tokens from the bridge contract on Ethereum. This is the path in and out; no other Pod precompile moves value across the boundary.

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. **Vote batch timestamps** - each validator signs every vote batch it broadcasts, and each batch carries a microsecond timestamp and a sequence number. A validator with nothing to attest to still emits a batch with no votes in it, so time keeps advancing on an idle network. Vote batches 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 vote batches 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 vote 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 vote signatures to independently confirm the set is final.


# 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.


# 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. It is how value crosses the boundary in either direction: there is no deposit call and no withdraw call on any other Pod precompile.

## 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 `withdraw` here to send a balance to Ethereum; the same precompile is where validators apply the deposits they observe on 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 recipient's **balance** on Pod, ready to trade with. Nothing is credited anywhere else, and the user sends no transaction on Pod at all: the bridge relayer submits the deposits and every validator re-checks each entry against its own view of the finalized Ethereum event before attesting.

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's `deposit` still takes `callContract` and `reserveBalance`, and they are still carried through to the Pod-side `DepositApplied` event so the two sides reconcile - but they **no longer route anything on Pod**. A deposit is credited whole to the recipient's balance regardless of what they say, because there is no longer a second balance to split it against.

They are still **validated on Ethereum**, though, so a stale non-zero value is a revert rather than a no-op. The Ethereum contract rejects a `callContract` that the admin has not whitelisted via `setCallContractWhitelist`, a `reserveBalance` greater than `amount`, and any non-zero `reserveBalance` when `callContract` is `address(0)`.

Pass `address(0)` and `0`.

## Pod → Ethereum

Users call `withdraw` on the Pod bridge precompile. It debits the caller's balance, burns it on Pod, and makes the same value claimable on Ethereum - one transaction and one signature, with nothing credited to any Pod account on the way.

The call takes **no `chainId`**: exactly one chain is claimable - the one the network's bridge is configured for, served by `GET /v1/bridge/config` - so there is nothing to name wrongly, and the claim hash commits to it. Its `to` is an address on that chain, not on Pod.

A withdrawal is a solver-gated intent, like an order: it carries an auction-aligned `deadline` and settles when that batch executes. Admission deliberately does not check the balance, because pending fills can raise it before the tick runs, so an insufficient balance arrives as a refused **outcome** on `pod_withdrawals` rather than as a rejected transaction. A refusal debits nothing.

Validators sign each accepted 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 withdrawal is identified by its own transaction hash - it is always its own transaction, never a batch sub-intent - and the proof is fetched by that hash, from `GET /v1/bridge/withdrawals/by-id/{tx_hash}`, which also reports `claimable` / `pending` / `refused`. The bridge relayer watches for claimable withdrawals and submits the claims itself; the call is permissionless, so anyone - including the withdrawer - can submit the same proof if the relayer is unavailable.

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

## 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**: `amount` stays in Pod's 18 decimals, but it must be a whole number of bridged-chain units - `amount % 10^(18 - decimals) == 0`, so a multiple of 1e12 wei for a 6-decimal token. An amount with a remainder finer than that has no faithful representation on the other chain, so it is rejected before attestation rather than truncated. The claim itself carries the converted amount, and the per-token limits are read in the bridged chain's decimals.

`tx.value` is always `0` on a withdraw, native token included: the balance is debited internally, so nothing rides along with the transaction. Withdrawals are gas-exempt for the same reason - an account funded entirely over the bridge holds no Pod-side gas balance, so charging a fee would make the withdrawal that empties a balance unsubmittable.

## 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.

Both proof surfaces handle this automatically - they return 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.

The per-token minimum and maximum are also enforced on Pod, before a withdrawal is attested - `GET /v1/bridge/config` serves them, in the bridged chain's decimals, alongside the bridged chain's id and bridge contract address. The rolling daily claim cap is not: it lives on the other chain, so a claim submitted once the cap is exhausted reverts while the funds have already left Pod. It becomes claimable again when the window rolls, and the proof stays valid in the meantime.

## 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.

## Native Markets

Native markets are accessed through the Market precompile. Funds arrive on Pod through the [native bridge](/documentation/core/native-bridge), which credits the market balance directly, and traders then 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** - deposits are credited first, so the 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. **Transfers** - account-to-account transfers are applied after matching, so a debit sees the tick's settled fills.
6. **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, that a transfer's recipient can withdraw what it received within that same batch, and that withdrawals only execute after all positions have been settled.

The two ends of the batch cross the network boundary and the middle does not. A deposit enters only from the bridge; an accepted withdrawal leaves Pod entirely - the balance is burned and becomes claimable on the chain the bridge is configured for, rather than moving to another balance on Pod. A [`transfer`](https://docs.v2.pod.network/api-reference/applications-precompiles/orderbook) stays put: both sides are market balances on this ledger.

Neither transfers nor withdrawals have their balance checked at admission, because pending fills can raise it before the batch executes. One the balance does not cover at execution is refused - nothing is debited and the trader can resubmit. See [Native Bridge](/documentation/core/native-bridge) for the claim flow and the [Bridge precompile reference](https://docs.v2.pod.network/api-reference/applications-precompiles/bridge) for the withdraw call itself.

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.

## Navigating the Docs

* [Order Book](/documentation/markets/orderbook) - the enshrined CLOB, order types, matching, and market data
* [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` / `transfer` calls target this address (funds enter and leave the network through the [bridge precompile](https://docs.v2.pod.network/api-reference/applications-precompiles/bridge) instead) — 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.

### Execution flags

Beyond its type, an order carries a small set of execution properties, submitted as the `flags` bitfield on `submitOrder`:

| Flag          | Effect                                                                                                                         |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `REDUCE_ONLY` | The order may only reduce the submitter's existing position. Perpetual markets only.                                           |
| `IOC`         | Immediate-or-cancel: whatever does not match in the order's batch is cancelled rather than resting. Market orders must set it. |
| `POST_ONLY`   | Add-liquidity-only — see below.                                                                                                |

A flag bit that a node does not recognise is rejected rather than ignored, so an order never executes with a property dropped from it. Bit values and the encoding rules are in the [Orderbook precompile reference](https://docs.v2.pod.network/api-reference/applications-precompiles/orderbook).

### Post-only

A post-only order is guaranteed to add liquidity rather than take it. Under frequent batch auctions that guarantee has to be stated against the batch, not against the book at arrival: every intent in a batch is matched simultaneously, so two orders that arrive in the same batch and match each other are both takers, however the book looked when either was submitted. Asking "does it cross right now?" would therefore not be enough to guarantee anything.

So the rule is:

> A post-only order may not trade in the batch that admitted it. From the next batch onwards it is an ordinary resting maker.

What follows from it:

* A post-only order that would have traded in its admitting batch is removed from the book instead. The removal is terminal and never partial, and it is reported under its own status, `post_only_refused`, so it is distinguishable from a cancel the trader sent.
* One that would not have traded in that batch simply rests, and matches from the next batch on.
* Two post-only orders admitted in the same batch that cross only each other are both refused: neither took resting liquidity, but each would have taken from the other.
* If a same-price order with better queue priority absorbs the crossing liquidity first, the post-only order behind it rests untouched — it never had the chance to take.
* Amending an order in a way that re-queues it (a new price, or a larger size) makes it a newcomer again for that batch; an amendment that only shrinks the order keeps its queue priority and goes on matching.

A post-only order is therefore a *guaranteed maker* under a fee schedule that classifies maker and taker by the batch an order was included in: the classification cannot be gamed by an order that both arrived and traded in the same batch.

## 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 four-case k-double-auction rule (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 first k buyers and sellers trade at a single clearing price p.

Only limit orders determine p; market orders match but never set the price. Four prices bound the clearing range — the marginal matched limit sell and buy (ps, pb) and the best unmatched limit buy and sell left on the book (b', s'). The range is \[max(ps, b'), min(pb, s')], skipping any of the four that don't exist, and p is chosen by case:

* Both a lower and an upper bound exist — p is their midpoint.
* Only one side has a limit bound — p is that bound. For example, market buys that fill against every resting limit sell clear at the highest matched sell price.
* No limit order bounds the price at all (e.g. both sides matched only market orders) — p falls back to the previous batch's clearing price; on perpetual markets, to the mark price if there is no previous clearing. A spot market with no previous clearing price cannot price the batch: it emits no fills and the orders rest until a clearing price exists (IOC orders still expire at the end of their batch).

Finally, p is clamped to the prices of the matched orders themselves, market orders included: every matched seller receives at least their order's price and every matched buyer pays at most theirs, so no order ever fills worse than its own price.

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. When a price level is only partially filled at the margin, orders admitted to the book in an earlier batch fill first, and the order ID breaks ties between orders admitted in the same batch, so every node allocates the marginal fill identically.

### 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 move or 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.


# Oracle

Every perpetual market needs a reference price for the underlying asset. It anchors the [mark price](/documentation/markets/perpetuals#mark-price), drives [funding](/documentation/markets/perpetuals#funding), and through them decides margin and liquidation. Pod calls this reference the **oracle price**.

Spot markets do not use an oracle price.

## Multiple oracle sources

A single price feed is a single point of failure: if it goes down or reports a wrong price, every market that depends on it is affected. So Pod does not rely on one feed. Each perp market is configured with one or more independent oracle sources, and on every batch the network receives the latest observation from each of them:

| Field        | Meaning                                                             |
| ------------ | ------------------------------------------------------------------- |
| Price        | The price the source reported                                       |
| Publish time | When the source published that price                                |
| Source       | Which source it came from: its position in the market's oracle list |

Each source carries a [weight](#source-weights). The order in which observations arrive does not matter.

### Dropping stale observations

A feed that stops updating does not necessarily go quiet: its last price can keep being delivered long after it stopped being true. So before any observation is used, its age is checked against the batch's deadline:

```
age = batch_deadline − publish_time
```

An observation is **fresh** if its age is at most the staleness threshold (30 seconds), and **stale** otherwise. Stale observations are ignored for that batch.

Age is measured against the batch deadline, not the wall clock, so every validator reaches the same verdict for the same batch.

### Combining the fresh observations: the weighted median

The oracle price for the batch is the **weighted median** of the fresh observations. If no observation is fresh, the market switches to the [internal price](#internal-price).

| Fresh observations | Oracle price for the batch                                         |
| ------------------ | ------------------------------------------------------------------ |
| One or more        | The weighted median of the fresh observations                      |
| None               | The [internal price](#internal-price), derived from the order book |

Each fresh price counts as many times as its source's weight. Sort the fresh prices, then walk up from the lowest, adding up their weights:

* The first price where the running weight passes **more than half** of the total fresh weight is the oracle price.
* If the running weight lands **exactly on half**, the oracle price is the average of that price and the next one.

With every weight at 1 this is the plain median:

* **Odd count:** the middle value. `99.9, 100.0, 100.2` → `100.0`
* **Even count:** the average of the two middle values. `99.9, 100.0, 100.2, 100.4` → `(100.0 + 100.2) / 2 = 100.1`
* **One observation:** that observation's price.

With weights:

| Fresh prices (weight)     | Counted as              | Oracle price                |
| ------------------------- | ----------------------- | --------------------------- |
| 98 (1), 100 (2), 104 (2)  | 98, 100, 100, 104, 104  | 100                         |
| 100 (1), 102 (1), 110 (3) | 100, 102, 110, 110, 110 | 110 (the plain median: 102) |
| 100 (2), 104 (2)          | 100, 100, 104, 104      | 102 (exactly half: average) |

The order the observations arrive in does not change the result.

### Source weights

Each source in a market's oracle list has a weight, a whole number from 1 to 65,535. It is written as an `N*` prefix on the source in the market's oracle spec; no prefix means weight 1:

```
2*PythPro/NVDA,Nobi/Equity:US:NVDA/USD    ← PythPro counts twice, Nobi once
```

Weights are set when the market is created and changed with `updateMarketOracle`, like the sources themselves. A list cannot name the same source and asset twice: `PythPro/BTC,2*PythPro/BTC` is rejected. A change applies from the batch after the one it lands in.

A stale source leaves the vote with its whole weight, so the weighted median is taken over the fresh sources only. In the first example above, if the weight-2 source at 100 goes stale, the fresh prices are `98, 104, 104` and the oracle price is 104.

### Why a median and not an average

An average moves with every source, including a broken one. The median does not depend on how far off an outlier is.

```
prices  = 100.0, 100.2, 150.0
average = 116.7    ← one bad source moves it 16%
median  = 100.2    ← same whether the bad price is 150 or 1,000,000
```

### How many bad sources a market can tolerate

* **Dead sources:** any number. They go stale and drop out. One fresh source is enough to keep a real price.

### Example: sources failing over time

A market with three sources, A, B and C, all weight 1. Each row is a batch:

| Batch | A             | B             | C            | Fresh | Oracle price        |
| ----- | ------------- | ------------- | ------------ | ----- | ------------------- |
| 1     | 100.0         | 100.2         | 99.9         | 3     | 100.0 (median of 3) |
| 2     | 100.1         | 100.3         | 99.9 (stale) | 2     | 100.2 (median of 2) |
| 3     | 100.2         | 100.3 (stale) | 99.9 (stale) | 1     | 100.2 (only A)      |
| 4     | 100.2 (stale) | 100.3 (stale) | 99.9 (stale) | 0     | Internal price      |
| 5     | 100.2 (stale) | 100.5         | 99.9 (stale) | 1     | 100.5 (back on B)   |

* Batches 2 and 3: as sources go stale they drop out, and the price keeps coming from whichever sources are still fresh.
* Batch 4: every source is stale, so the market switches to the [internal price](#internal-price), anchored to the last median (100.2).
* Batch 5: as soon as one source is fresh again, the next batch returns to the median. There is no waiting period.

The last median computed from fresh observations is always remembered. It becomes the **anchor** for the internal price if every source goes stale.

## Internal price

When every source for a market is stale, Pod does not keep trading against the last price it saw. It derives an **internal price** from what the market's own order book is willing to pay, anchored to the last real price and bounded around it.

It works like this:

1. **Start from the last real price.** This is the last price computed from fresh sources: the **anchor**.
2. **Look at the order book.** The **book price** is where the book is willing to trade. If the impact bid has moved above the anchor, the book price is the impact bid. If the impact ask has moved below the anchor, it is the impact ask. If the anchor still lies between the impact bid and the impact ask, the book price is the anchor itself.
3. **Blend the two, giving the book more weight over time.** The book's weight starts at 0 when the sources go stale and grows steadily to 1 over 30 minutes.
4. **Keep the result within a corridor around the anchor.** See [The corridor](#the-corridor).

```
book_weight    = min(time_since_last_fresh_price / 30 minutes, 1)
internal_price = anchor + book_weight × (book_price − anchor)
                 limited to anchor × (1 ± w)
```

For example, suppose the anchor is 100 and the book price is 102:

| Time without a fresh source | Book weight | Internal price |
| --------------------------- | ----------- | -------------- |
| 0 minutes                   | 0           | 100            |
| 15 minutes                  | 0.5         | 101            |
| 30 minutes or more          | 1           | 102            |

So the price does not jump when the sources go stale. It moves gradually toward the book, and after 30 minutes the market prices itself from its own book, still within the corridor.

{% hint style="info" %}
The book price is measured at a fixed trade size, the market's impact notional: it is the price a trade of that size would get. On a book with enough depth, a single small order does not set it on its own (see [limitations](#trust-model-and-limitations) for thin books). These are the same impact prices [funding](/documentation/markets/perpetuals#funding) uses. An empty side of the book has no effect.
{% endhint %}

Internal pricing has no time limit. A market can run on it indefinitely, for example across a weekend when the underlying's venue is closed.

### The corridor

The internal price can never move more than a fraction `w` away from the anchor, in either direction. `w` is derived from the market's margin ratios:

```
w = (initial_margin_ratio − maintenance_margin_ratio) / (1 + maintenance_margin_ratio)
```

This is the largest price move that a position opened at maximum leverage can survive without falling below maintenance margin.

So **the internal price alone never liquidates anyone.** A position opened at maximum leverage at the last real price keeps its margin ratio at or above maintenance for as long as the market runs on internal pricing. Lower-leverage positions keep more slack.

{% hint style="info" %}
**Example:** on a 10× market, `initial_margin_ratio = 10%` and `maintenance_margin_ratio = 5%`, so `w = 0.05 / 1.05 ≈ 4.76%`. With a last real price of 100, the internal price stays within roughly 95.24 to 104.76.
{% endhint %}

The guarantee covers the oracle price, but liquidation is checked against the [mark price](/documentation/markets/perpetuals#mark-price), which also takes input from the order book. Over a long outage, a persistently displaced book can move the mark beyond the corridor. The mark's per-batch clamp slows this down but does not prevent it. Funding paid during an outage also reduces equity independently of the corridor.

### Funding during an outage

[Funding](/documentation/markets/perpetuals#funding) is computed against the internal price. As the internal price converges on the book, the gap between the book and the oracle price shrinks, and funding falls toward zero. It does not keep accruing against a frozen price.

## New markets

A perp market comes into existence on the first price it receives. If every observation in that first batch is already stale, there is no previous real price and no book to derive one from. In that case the market starts from the plain median of all its observations, stale or not and ignoring weights, and uses that value as its first anchor.

## Trust model and limitations

* **Prices are delivered by the solver.** Observations, their publish times, and their source tags come from the [solver](/documentation/markets/orderbook#solver) and are not independently verified on-chain. The staleness check protects against honest failures, such as a dead connection, a source outage, or a halted venue. It does not protect against a solver that deliberately supplies wrong prices or timestamps.
* **Thin books can be moved.** While a market runs on internal pricing, a single order on a thin side of the book can shift the impact price and so the internal price. Three things limit the effect: the book's small weight early in an outage, the corridor, and the mark price's per-batch clamp.
* **Liquidation orders count.** The impact price includes liquidation orders resting in the book, because they are real liquidity a batch can fill against. During an outage, a chain of liquidations can therefore move the internal price.
* **External mid prices are not checked for staleness.** The external mid prices that feed the [mark price](/documentation/markets/perpetuals#mark-price) are used as delivered.

## Parameters

| Parameter           | Value                                                                                | Scope                  |
| ------------------- | ------------------------------------------------------------------------------------ | ---------------------- |
| Staleness threshold | 30 seconds                                                                           | Network-wide           |
| `tau`               | 30 minutes                                                                           | Network-wide           |
| Corridor `w`        | `(initial_margin_ratio − maintenance_margin_ratio) / (1 + maintenance_margin_ratio)` | Per market, derived    |
| Oracle sources      | One or more                                                                          | Per market             |
| Source weight       | 1 to 65,535, default 1                                                               | Per source, per market |


# 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 and triggers, 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 cannot move a single unit of it to another account.
* **Hot/cold key separation.** The master can be a cold key that signs only the delegation message and remains the only key able to move funds at all; 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/update target | master                                   |
| `order_id`                                          | keyed on the delegate (the tx signer)    |
| Transaction signer, nonce, account lock             | delegate                                 |
| Moving funds (`transfer`)                           | not delegable at all - see below         |
| 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                                                                                       |
| `submitBatch`                                                                                                | ✅          | every sub-intent is owned by the master; the certificate must cover the batch's `deadline` |
| `transfer`                                                                                                   | ❌          | rejected as the inner call **and** inside a wrapped `submitBatch`                          |
| `submitSolutions`, `createMarket`, `disableMarket`, `settleMarket`, `updateMarketOracle`, 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`.

**Why `transfer` is excluded.** Elsewhere the envelope makes a call safe by pinning its recipient to the master. That does not work here: a transfer to the master *by* the master is a self-transfer, which the protocol rejects because it burns a nonce and moves nothing. The only alternative — letting the delegate name the recipient — would make a leaked delegate key worth exactly as much as a leaked master key for the whole spendable balance, so the envelope is refused outright instead. The check runs at the innermost layer, so nesting a transfer inside a delegated `submitBatch` does not slip past it.

## 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.** Nothing a delegate can sign moves funds to another account: `transfer` is refused, both directly and inside a wrapped `submitBatch`. A leaked delegate key can trade the master's balance but never take 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 bridge deposits, incoming transfers and incoming funding, and decreases on withdrawals, outgoing transfers and outgoing funding:

```
cash = deposits − withdrawals + transfers_in − transfers_out + 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
```

A withdrawal or transfer must leave a **transfer margin** behind: the larger of the initial margin and a fixed fraction of the open notional, `transfer_margin_ratio` (a network parameter, 10% by default). Equity counts unrealized PnL, so it is withdrawable too; the withdrawal can take `cash` negative.

```
withdrawable_cash = max(0, equity − max(locked_margin, transfer_margin_ratio × notional))
```

Without open positions both terms are zero, so the whole non-negative equity is withdrawable.

That is the ceiling the account imposes, and it bounds transfers to other accounts as well as withdrawals. What actually *leaves the network* is further bounded by the bridge: a withdrawal is claimed on another chain, so its amount must be a whole number of that chain's token units and must fall inside the token's `[min, max]`. See the [Bridge precompile reference](https://docs.v2.pod.network/api-reference/applications-precompiles/bridge) for the exact rules.

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.


# 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.

A bridge withdrawal follows this rule: it is always its own transaction, so that transaction's hash is its identity — what its outcome is reported under, and what its claim proof is fetched by at `GET /v1/bridge/withdrawals/by-id/{tx_hash}`. Withdrawals made before this design carry a computed id in the same field, served by the same lookups; only current ones are real transaction hashes, so do not feed a historical value to `eth_getTransactionByHash`.

**Exception — orderbook orders and transfers.** A resting order is identified by a computed `order_id = keccak256(abi.encode(signer, nonce, sequence))`, **not** its `submitOrder` tx hash, because one transaction can carry several intents. A `transfer` is keyed the same way, as a `transfer_id`, and that is what its outcome is reported under on `pod_transfers`. 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. Its `flags` argument carries the order's execution properties as a bitfield — pass `0` for a plain resting limit order.

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.

Submit a limit order with price, size, deadline, and TTL. The account needs a balance of the quote token to cover it.

{% 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, uint8 flags)",
];

// `flags` bits — OR together the ones you want, 0 for a plain resting limit order
const REDUCE_ONLY = 0x01; // perp only
const IOC = 0x02;
const POST_ONLY = 0x04;

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;

// 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,
  0,        // flags — 0 rests on the book; POST_ONLY to guarantee you add liquidity
);
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::{Address, 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,
            uint8 flags
        ) public;
    }
}

// `flags` bits — OR together the ones you want, 0 for a plain resting limit order
const REDUCE_ONLY: u8 = 0x01; // perp only
const IOC: u8 = 0x02;
const POST_ONLY: u8 = 0x04;

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;

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

// 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,
        0,            // flags — 0 rests on the book; POST_ONLY to guarantee you add liquidity
    )
    .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 %}

## Guarantee that you add liquidity

Pass `POST_ONLY` (`0x04`) in `flags` to make the order a guaranteed maker. It rests on the book as usual, but it may not trade in the batch that admitted it: if it would have taken liquidity in that batch, it is removed instead and reported with the terminal status `post_only_refused`. From the next batch onwards it matches like any other resting order.

```typescript
const tx = await orderbook.submitOrder(
  orderbookId, size, price, orderType, deadline, ttl,
  POST_ONLY,
);
```

`POST_ONLY` cannot be combined with `IOC`, and cannot be set on a market order — both are rejected. See [Post-only orders](/guides-references/references/applications-precompiles/orderbook#post-only-orders) for the exact rules, including what happens when two post-only orders cross each other and how amendments re-arm the guarantee.


# 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 balance 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.

Submit a limit order for the perp market (e.g. NVDA-USD). The account needs a USD balance to cover the margin the market computes.

{% 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, uint8 flags)",
];

// `flags` bits — OR together the ones you want, 0 for a plain resting limit order
const REDUCE_ONLY = 0x01;
const IOC = 0x02;
const POST_ONLY = 0x04;

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;

// 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,
  0,        // flags — REDUCE_ONLY to only close, POST_ONLY to guarantee you add liquidity
);
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 {
        enum OrderType { Limit, Market }
        function submitOrder(
            bytes32 orderbookId, int256 size, uint256 price,
            OrderType orderType, uint128 deadline, uint128 ttl,
            uint8 flags
        ) public;
    }
}

// `flags` bits — OR together the ones you want, 0 for a plain resting limit order
const REDUCE_ONLY: u8 = 0x01;
const IOC: u8 = 0x02;
const POST_ONLY: u8 = 0x04;

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;

// 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,
        0,            // flags — REDUCE_ONLY to only close, POST_ONLY to guarantee you add liquidity
    )
    .send().await?;
println!("Perp order tx: {:?}", tx.tx_hash());
```

{% endtab %}
{% endtabs %}

## Closing a position

Submit an opposite-sided order with `REDUCE_ONLY` (`0x01`) set in `flags`. 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.

## Market-making: guarantee that you add liquidity

Set `POST_ONLY` (`0x04`) in `flags` to quote as a guaranteed maker. The order rests on the book as usual, but it may not trade in the batch that admitted it: if it would have taken liquidity in that batch, it is removed instead and reported with the terminal status `post_only_refused`. From the next batch onwards it matches like any other resting order.

```typescript
// A post-only, reduce-only quote: it can only add liquidity, and only close exposure
const tx = await orderbook.submitOrder(
  nvdaPerpId, size, price, orderType, deadline, ttl,
  POST_ONLY | REDUCE_ONLY,
);
```

`POST_ONLY` cannot be combined with `IOC`, and cannot be set on a market order — both are rejected. It also cannot be requested on a TP/SL trigger, since `submitTrigger` has no `flags` argument. See [Post-only orders](/guides-references/references/applications-precompiles/orderbook#post-only-orders) for the exact rules, including what happens when two post-only orders cross each other and how amendments re-arm the guarantee.

{% 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, uint8 flags)",
  "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)",
];

// `submitOrder` flags bits. `submitTrigger` keeps its two booleans and has no
// flags argument, so a trigger's synthetic order cannot be post-only.
const REDUCE_ONLY = 0x01;
const IOC = 0x02;
const POST_ONLY = 0x04;

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, 0 /* flags */,
]);

// 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,
            uint8 flags
        ) 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,
    // flags — 0 rests on the book; POST_ONLY (0x04) to guarantee you add liquidity
    deadline, ttl, flags: 0,
}.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 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, uint8 flags)",
  "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, 0 /* flags */,
]);

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,
            uint8 flags
        ) 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, flags: 0,
}.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) 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 delegate can trade the master's balance but cannot move it: `transfer` is rejected as a delegated call and inside a delegated `submitBatch`, so moving funds remains the master key's alone — see [Transfers between accounts](/guides-references/references/applications-precompiles/orderbook#transfers-between-accounts).
* **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 and serves its market data two ways, on the same host as the JSON-RPC endpoint:

* **REST** under `/v1` for one-shot reads: markets, books, candles, solutions, and an account's orders and fills. See the [REST reference](/guides-references/references/rest) for every route.
* **WebSocket subscriptions** (`eth_subscribe`) that push what changed after every auction tick.

For every stream, seed over REST, then subscribe with `since` set to the solution time (µs) the REST response was current at. The node replays every tick after that point, then streams live, with no gap or duplicate.

```javascript
const REST = "https://rpc.podtestnet.dev/v1";
const orderbookId = "0x0000000000000000000000000000000000000000000000000000000000000001"; // NVDAx-USD spot
const get = async (path) => {
  const res = await fetch(`${REST}${path}`);
  if (!res.ok) throw new Error(`${path}: ${res.status} ${await res.text()}`);
  return res.json();
};
```

Amounts are 1e18-scaled, in two encodings. `/clob/markets`, `/clob/markets/stats` and `/clob/backstop-transfers` use decimal strings. Candles, orders, fills, solutions, positions and balances encode unsigned prices and amounts as `0x` hex strings, and signed values as decimal strings. Orderbook snapshots key their price levels by decimal strings and give each level's volume in hex. Timestamps ending in `_us` are microseconds.

## Markets

```javascript
// Static configuration: name, tokens, fees, tick precision, lot size, status, ...
const markets = await get("/clob/markets");

// Live 24h statistics, plus the solution time they are current at.
const { solution_now, markets: stats } = await get("/clob/markets/stats");
// stats: [{ orderbook_id, last_clearing_price, volume_24h, high_24h, low_24h, mark_price, ... }]
```

Optional stats fields (`last_clearing_price`, `high_24h`, the perp fields, ...) are omitted until the market has the data.

## Orderbook

```javascript
const book = await get(`/clob/orderbook/${orderbookId}?depth=20`);
// { orderbook_id, buys: { "<price>": { volume } }, sells: { ... },
//   buys_count, sells_count, clearing_price, timestamp, ... }
```

`depth` keeps the best N price levels per side (minimum 1; omit it for the whole book). Both sides are keyed by price in ascending order: the best bid is the last key of `buys`, the best ask the first key of `sells`. `buys_count`/`sells_count` count the full book even when truncated. `timestamp` is the deadline (µs) of the batch the snapshot was taken after. The route answers 404 until a batch has cleared that orderbook since the node started.

## Candles

```javascript
const nowSecs = Math.floor(Date.now() / 1000);
const { candles, range, solution_now_us } = await get(
  `/clob/candles/${orderbookId}?resolution=1m&from=${nowSecs - 3600}&to=${nowSecs}`
);
// candles: [{ timestamp, open, high, low, close, volume, quote_volume }], newest first

// Start of the bucket still forming at solution time; build it from pod_candles.
const bucketUs = 60_000_000; // 1m
const formingStartUs = Math.floor(solution_now_us / bucketUs) * bucketUs;
```

`resolution` is one of `1m`, `5m`, `15m`, `30m`, `1h`, `4h`, `1d`, `1w`, `1M`. `from`/`to` are seconds and select `[from, to)`; `limit` caps the page at up to 500 candles. Only closed bars are returned. To page further back, request again with `to = range.from_us / 1e6`.

Build the forming bar, including the trades it already holds, from `pod_candles` ticks. Subscribe with `since: formingStartUs - 1`: `since` replays every tick strictly after it, so the whole forming bucket arrives before live ticks. The node keeps 16,384 ticks for replay (about 2.3 hours at the 500 ms cadence), enough for a forming bucket of up to 1h. For `4h` and coarser, first fill the forming bar from closed `1h` candles over `[formingStartUs, start of the current hour)`, then replay ticks from the start of the current hour.

## Solutions

```javascript
const { solutions } = await get(`/clob/solutions?orderbook=${orderbookId}&limit=50`);
// [{ orderbook_id, timestamp, clearing_price, mark_price, volume, oracle_price, funding_rate, ... }]
```

One row per orderbook per auction tick, newest first. `limit` counts ticks (1 to 200); page back with `until_us` (exclusive) set to the oldest `timestamp` you hold, or bound the window from below with `since_us` (inclusive).

## Account orders and fills

```javascript
const page = await get(`/clob/orders/${walletAddress}?limit=50`);
// { orders: [...], next_cursor, total_count, solution_now }
// next page: get(`/clob/orders/${walletAddress}?limit=50&cursor=${page.next_cursor}`)

const { fills } = await get(`/clob/fills/${walletAddress}?orderbook=${orderbookId}&from_us=${Date.now() * 1000 - 3600e6}`);
// [{ orderbook_id, order_id, price, base_amount, quote_amount, fee, timestamp, ... }]
```

Orders come newest first; `next_cursor` is `null` on the last page. Fills take `from_us`/`to_us` (`to_us` defaults to now) and up to 500 rows.

## Stream live updates

Open one WebSocket to the RPC host and subscribe once per stream. Each subscription confirms with an id; updates then arrive as `eth_subscription` notifications carrying that id.

```javascript
const ws = new WebSocket("wss://rpc.podtestnet.dev");
const handlers = new Map(); // request id -> handler, then subscription id -> handler
let nextId = 1;

function subscribe(channel, params, onUpdate) {
  const id = nextId++;
  handlers.set(id, onUpdate);
  ws.send(JSON.stringify({ jsonrpc: "2.0", id, method: "eth_subscribe", params: [channel, params] }));
}

ws.onmessage = ({ data }) => {
  const msg = JSON.parse(data);
  if (msg.id !== undefined) {
    if (msg.error) throw new Error(`subscribe failed: ${msg.error.message}`);
    handlers.set(msg.result, handlers.get(msg.id)); // subscription confirmed
    handlers.delete(msg.id);
  } else if (msg.method === "eth_subscription") {
    const { subscription, result, error } = msg.params;
    if (error) return console.warn("subscription closed", error); // resubscribe with error.data.resume_since
    handlers.get(subscription)?.(result);
  }
};

ws.onopen = () => {
  const ids = [orderbookId];
  // Delta channels: replay every tick after `since`, then live. Use the
  // solution-time watermark (`solution_now`) as `since`; it stays inside the
  // replay buffer even for a quiet book.
  subscribe("pod_orderbook", { orderbook_ids: ids, depth: 20, since: solution_now }, (snapshot) => {});
  subscribe("pod_candles", { orderbook_ids: ids, since: formingStartUs - 1 }, (tick) => {
    // { orderbook, timestamp_us, price, volume }: fold into the forming bar
  });
  subscribe("pod_orders_v2", { bidder: walletAddress, since: page.solution_now }, (frame) => {
    // one frame per orderbook per batch: orders created in it, plus events (fills, cancels, ...)
  });
  // State channel: with `since`, sends every subscribed market's current entry first, then one
  // entry per market cleared (or changing status) in each tick.
  subscribe("pod_markets", { orderbook_ids: ids, since: solution_now }, (entry) => {});
};
```

* `pod_orderbook` pushes a full snapshot (the REST shape) for each subscribed book cleared in a tick.
* `pod_candles` pushes one clearing-price tick per cleared book.
* `pod_orders_v2` streams order activity; `bidder` narrows it to one account and `bidders` to up to 64. See the `eth_subscribe` entry in the [JSON-RPC reference](/guides-references/references/json-rpc) for the frame format.
* `pod_markets` pushes the `/clob/markets/stats` entry plus the market's lifecycle (`status`, and `live_at_us`, `disable_at_us`, `settlement_price` once set).

If `since` is older than the node's replay buffer, the subscribe call fails with `-32602` `since too old`: seed again over REST and resubscribe with the new watermark. A subscription the server ends itself (a slow consumer, a node shutdown) arrives as a notification carrying `error`; see [JSON-RPC Errors](/guides-references/references/json-rpc-errors#subscription-close-notifications) for how to resume.


# 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).

{% hint style="info" %}
**Bridging in is how you fund a Pod account, and it is a single step.** The deposit is credited straight to the recipient's balance — available for trading. The Orderbook precompile has no `deposit`.
{% endhint %}

{% hint style="warning" %}
**`deposit` may be relayer-only on the deployment you are targeting.** The bridge contract has a Private mode in which only a permissioned relayer deposits on users' behalf; `deposit` is gated on the contract being Public and otherwise reverts with `ContractPaused`. If your own call reverts that way, the deposit goes through the operator's relayer rather than directly.
{% endhint %}

## Deposit

Deposit tokens on Ethereum; the full amount is credited to the recipient's balance on Pod.

### Steps

1. Call `deposit(token, amount, podRecipient, callContract, reserveBalance, permit)` on the Ethereum bridge contract. Set `callContract` to `address(0)` and `reserveBalance` to `0` — see the note below on why.
2. Once the deposit is finalized on Ethereum, Pod validators automatically credit the balance on Pod. No claim is needed, and you send no transaction on Pod.

{% 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();
// Credited to podRecipient's balance once the deposit is finalized
// on Ethereum, scaled up to Pod's 18 decimals. Read it back with
// balanceOf(token, account) on the orderbook precompile.
```

{% 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?;
// Credited to pod_recipient's balance once the deposit is finalized
// on Ethereum, scaled up to Pod's 18 decimals. Read it back with
// balanceOf(token, account) on the orderbook precompile.
```

{% endtab %}
{% endtabs %}

## `callContract` and `reserveBalance`

These two parameters used to split a deposit between a Pod account and a contract on Pod. **They no longer route anything on Pod.** Every deposit is credited whole to the recipient's balance, because that is now the only balance there is to credit. The values are still carried through to the Pod-side `DepositApplied` event so the two chains reconcile, but they change nothing about where the funds land.

They are still **validated on Ethereum**, so a stale non-zero value is a revert rather than a harmless no-op. The Ethereum contract rejects:

* a `callContract` the admin has not whitelisted via `setCallContractWhitelist` (`CallContractNotWhitelisted`),
* a `reserveBalance` greater than `amount` (`AmountBelowReserve`),
* any non-zero `reserveBalance` when `callContract` is `address(0)` (`InvalidReserveBalance`).

Pass `address(0)` and `0`.

## Amounts and decimals

`amount` is in the **Ethereum token's** units — `1000000` for 1 USDC, not `1e18`. The bridge scales it up to Pod's 18 decimals when it credits the balance, so 1 USDC deposited reads back as `1e18` from `balanceOf`.

The bridge contract enforces a per-token minimum and a rolling daily cap, and the token must be whitelisted by the bridge admin before it can be deposited at all.

## Next steps

* Trade the balance — see [Place a spot order](/guides-references/guides/place-a-spot-order) or [Place a perpetual order](/guides-references/guides/place-a-perpetual-order).
* Send some of it to another Pod account with the orderbook precompile's [`transfer`](/guides-references/references/applications-precompiles/orderbook#transfers-between-accounts).
* Take it off Pod again with [Bridge from Pod](/guides-references/guides/bridge-from-pod).


# Bridge from Pod

This guide walks through moving tokens off Pod: `withdraw` on the bridge precompile debits your balance, burns it on Pod, and makes the same value claimable on the bridged chain. For background on how the bridge works, see [Native Bridge](https://docs.v2.pod.network/documentation/native-bridge); for the full call reference, see the [Bridge precompile](/guides-references/references/applications-precompiles/bridge).

## Before you start

Read `GET /v1/bridge/config` on any full node. It names the bridged chain, the contract the claim is submitted to, and the per-token rules — there is no `chainId` parameter to pass, and this list is the only source of the Pod-token → bridged-chain-token mapping:

```json
{
  "claim_chain_id": 42161,
  "source_contract": "0x…",
  "version": 1,
  "tokens": [
    { "pod_token": "0x…", "l1_token": "0x…", "decimals": 6, "min": "0xf4240", "max": "0x…" }
  ]
}
```

## Amounts and decimals

`amount` is in **Pod's 18 decimals** — the units the balance is denominated in — and must be a **whole number of bridged-chain units**: `amount % 10^(18 - decimals) == 0`. For a 6-decimal token like USDC that means a multiple of `1e12` wei. Nothing is rounded for you; an inexact amount is rejected before attestation.

`min` and `max` from `/v1/bridge/config` are in the token's **bridged-chain** decimals and are compared against the converted amount, not the 18-decimal one you sign.

{% hint style="warning" %}
**`tx.value` must be `0`, native token included.** The balance is debited internally, so nothing rides along with the transaction. Withdrawals are also gas-exempt, so an account funded entirely over the bridge can withdraw all of it without keeping anything back for fees.
{% endhint %}

## Steps

1. Call `withdraw(token, to, amount, deadline)` on the Pod bridge precompile. `to` is an address on the **bridged chain**, and `deadline` is an auction-aligned batch deadline in microseconds, exactly like an order's.
2. Poll `GET /v1/bridge/withdrawals/by-id/{txHash}` — keyed by the withdraw transaction's own hash — until a `proof` appears. The route 404s until the withdrawal executes, a tick after admission. `pending` means the certificate is still assembling; `refused` means nothing was debited.
3. Call `claim(token, amount, to, proof, auxTxSuffix)` on the bridged chain's bridge contract. Take `amount` and `to` **from the proof response** — that amount is in the bridged chain's decimals, not the 18-decimal value you signed. Do **not** take `token` from it: the proof reports the Pod-side address, and `claim` needs the bridged-chain one, which is `l1_token` in `/v1/bridge/config`.

The bridge relayer performs step 3 for you. The call is permissionless, so submit it yourself only if the relayer is unavailable.

## Examples for withdrawing 100 USDC from Pod (6 decimals on the bridged chain)

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

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

const podProvider = new ethers.JsonRpcProvider("https://rpc.podtestnet.dev");
const claimProvider = new ethers.JsonRpcProvider(CLAIM_CHAIN_RPC); // the chain /v1/bridge/config names
const podWallet = new ethers.Wallet(PRIVATE_KEY, podProvider);
const claimWallet = new ethers.Wallet(PRIVATE_KEY, claimProvider);

const POD_BRIDGE = "0x50d0000000000000000000000000000000000001";
const POD_RPC_REST = "https://rpc.podtestnet.dev/v1";
const POD_TOKEN = "POD_TOKEN_ADDRESS"; // 0xEeee…EEeE for the native token

// From GET /v1/bridge/config — the bridged chain, its bridge contract, and the
// Pod-token -> bridged-chain-token mapping all come from here.
const config = await (await fetch(`${POD_RPC_REST}/bridge/config`)).json();
const token = config.tokens.find((t) => t.pod_token.toLowerCase() === POD_TOKEN.toLowerCase());

// Amounts are in Pod's 18 decimals and must be a whole number of bridged-chain
// units — 100 USDC is 100e18 wei here, which is a clean multiple of 1e12.
const amount = ethers.parseEther("100");
const granularity = 10n ** BigInt(18 - token.decimals);
if (amount % granularity !== 0n) throw new Error("amount is not a whole number of bridged-chain units");

// Deadlines must be an exact multiple of the 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. Withdraw. tx.value is 0 for every token, native included.
const bridge = new ethers.Contract(
  POD_BRIDGE,
  ["function withdraw(address token, address to, uint256 amount, uint128 deadline)"],
  podWallet
);
const withdrawTx = await bridge.withdraw(
  POD_TOKEN,
  claimWallet.address,       // recipient on the CLAIM CHAIN, not on Pod
  amount,
  deadlineAfter(60_000_000n)
);
const receipt = await withdrawTx.wait();

// 2. Poll for the claim proof, keyed by the withdraw tx hash. The route 404s
// until the withdrawal executes (a tick after admission), so treat a non-200 as
// "not yet". Branch on the presence of `proof`, not on `status`: a status a
// client does not recognise must never veto a certificate in the same response,
// and must mean "retry" rather than "failed".
let detail;
for (;;) {
  const res = await fetch(`${POD_RPC_REST}/bridge/withdrawals/by-id/${receipt.hash}`);
  if (res.ok) {
    detail = await res.json();
    if (detail.proof) break;
    if (detail.status === "refused") throw new Error(`refused: ${detail.withdrawal.error}`);
  }
  await new Promise((r) => setTimeout(r, 1000)); // 404, "pending", or anything unfamiliar
}

// 3. Claim. `amount` and `to` come from the proof — that amount is in the claim
// chain's decimals (100e6 here), NOT the 18-decimal value you signed. `token`
// does NOT: the proof reports the Pod-side address, so map it via l1_token.
// `proof` and `aux_tx_suffix` arrive as arrays of byte values, not hex strings.
const claimBridge = new ethers.Contract(
  config.source_contract,
  ["function claim(address token, uint256 amount, address to, bytes proof, bytes auxTxSuffix)"],
  claimWallet
);
await (await claimBridge.claim(
  token.l1_token,
  detail.proof.amount,
  detail.proof.to,
  new Uint8Array(detail.proof.proof),
  new Uint8Array(detail.proof.aux_tx_suffix)
)).wait();
```

{% endtab %}

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

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

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

    #[sol(rpc)]
    contract ClaimBridge {
        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 claim_provider = ProviderBuilder::new()
    .wallet(signer.clone())
    .on_http(CLAIM_CHAIN_RPC.parse()?); // the chain /v1/bridge/config names

let pod_token = "POD_TOKEN_ADDRESS".parse()?; // 0xEeee…EEeE for the native token
let claim_decimals = 6u32;                    // token.decimals from /v1/bridge/config

// Pod's 18 decimals, and a whole number of bridged-chain units.
let amount = U256::from(100u64) * U256::from(10u64).pow(U256::from(18));
let granularity = U256::from(10u64).pow(U256::from(18 - claim_decimals));
assert!(amount % granularity == U256::ZERO, "not a whole number of bridged-chain units");

// Deadlines must be an exact multiple of the 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. Withdraw. No chain id, and no value — the balance is debited
// internally. `deadline` is an auction-aligned batch deadline in microseconds.
let pod_bridge = PodBridge::new(
    "0x50d0000000000000000000000000000000000001".parse()?,
    &pod_provider,
);
let withdraw_receipt = pod_bridge
    .withdraw(pod_token, signer.address(), amount, deadline_after(60_000_000))
    .send().await?
    .get_receipt().await?;

// 2. Poll for the claim proof by the withdraw tx hash. The withdrawal settles a
// tick after admission, so the first attempts legitimately come back empty.
let claim_proof = loop {
    let got: Option<serde_json::Value> = pod_provider
        .raw_request(
            "pod_getBridgeClaimProof".into(),
            vec![withdraw_receipt.transaction_hash],
        )
        .await
        .ok();
    if let Some(p) = got.filter(|p| !p["proof"].is_null()) {
        break p;
    }
    tokio::time::sleep(std::time::Duration::from_secs(1)).await;
};

// 3. Claim. `amount` and `to` come from the proof: that amount is in the claim
// chain's decimals (100e6 here), not the 18-decimal value that was signed.
// `token` does NOT come from the proof — that field is the Pod-side address, so
// map it through `l1_token` in /v1/bridge/config. `proof` and `aux_tx_suffix`
// are byte arrays in JSON, not hex strings.
let bytes = |v: &serde_json::Value| -> Vec<u8> { serde_json::from_value(v.clone()).unwrap() };
let claim_bridge = ClaimBridge::new("CLAIM_CHAIN_BRIDGE_ADDRESS".parse()?, &claim_provider);
claim_bridge
    .claim(
        "CLAIM_CHAIN_TOKEN_ADDRESS".parse()?, // l1_token from /v1/bridge/config
        claim_proof["amount"].as_str().unwrap().parse()?,
        claim_proof["to"].as_str().unwrap().parse()?,
        bytes(&claim_proof["proof"]).into(),
        bytes(&claim_proof["aux_tx_suffix"]).into(),
    )
    .send().await?
    .watch().await?;
```

{% endtab %}
{% endtabs %}

## If the withdrawal is refused

Admission deliberately does **not** check your balance — pending fills can raise it before the batch executes — so a shortfall arrives as an outcome, not as a rejected transaction. Watch `eth_subscribe("pod_withdrawals", { account })`, or read `error` from the REST detail:

* `insufficient_balance` — the balance did not cover the amount when the batch executed.
* `not_included` — the solver left the intent out of the solution its deadline pointed at.

Both mean **nothing was debited** and no claim will ever exist. The nonce is spent, so retrying means a new transaction with a new hash. A client watching only the bridged chain would wait forever for an event that cannot come.

A `refused` status can also arrive with **no** `error` at all — a node whose bridge config does not cover the token records the row and signs nothing. Treat `refused` as terminal on the status alone, without requiring a reason.

{% hint style="info" %}
Anyone can submit the claim transaction — it does not need to come from the account that withdrew.
{% 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. It returns `{ hash, nonce }`, or `null` if the account is not locked.
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 target = await provider.send("pod_getRecoveryTargetTx", [wallet.address]);
if (!target) throw new Error("account is not locked");

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

{% endtab %}

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

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

#[derive(Deserialize)]
struct TargetTx {
    hash: B256,
    nonce: u64,
}

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: Option<TargetTx> = provider
    .raw_request("pod_getRecoveryTargetTx".into(), vec![account_address])
    .await?;
let target = target.ok_or("account is not locked")?;

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

{% 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

A pod block is one auction tick: its height counts ticks and its `timestamp` is the tick's deadline (in seconds). `transactions` lists the intent transactions the tick sequenced, but most header fields (`parentHash`, the roots, `logsBloom`, `miner`, `gasLimit`, `gasUsed`, …) are zero. Most `eth_` methods work as expected, but a few differ:

| RPC Method                | Ethereum                             | Pod                                                                                                                                                                                                                                                                                |
| ------------------------- | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **eth\_blockNumber**      | Returns the most recent block number | Returns the chain-tip height (hex). Before the first block it fails with `-32002` `Chain has no block yet`.                                                                                                                                                                        |
| **eth\_getBlockByHash**   | Returns block information by hash    | Returns the block, or `null` if there is none with that hash.                                                                                                                                                                                                                      |
| **eth\_getBlockByNumber** | Returns block information by number  | Returns the block, or `null` past the tip, below the oldest retained block, or before the first block. `latest`, `pending`, `safe` and `finalized` all resolve to the tip; `earliest` to the oldest retained block. Unknown tags and malformed numbers are rejected with `-32602`. |

**Timestamps are in microseconds.** Pod uses microsecond-precision Unix timestamps for transaction deadlines, TTLs and subscription cursors (`since`). Block `timestamp` is in seconds.

**Block-related fields are zeroed.** 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\")"},"status":{"type":"string","enum":["pending","active","disabled","settled"],"description":"Lifecycle status. `pending`: created, not yet trading (waiting for `live_at`\nand, for perps, a first oracle price). `active`: trading. `disabled`: halted\nat `disable_at`; every intent is refused, orders and positions stay put.\n`settled`: orders refunded and positions closed at `settlement_price`; kept\nfor history.\n"},"live_at":{"type":"integer","format":"int64","description":"Batch deadline (microseconds) from which a `pending` market may go `active`. Absent for markets that were live from genesis."},"disable_at":{"type":"integer","format":"int64","description":"Batch deadline (microseconds) of a scheduled halt. Present from the moment the `disableMarket` intent applies, i.e. throughout the notice window."},"settlement_price":{"$ref":"#/components/schemas/HexUint256","description":"Price every position was (or will be) closed at, 1e18-scaled. Present once the market is `disabled`."},"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":{"type":"string","nullable":true,"description":"Last auction clearing price (hex-encoded, quote/base with 1e18 scale). `null` until the market's first fill."},"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":{"type":"string","nullable":true,"description":"24-hour highest price (hex-encoded, 1e18). `null` until the market has a completed candle."},"low_24h":{"type":"string","nullable":true,"description":"24-hour lowest price (hex-encoded, 1e18). `null` until the market has a completed candle."},"price_change_24h":{"type":"integer","nullable":true,"description":"24-hour price change in basis points (signed JSON number; `300` = +3%). `null` until the market has a completed candle."},"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."},"min_notional":{"$ref":"#/components/schemas/HexUint256","description":"Minimum quote notional per order, hex-encoded with `1e18` scale. `0x0` means no floor. Orders below it are rejected at admission."},"maker_fee":{"type":"string","description":"Maker fee rate, a decimal fraction of the quote amount; `\"0.010000\"` is 1%."},"taker_fee":{"type":"string","description":"Taker fee rate, a decimal fraction of the quote amount; `\"0.010000\"` is 1%."},"max_leverage":{"type":"integer","description":"Maximum allowed leverage. Returned for both spot and perp markets, but only meaningful for perp."},"initial_margin":{"type":"string","description":"Initial-margin rate as the engine charges it (`1 / max_leverage`),\nhex-encoded 1e18-scaled; the maintenance rate is half of it. Use it\nrather than re-deriving from the integer `max_leverage`.\n"},"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), undivided\nand unquantized — see `funding_settling_index` for the base a\nposition's `funding_basis` uses. `null` for spot markets.\n"},"funding_settling_index":{"type":"string","nullable":true,"description":"Perp markets only. The index positions settle against: the\n`funding_index` accumulator divided by `funding_window_us` and\nquantized to the market's funding grid, as a signed decimal string\n(1e18-scaled). With a position's `funding_basis` this gives accrual\nexactly: `funding_settling_index × size − funding_basis`.\n`funding_index` is a DIFFERENT base and cannot be subtracted from a\nposition's basis. `null` for spot markets, and until the market's\nfirst perp batch after a node start.\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."},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"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"}}}}
```

## 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.\
> Both \`buys\` and \`sells\` are keyed by price in ascending order: the best bid is the last key\
> of \`buys\`, the best ask the first key of \`sells\`.\
> \
> \`depth\` is at least 1. Before the orderbook's first snapshot exists\
> (e.g. right after a node start) the call returns an invalid-params error; retry later.<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.\nBoth `buys` and `sells` are keyed by price in ascending order: the best bid is the last key\nof `buys`, the best ask the first key of `sells`.\n\n`depth` is at least 1. Before the orderbook's first snapshot exists\n(e.g. right after a node start) the call returns an invalid-params error; retry later.\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, at least 1): Maximum number of price levels to return for each side — the best `depth` levels. 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 ascending — the best bid is the last key"},"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). The window is\
> half-open, \`\[from\_ts, to\_ts)\`.\
> \
> 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). The window is\nhalf-open, `[from_ts, to_ts)`.\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 (exclusive) in microseconds. Unbounded if omitted."},"limit":{"type":"integer","description":"Maximum number of candles to return. Defaults to 500; a value above 500 is rejected."}}},"CandleResolution":{"type":"string","enum":["1m","5m","15m","30m","1h","4h","1d","1w","1M"],"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":"Base volume traded during this candle period (1e18)"},"quote_volume":{"$ref":"#/components/schemas/HexUint256","description":"Quote (USD) notional traded during this candle period, `Σ(base × clearing price)` over its ticks (1e18)"}}},"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 newest first, sorted by \`(deadline, nonce, order\_id)\` descending.\
> 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 newest first, sorted by `(deadline, nonce, order_id)` descending.\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 `\"{deadline}:{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. Clamped to `[1, 200]`; defaults to 200."},"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, fill each order's per-batch partial `fills` array. Defaults to false, and `fills` is then empty."},"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","margin_canceled","self_trade_canceled","post_only_refused","invalid"],"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- `margin_canceled`: The engine removed the order because the owner's margin capacity was exhausted\n- `self_trade_canceled`: The engine removed a resting order that was about to fill against another order of the same owner\n- `post_only_refused`: The engine removed a `post_only` order that would have taken liquidity in the batch that admitted (or re-priced) it. Distinct from `canceled` so an engine refusal can be told apart from a cancel the trader sent — see [Post-only orders](https://docs.v2.pod.network/api-reference/applications-precompiles/orderbook)\n- `invalid`: Rejected at execution and never entered the book; the reject reason travels with the status\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`. `post_only` is reported on both. 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/TimestampString","description":"Batch deadline the order was signed for (microseconds, as a decimal string)"},"end":{"$ref":"#/components/schemas/Timestamp","description":"Timestamp when order expires (microseconds)"},"included_batch":{"$ref":"#/components/schemas/Timestamp","description":"Deadline of the batch the order entered the book in, at or before `deadline`. `0` for engine-generated orders and orders indexed before this field existed."},"invalid_reason":{"type":"string","description":"Why the engine refused the order. Present only when `status` is `invalid`."},"realized_pnl":{"type":"string","description":"Perp only — aggregate realized PnL across this order's fills (signed decimal, 1e18 USD). Omitted on spot orders and on perp orders that never closed a slice."},"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, oldest first. Always present; empty unless the query sets `with_fills`."},"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},"post_only":{"type":"boolean","description":"Add-liquidity-only — the order could not trade in the batch that admitted it. Reported on\nboth market types, and **omitted when false**.\n"},"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","adl","adl_counterparty","backstop_transfer"],"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- `adl`: synthetic order recording an auto-deleveraging close, on the bankrupt account whose position was closed\n- `adl_counterparty`: synthetic order recording the same ADL close on the account that covered it\n- `backstop_transfer`: synthetic order recording a position swept to the backstop during liquidation\n"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"TimestampString":{"type":"string","pattern":"^[0-9]+$","description":"Unix timestamp in microseconds as a string"},"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); the order's own price for ADL fills."}}},"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"],"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\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":"What a withdrawal or transfer can take now (1e18 USD): `max(0, equity − max(initial_margin, transfer_margin_ratio × notional))`, where `notional` is `Σ |size| × mark` and `transfer_margin_ratio` is a network parameter (10% by default). Equity counts unrealized PnL."},"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":"`funding_settling_index × size − funding_basis` (signed, 1e18 USD). Authoritative and exact."},"funding_basis":{"type":"string","description":"The position's funding ledger, `Σ settling_index × Δsize` (signed,\n1e18 USD). Pair it with the market's live `funding_settling_index`\nto recompute `funding_accrued` exactly between snapshots.\n"},"cost_basis":{"type":"string","description":"The position's price ledger, `Σ clearing × Δsize` (signed, 1e18\nUSD). `mark × size − cost_basis` is `unrealized_pnl`, exactly.\n"},"entry_funding":{"type":"string","description":"Funding accumulator at entry, on `funding_index`'s base (undivided\nby the funding window). Truncating and approximate — the exact pair\nis `funding_basis` with `funding_settling_index`.\n"},"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 × size − cost_basis` — pure price drift (signed, 1e18 USD); funding is reported separately as `funding_accrued`."},"realized_pnl":{"type":"string","description":"Always `\"0\"`; a leg's realized PnL banks into cash when it reaches flat. The lifetime figure is the account-level `total_realized_pnl`."},"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, the account equity at that\
> moment, and the PnL the forced close realized. The terminal cash sweep that ends a backstop\
> (including one on an account with no positions left) is recorded as its own row with no\
> \`orderbook\_id\`.\
> \
> 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, the account equity at that\nmoment, and the PnL the forced close realized. The terminal cash sweep that ends a backstop\n(including one on an account with no positions left) is recorded as its own row with no\n`orderbook_id`.\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 on the terminal cash-sweep row, which belongs to no orderbook."},"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."},"eq":{"type":"string","description":"Account equity at the moment of the sweep (decimal int256, 1e18)."},"realized_pnl":{"type":"string","description":"PnL the forced close realized (decimal int256, 1e18). `0` on the terminal cash-sweep row and on rows recorded before this field existed."},"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/TimestampString","description":"Batch deadline the trigger was signed for (microseconds, decimal string)."},"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"],"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\nOmitted from an `Order` response when it is the default `none`.\n"},"TimestampString":{"type":"string","pattern":"^[0-9]+$","description":"Unix timestamp in microseconds as a string"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```

## 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."},"internal":{"type":"boolean","description":"`true` when `oracle_price` is a book-derived internal price because every oracle source was stale."}}},"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\nint256, 1e18; may be negative), undivided and unquantized. A\nposition's `funding_basis` is NOT on this base — see\n`funding_settling_index`.\n"},"funding_settling_index":{"type":"string","description":"The index positions settle against: `funding_index` divided by the\nmarket's `funding_window_us` and quantized to its funding grid\n(signed decimal int256, 1e18). `funding_settling_index × size −\nfunding_basis` is a position's `funding_accrued`, exactly. Omitted\nuntil the orderbook's first perp batch after a node start — treat\na missing value as unknown, never as zero.\n"},"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)"}}}}
```

## Get Per-Tick Solutions

> Returns the indexer's per-tick solution records: one row per orderbook per executed batch,\
> with the clearing price, volume, and (perp only) oracle, mark, funding and open-interest\
> state.\
> \
> Rows are ordered by \`timestamp\` descending, then orderbook id descending. A page holds\
> whole ticks; to page back, pass the oldest \`timestamp\` of the previous page as \`until\`.<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_getSolutions":{"post":{"tags":["Orderbook Data (ob_)"],"summary":"Get Per-Tick Solutions","operationId":"ob_getSolutions","description":"Returns the indexer's per-tick solution records: one row per orderbook per executed batch,\nwith the clearing price, volume, and (perp only) oracle, mark, funding and open-interest\nstate.\n\nRows are ordered by `timestamp` descending, then orderbook id descending. A page holds\nwhole ticks; to page back, pass the oldest `timestamp` of the previous page as `until`.\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_getSolutions"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Positional parameters:\n1. `query` (SolutionsQuery): optional `orderbook_id`, `since`, `until`, and `limit`\n","items":{"$ref":"#/components/schemas/SolutionsQuery"}}}}}}},"responses":{"200":{"description":"Object containing the solutions array","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"type":"object","properties":{"solutions":{"type":"array","items":{"$ref":"#/components/schemas/SolutionResponse"}}}},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"SolutionsQuery":{"type":"object","description":"Query parameters for ob_getSolutions. All fields optional.","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32","description":"Restrict to one orderbook; omit for every orderbook."},"since":{"$ref":"#/components/schemas/Timestamp","description":"Inclusive lower bound on the batch deadline (microseconds)."},"until":{"$ref":"#/components/schemas/Timestamp","description":"Exclusive upper bound on the batch deadline (microseconds)."},"limit":{"type":"integer","description":"Ticks per page — a tick carries one row per orderbook. Clamped to `[1, 200]`; defaults to 200."}}},"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."},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"},"SolutionResponse":{"type":"object","description":"One orderbook's record for one executed batch, as returned by `ob_getSolutions`. Perp-only fields are omitted on spot rows; replay inputs are also omitted on rows recorded before they were stored.","required":["orderbook_id","timestamp","mark_price","volume"],"properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"timestamp":{"$ref":"#/components/schemas/Timestamp","description":"Batch deadline (microseconds)."},"clearing_price":{"$ref":"#/components/schemas/HexUint256","description":"Clearing price (1e18). Omitted for a market that has never traded."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Oracle-anchored mark (1e18); `0x0` for spot."},"volume":{"$ref":"#/components/schemas/HexUint256","description":"Base volume cleared this batch (1e18)."},"oracle_price":{"$ref":"#/components/schemas/HexUint256","description":"Perp only — oracle price used this batch (1e18)."},"funding_rate":{"type":"string","description":"Perp only — funding rate this batch (signed decimal, 1e18)."},"funding_index":{"type":"string","description":"Perp only — cumulative funding accumulator after this batch (signed decimal, 1e18), undivided and unquantized; divided by `funding_window` and grid-quantized it becomes the index positions settle against."},"open_interest":{"$ref":"#/components/schemas/HexUint256","description":"Perp only — open interest (1e18 USD notional)."},"mark_best_bid":{"$ref":"#/components/schemas/HexUint256","description":"Perp only — the clean best bid the mark path read. Describes the previous batch."},"mark_best_ask":{"$ref":"#/components/schemas/HexUint256","description":"Perp only — the clean best ask the mark path read. Describes the previous batch."},"premium_ema":{"type":"string","description":"Perp only — premium EMA after the previous batch's step (signed decimal, 1e18)."},"book_median_ema":{"$ref":"#/components/schemas/HexUint256","description":"Perp only — book-median EMA after the previous batch's step. Omitted until seeded."},"impact_bid":{"$ref":"#/components/schemas/HexUint256","description":"Perp only — impact bid price funding consumed this batch."},"impact_ask":{"$ref":"#/components/schemas/HexUint256","description":"Perp only — impact ask price funding consumed this batch."}}},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"}}}}
```


# 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 account's native cash on the orderbook, in wei, floored at zero: the balance\
> bridge deposits are credited to and orders, transfers and withdrawals spend.\
> \
> The amount withdrawable now is the orderbook contract's \`withdrawableBalance(token, account)\`\
> (via \`eth\_call\`), or \`withdrawable\_cash\` from \`ob\_getPositions\`.\
> \
> 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 account's native cash on the orderbook, in wei, floored at zero: the balance\nbridge deposits are credited to and orders, transfers and withdrawals spend.\n\nThe amount withdrawable now is the orderbook contract's `withdrawableBalance(token, account)`\n(via `eth_call`), or `withdrawable_cash` from `ob_getPositions`.\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, in the standard Ethereum shape.\n`blockHash`, `blockNumber` and `transactionIndex` are set when a tick sequenced the\ntransaction into a block and null otherwise. EIP-1559 transactions carry `maxFeePerGas`,\n`maxPriorityFeePerGas`, `accessList` and `yParity`; legacy (EIP-155) ones omit them.\n","properties":{"type":{"type":"string","description":"Transaction type: `0x2` (EIP-1559) or `0x0` (legacy)."},"chainId":{"type":"string"},"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","description":"Effective gas price; for EIP-1559 transactions the `maxFeePerGas`."},"maxFeePerGas":{"type":"string"},"maxPriorityFeePerGas":{"type":"string"},"accessList":{"type":"array","items":{"type":"object"}},"input":{"type":"string"},"v":{"type":"string"},"yParity":{"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.\
> \
> \*\*Pod-specific:\*\* \`pending\` returns the next nonce to sign with, counting attested but not\
> yet finalized transactions. Every other tag (\`latest\`, \`safe\`, \`finalized\`, \`earliest\`, or a\
> block number) returns the finalized nonce. A tag that does not parse is rejected with\
> invalid params.<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.\n\n**Pod-specific:** `pending` returns the next nonce to sign with, counting attested but not\nyet finalized transactions. Every other tag (`latest`, `safe`, `finalized`, `earliest`, or a\nblock number) returns the finalized nonce. A tag that does not parse is rejected with\ninvalid params.\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): `pending` for the next nonce including in-flight transactions; any other tag or block number for the committed nonce\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\
> (order submissions, cancellations, updates, transfers) to the orderbook contract, and bridge\
> withdrawals to the bridge 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(order submissions, cancellations, updates, transfers) to the orderbook contract, and bridge\nwithdrawals to the bridge 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\n2. `skip_validation` (boolean, optional): When true, a full node skips its local pre-validation and forwards the transaction to validators as is. Default false.\n","items":{"oneOf":[{"type":"string","description":"Signed RLP-encoded transaction"},{"type":"boolean","description":"skip_validation"}]}}}}}}},"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 an account's 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 an account's 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`\n\nThe call takes only this object and runs against current state.\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","nullable":true,"description":"The transaction's position within its block (hex-encoded); null when `blockNumber` is\nnull.\n"},"blockHash":{"nullable":true,"description":"Hash of the block the transaction was sequenced in; null when it is in no block","allOf":[{"$ref":"#/components/schemas/Bytes32"}]},"blockNumber":{"type":"string","nullable":true,"description":"Block number (hex-encoded), or null when the transaction is in no block - `submitSolutions`,\nrecovery transactions, and an orderbook intent whose auction tick has not executed yet. A null\nblock is not a pending state: the receipt is final either way.\n"},"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)"},"blockHash":{"type":"string","nullable":true,"description":"Block of the emitting transaction. Set in the receipt of a transaction in a block; null in `eth_getLogs` results."},"blockNumber":{"type":"string","nullable":true,"description":"As `blockHash`."},"transactionHash":{"$ref":"#/components/schemas/Bytes32"},"transactionIndex":{"type":"string","nullable":true,"description":"As `blockHash`."},"logIndex":{"type":"string","description":"Position of the log within its transaction's logs (hex-encoded)."},"removed":{"type":"boolean","description":"Always false."}}},"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:\*\* the estimate is a table lookup. If the transaction specifies a gas\
> value, that value is returned. Otherwise the gas comes from the fixed per-contract cost\
> table, keyed by \`to\` and the call's selector: \`21000\` for a plain transfer, an unknown\
> contract, or an unknown selector; \`21000\` per inner intent for \`submitBatch\`; \`0\` for\
> exempt calls (the solver's \`submitSolutions\` and the relayer's \`processDeposits\`, matched\
> against the unauthenticated \`from\`, bridge \`withdraw\`, CLOB \`delegated\` calls, and the lock\
> contract).<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:** the estimate is a table lookup. If the transaction specifies a gas\nvalue, that value is returned. Otherwise the gas comes from the fixed per-contract cost\ntable, keyed by `to` and the call's selector: `21000` for a plain transfer, an unknown\ncontract, or an unknown selector; `21000` per inner intent for `submitBatch`; `0` for\nexempt calls (the solver's `submitSolutions` and the relayer's `processDeposits`, matched\nagainst the unauthenticated `from`, bridge `withdraw`, CLOB `delegated` calls, and the lock\ncontract).\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.\
> \
> \`fromBlock\`/\`toBlock\` are block heights (inclusive); \`latest\`, \`pending\`, \`safe\`,\
> \`finalized\` and an omitted bound mean the tip, and \`earliest\` the oldest retained block. A\
> range is clamped to the retained chain; one wholly below it or above the tip (e.g.\
> \`fromBlock = tip + 1\`) returns \`\[]\`. \`blockHash\` selects a single block.\
> \
> Rejected with invalid params: an inverted range, a range spanning more than 7,200 blocks,\
> and a query matching more than 10,000 logs.<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_getLogs":{"post":{"tags":["Ethereum Interface (eth_)"],"summary":"Get Logs","operationId":"eth_getLogs","description":"Returns an array of log objects matching the given filter criteria.\n\n`fromBlock`/`toBlock` are block heights (inclusive); `latest`, `pending`, `safe`,\n`finalized` and an omitted bound mean the tip, and `earliest` the oldest retained block. A\nrange is clamped to the retained chain; one wholly below it or above the tip (e.g.\n`fromBlock = tip + 1`) returns `[]`. `blockHash` selects a single block.\n\nRejected with invalid params: an inverted range, a range spanning more than 7,200 blocks,\nand a query matching more than 10,000 logs.\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_getLogs"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `filter` (object): Filter object with `address`, `topics`, and either `fromBlock`/`toBlock` or `blockHash`\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)"},"blockHash":{"type":"string","nullable":true,"description":"Block of the emitting transaction. Set in the receipt of a transaction in a block; null in `eth_getLogs` results."},"blockNumber":{"type":"string","nullable":true,"description":"As `blockHash`."},"transactionHash":{"$ref":"#/components/schemas/Bytes32"},"transactionIndex":{"type":"string","nullable":true,"description":"As `blockHash`."},"logIndex":{"type":"string","description":"Position of the log within its transaction's logs (hex-encoded)."},"removed":{"type":"boolean","description":"Always false."}}},"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\_activity\` — an \`ActivityFrame\`: one account's activity in one tick, as a map with one\
> &#x20; key, the tick's deadline, to its \`ActivityEntry\` list: orders, fills, modifications,\
> &#x20; terminations, refused modifications and cancels on every orderbook, and the money it moved\
> &#x20; (backstop sweeps, bridge deposits and withdrawals, transfers). The same shape as\
> &#x20; \`GET /v1/clob/activity/{account}\`. Requires \`account\` (alias \`bidder\`).\
> \- \`pod\_markets\` — a \`MarketDynamicEntry\` per orderbook carrying live market statistics\
> &#x20; (last clearing price, 24h volume/high/low, perp mark/oracle/funding/open-interest) and its\
> &#x20; lifecycle (\`status\`, \`live\_at\_us\`, \`disable\_at\_us\`, \`settlement\_price\`). Sent each tick\
> &#x20; for the orderbooks that cleared or had a lifecycle event.\
> \- \`pod\_positions\` — a \`PositionsUpdate\` (\`{ account, data }\`, where \`data\` matches\
> &#x20; \`ob\_getPositions\`) for the subscribed account, pushed for a tick that touches it: order\
> &#x20; flow on any orderbook (new, fill, cancel, expiry, modification, trigger arm/cancel/update),\
> &#x20; a backstop sweep or ADL close, a bridge deposit or withdrawal, or a transfer either way.\
> &#x20; \*\*Requires\*\* \`account\` (alias \`bidder\`).\
> \- \`pod\_triggers\` — a \`TriggersUpdate\` (the \`ob\_getTriggers\` fields plus \`account\`, at most\
> &#x20; 200 triggers) for the subscribed account, pushed for a tick that touches it, on the same\
> &#x20; rule as \`pod\_positions\`. \*\*Requires\*\* \`account\`.\
> \- \`newHeads\` — a \`BlockHeader\` per block as it is flushed, in height order, each height\
> &#x20; once. Takes no options. A subscriber that falls behind the block feed is closed with\
> &#x20; \`-32020\` and no \`resume\_since\`; resubscribe and fill the gap with \`eth\_getBlockByNumber\`.\
> \- \`pod\_withdrawals\` — an \*\*array of \`WithdrawalUpdate\`\*\*: what became of every bridge\
> &#x20; withdrawal that settled this tick — claimable on the bridged chain, or refused with\
> &#x20; the reason. Tick-level rather than per-orderbook, since a withdrawal belongs to no book, so\
> &#x20; \`orderbook\_ids\` does not apply; \`account\` narrows it to one withdrawer. A tick with no\
> &#x20; matching outcomes sends nothing at all rather than an empty array.\
> \- \`pod\_transfers\` — an \*\*array of \`TransferUpdate\`\*\*: what became of every account-to-account\
> &#x20; transfer that settled this tick. The sibling of \`pod\_withdrawals\`, kept separate because a\
> &#x20; transfer's \`to\` is an account on this ledger while a withdrawal's is an address on the claim\
> &#x20; chain — one channel would deliver two meanings of the same field name. Tick-level, so\
> &#x20; \`orderbook\_ids\` does not apply; \`account\` matches \*\*either\*\* side, so a recipient hears the\
> &#x20; credit as readily as a sender hears the debit. A tick with no matching outcomes sends\
> &#x20; nothing at all rather than an empty array.\
> \
> \`pod\_orderbook\`, \`pod\_orders\`, \`pod\_orders\_v2\`, \`pod\_activity\`, \`pod\_candles\`,\
> \`pod\_withdrawals\`, and \`pod\_transfers\` are \*\*delta\*\* channels\
> (they stream what changed each tick). \`pod\_markets\`, \`pod\_positions\`, and \`pod\_triggers\` are \*\*state\*\* channels\
> (each pushes a current snapshot). \`newHeads\` is served from the block feed. 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. \`f\` is\
> that fill's fee, beside the running \`tf\`.\
> \
> \*\*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.\
> \
> \*\*Engine-generated closes.\*\* A backstop sweep leg and an ADL close each appear as a\
> synthetic order: a \`new\` for an entity of \`kind\` \`backstop\_transfer\`, \`adl\` or\
> \`adl\_counterparty\`, followed by a terminal \`fill\`. An ADL close is delivered to both parties.\
> \
> \*\*Reading a \`pod\_activity\` frame.\*\* The result is \`{ "\<deadline µs>": \[ActivityEntry] }\`\
> with exactly one key. Each entry is tagged by \`k\` and carries its own book and order id,\
> so it stands alone; there are no entities or indexes as in \`pod\_orders\_v2\`. Entries are the\
> ones \`GET /v1/clob/activity/{account}\` serves for that batch, in the same order. A tick with no entries for the\
> account sends nothing.\
> \
> \*\*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\`. \`pod\_withdrawals\` takes \`account\`\
> \*\*optionally\*\* — omitted streams every account's outcomes — and matches it against\
> \`withdrawer\`, the debited account; it ignores \`orderbook\_ids\` too. \`pod\_transfers\` takes\
> \`account\` optionally on the same terms, but matches it against \*\*either\*\* \`from\` or \`to\`.\
> \`pod\_activity\` requires \`account\`, rejects \`bidders\`, and ignores \`orderbook\_ids\`.\
> \`depth\` applies to \`pod\_orderbook\` snapshots only and is at least 1.\
> \
> \*\*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\_activity\`, \`pod\_candles\`, \`pod\_withdrawals\`, \`pod\_transfers\`) replay buffered ticks\
> with deadline strictly greater than \`since\` (\`pod\_orders\_v2\` differs, see below). If\
> \`since\` predates the retained buffer — or the buffer is empty, as right after a node start\
> — the subscription is rejected with \`-32602\` "since too old; backfill via REST then\
> resubscribe" (for \`pod\_withdrawals\` that is \`GET /v1/bridge/withdrawals\[/{account}]?since=\`,\
> which takes the same cursor and serves the same shape; \`pod\_transfers\` has no REST\
> backfill: resubscribe live). State channels (\`pod\_markets\`, \`pod\_positions\`,\
> \`pod\_triggers\`) emit one current snapshot immediately when \`since\` is passed (any value),\
> then stream live. Omitted = live-only: a state channel sends nothing until a tick touches\
> it. 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 starts at the batch equal to \`since\` (inclusive),\
> 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_activity` — an `ActivityFrame`: one account's activity in one tick, as a map with one\n  key, the tick's deadline, to its `ActivityEntry` list: orders, fills, modifications,\n  terminations, refused modifications and cancels on every orderbook, and the money it moved\n  (backstop sweeps, bridge deposits and withdrawals, transfers). The same shape as\n  `GET /v1/clob/activity/{account}`. Requires `account` (alias `bidder`).\n- `pod_markets` — a `MarketDynamicEntry` per orderbook carrying live market statistics\n  (last clearing price, 24h volume/high/low, perp mark/oracle/funding/open-interest) and its\n  lifecycle (`status`, `live_at_us`, `disable_at_us`, `settlement_price`). Sent each tick\n  for the orderbooks that cleared or had a lifecycle event.\n- `pod_positions` — a `PositionsUpdate` (`{ account, data }`, where `data` matches\n  `ob_getPositions`) for the subscribed account, pushed for a tick that touches it: order\n  flow on any orderbook (new, fill, cancel, expiry, modification, trigger arm/cancel/update),\n  a backstop sweep or ADL close, a bridge deposit or withdrawal, or a transfer either way.\n  **Requires** `account` (alias `bidder`).\n- `pod_triggers` — a `TriggersUpdate` (the `ob_getTriggers` fields plus `account`, at most\n  200 triggers) for the subscribed account, pushed for a tick that touches it, on the same\n  rule as `pod_positions`. **Requires** `account`.\n- `newHeads` — a `BlockHeader` per block as it is flushed, in height order, each height\n  once. Takes no options. A subscriber that falls behind the block feed is closed with\n  `-32020` and no `resume_since`; resubscribe and fill the gap with `eth_getBlockByNumber`.\n- `pod_withdrawals` — an **array of `WithdrawalUpdate`**: what became of every bridge\n  withdrawal that settled this tick — claimable on the bridged chain, or refused with\n  the reason. Tick-level rather than per-orderbook, since a withdrawal belongs to no book, so\n  `orderbook_ids` does not apply; `account` narrows it to one withdrawer. A tick with no\n  matching outcomes sends nothing at all rather than an empty array.\n- `pod_transfers` — an **array of `TransferUpdate`**: what became of every account-to-account\n  transfer that settled this tick. The sibling of `pod_withdrawals`, kept separate because a\n  transfer's `to` is an account on this ledger while a withdrawal's is an address on the claim\n  chain — one channel would deliver two meanings of the same field name. Tick-level, so\n  `orderbook_ids` does not apply; `account` matches **either** side, so a recipient hears the\n  credit as readily as a sender hears the debit. A tick with no matching outcomes sends\n  nothing at all rather than an empty array.\n\n`pod_orderbook`, `pod_orders`, `pod_orders_v2`, `pod_activity`, `pod_candles`,\n`pod_withdrawals`, and `pod_transfers` 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). `newHeads` is served from the block feed. 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. `f` is\nthat fill's fee, beside the running `tf`.\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**Engine-generated closes.** A backstop sweep leg and an ADL close each appear as a\nsynthetic order: a `new` for an entity of `kind` `backstop_transfer`, `adl` or\n`adl_counterparty`, followed by a terminal `fill`. An ADL close is delivered to both parties.\n\n**Reading a `pod_activity` frame.** The result is `{ \"<deadline µs>\": [ActivityEntry] }`\nwith exactly one key. Each entry is tagged by `k` and carries its own book and order id,\nso it stands alone; there are no entities or indexes as in `pod_orders_v2`. Entries are the\nones `GET /v1/clob/activity/{account}` serves for that batch, in the same order. A tick with no entries for the\naccount sends nothing.\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`. `pod_withdrawals` takes `account`\n**optionally** — omitted streams every account's outcomes — and matches it against\n`withdrawer`, the debited account; it ignores `orderbook_ids` too. `pod_transfers` takes\n`account` optionally on the same terms, but matches it against **either** `from` or `to`.\n`pod_activity` requires `account`, rejects `bidders`, and ignores `orderbook_ids`.\n`depth` applies to `pod_orderbook` snapshots only and is at least 1.\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_activity`, `pod_candles`, `pod_withdrawals`, `pod_transfers`) replay buffered ticks\nwith deadline strictly greater than `since` (`pod_orders_v2` differs, see below). If\n`since` predates the retained buffer — or the buffer is empty, as right after a node start\n— the subscription is rejected with `-32602` \"since too old; backfill via REST then\nresubscribe\" (for `pod_withdrawals` that is `GET /v1/bridge/withdrawals[/{account}]?since=`,\nwhich takes the same cursor and serves the same shape; `pod_transfers` has no REST\nbackfill: resubscribe live). State channels (`pod_markets`, `pod_positions`,\n`pod_triggers`) emit one current snapshot immediately when `since` is passed (any value),\nthen stream live. Omitted = live-only: a state channel sends nothing until a tick touches\nit. Which option applies to which subscription type is summarised in\n`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 starts at the batch equal to `since` (inclusive),\nskips every book at or below `since_book` within that batch, and delivers later batches\nwhole, 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_activity`, `pod_candles`, `pod_markets`, `pod_positions`,\n   `pod_triggers`, `pod_withdrawals`, `pod_transfers`, `newHeads`.\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` / `pod_activity` / `pod_withdrawals` / `pod_transfers`.\n   - `depth` (integer, at least 1) — **`pod_orderbook` only**: cap the price\n     levels per side 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`, `pod_triggers` and `pod_activity` (the account to stream). Optional on\n     `pod_withdrawals`, where it matches `withdrawer` (the debited account), and\n     on `pod_transfers`, where it matches either `from` or `to`.\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) — every channel but `newHeads`: catch-up\n     watermark (see the 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_activity","pod_candles","pod_markets","pod_positions","pod_triggers","pod_withdrawals","pod_transfers","newHeads"]},{"$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` / `pod_activity` require `account` (alias `bidder`).\n`newHeads` reads none of them. Which fields take effect 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  `pod_activity` / `pod_withdrawals` / `pod_transfers`.\n- `depth` — `pod_orderbook` only; at least 1.\n- `bidder` (alias `account`) — optional for `pod_orders` / `pod_orders_v2` /\n  `pod_withdrawals` / `pod_transfers`; **required** for `pod_positions`, `pod_triggers` and\n  `pod_activity`.\n- `bidders` — `pod_orders_v2` only, to follow several accounts on one subscription.\n  Mutually exclusive with `bidder`.\n- `since` — every channel but `newHeads` (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, at least 1. 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_orders_v2`, `pod_candles`, `pod_markets`; ignored by the account-scoped and tick-level channels (`pod_positions`, `pod_triggers`, `pod_activity`, `pod_withdrawals`, `pod_transfers`)."},"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` / `pod_activity` this is required: the account whose positions / triggers / activity to stream. On `pod_orders_v2` it is the single-account form of `bidders`, and sending both is an error. On `pod_withdrawals` it is optional and matches `withdrawer` — the debited account. On `pod_transfers` it is optional and matches either side of the transfer, `from` or `to`."},"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 (`pod_orders_v2` from the tick at it, see `since_book`); state channels emit one current snapshot then stream live. Omit for live-only. If a delta channel's `since` predates the retained buffer, or the buffer is empty, the subscription is rejected with `-32602`."},"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_orders_v2` → an `OrdersFrameV2`.\n- `pod_activity` → an `ActivityFrame`.\n- `pod_candles` → a `CandleTick`.\n- `pod_markets` → a `MarketDynamicEntry`.\n- `pod_positions` → a `PositionsUpdate`.\n- `pod_triggers` → a `TriggersUpdate`.\n- `pod_withdrawals` → an array of `WithdrawalUpdate`.\n- `pod_transfers` → an array of `TransferUpdate`.\n- `newHeads` → a `BlockHeader`.\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/OrdersFrameV2"},{"$ref":"#/components/schemas/ActivityFrame"},{"$ref":"#/components/schemas/CandleTick"},{"$ref":"#/components/schemas/MarketDynamicEntry"},{"$ref":"#/components/schemas/PositionsUpdate"},{"$ref":"#/components/schemas/TriggersUpdate"},{"type":"array","items":{"$ref":"#/components/schemas/WithdrawalUpdate"}},{"type":"array","items":{"$ref":"#/components/schemas/TransferUpdate"}},{"$ref":"#/components/schemas/BlockHeader"}]}}}}},"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 ascending — the best bid is the last key"},"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. This variant carries no\n  status, so an engine removal — such as a refused post-only order — is\n  indistinguishable from a cancel the trader sent. Use `pod_orders_v2`, whose `cancel` event\n  carries `st`, if you need to tell them apart.\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`)."}}},"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 cancellations, then\nrefused cancels, then modifications, then refused amendments, then fills ascending by\norder id, then the engine's matching-walk removals (`cancel` with `st`\n`post_only_refused` / `self_trade_canceled` / `margin_canceled`), then expirations, then\nADL closes, then backstop sweeps.\n\nThe order is not arbitrary: apply events as they arrive and your book is never transiently\nwrong. Cancellations precede the fills so you never hold an order that has already been\nremoved, and the matching-walk removals sit after the modifications and the fills, so an\norder repriced onto a crossing level and refused for it ends the frame removed, and a\nfill it took before removal lands on a live order.\n"}}},"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."},"book":{"$ref":"#/components/schemas/Bytes32","description":"Absent on `pod_orders_v2`, whose frame names the orderbook; `pod_activity` has its own entries."},"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."},"post_only":{"type":"boolean","description":"Add-liquidity-only — the order may not trade in the batch that admitted it, so it can rest\nthrough a batch it appeared to cross. Omitted means false.\n"},"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","cancel_reject","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. A removal by the matching walk carries\n  `st` (`post_only_refused`, `self_trade_canceled` or `margin_canceled`); a cancel the\n  owner sent, or one the engine made before matching, omits it.\n- `cancel_reject` — a cancel the engine refused. The order still rests; it is named by\n  `id`, the requester by `by`, and `code`/`why` say why.\n- `expire` — removed on reaching its TTL, or an IOC remainder killed in its admission batch.\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` and `cancel_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` and `cancel_reject`: 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","size_above_maximum","size_off_lot","notional_overflow","notional_above_cap","delegation_expired","post_only_ioc","post_only_market_order","unspecified"],"description":"`modify_reject` and `cancel_reject`: 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`. The fee of one fill is `f`.\n"},"f":{"type":"string","description":"`fill` only. The fee charged by this fill, 1e18-scaled decimal."},"st":{"type":"string","enum":["filled","canceled","margin_canceled","self_trade_canceled","expired","post_only_refused"],"description":"The terminal status an event closed the order with.\n\nOn `fill`: present only on the fill that **closed** the order; its absence there means the\norder is still working.\n\nOn `cancel`: present only when the **engine** removed the order rather than the owner\ncancelling it — `post_only_refused` (a `post_only` order that would have taken liquidity in\nthe batch that admitted or re-priced it), `self_trade_canceled` (a resting order that was\nabout to fill against the same owner), or `margin_canceled`. An ordinary cancel\nomits `st`, so a client that ignores the field reads every `cancel` exactly as it did\nbefore.\n\nAn engine removal is ordered after the `modify` and `fill` events in its frame, unlike every other cancel.\nAn order repriced onto a crossing level and refused for it emits `modify` and then `cancel`:\napply them in the order given and the order ends the frame removed, rather than resurrected\nat the refused price.\n"},"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."}}},"ActivityFrame":{"type":"object","description":"One `pod_activity` notification: a map with one key, the tick's deadline in microseconds as\na decimal string (also the `since` to resume from), to the subscribed account's entries in\nthat tick. `GET /v1/clob/activity/{account}` serves the same shape with many keys.\n","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/ActivityEntry"}}},"ActivityEntry":{"type":"object","description":"One `pod_activity` entry, discriminated by `k`. Within a tick, entries are ordered by kind\nin the order of the `k` enum, then by book ascending, then in engine order. Amounts and\nprices are 1e18-scaled decimal strings. Optional fields are omitted rather than `null`;\nboolean flags are omitted when false. Ignore kinds and fields you do not recognise.\n\n- `order` — a placement, as the `Order` object of `GET /v1/clob/orders/{account}` with `k`\n  added (`order_id, orderbook_id, tx_hash, nonce, kind, order_type, status, side, price,\n  initial_size, ...`; its amounts follow that schema, unsigned ones `0x` hex), in its\n  admission state: `status` `active`, or `invalid` with `invalid_reason`, zero totals and\n  `fills: []`. ADL closes appear as orders with `kind` `adl` or `adl_counterparty`,\n  followed by their `fill`s.\n- `fill` — `id, book, b, q, tb, tq, tf, f?, st?, pa?`.\n- `modify` — a resting order changed in place: `id, book, px, sz, old_px, old_sz`.\n- `termination` — an order left the book other than by filling: `id, book, st`.\n- `backstop` — a perp position swept to the backstop (`book` set), or the terminal cash\n  sweep (`book` omitted): `book?, sz, cash, mark, eq, pnl`.\n- `bridge_transfer` — a bridge deposit (positive `amt`) or withdrawal (negative):\n  `tx, idx, tok, amt, err?`.\n- `transfer` — an account-to-account transfer, debit negative, credit positive: `id, cp,\n  tok, amt, err?`. `cp` is the other side: the receiver on a debit, the sender on a credit.\n  A self-transfer is two entries, the debit first. A refused transfer is reported to the\n  sender only.\n- `modify_reject` — an amendment the engine refused; the order is untouched: `id, book, px,\n  sz, why`.\n- `cancel_reject` — a cancel the engine refused; the order still rests: `id, book, why`.\n\nEvery other order entry names its order by `id` and `book`; for an order placed before the\nclient's history, fetch its terms from `GET /v1/clob/orders/{account}`.\n","required":["k"],"properties":{"k":{"type":"string","enum":["order","fill","modify","termination","backstop","bridge_transfer","transfer","modify_reject","cancel_reject"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"The order id; on `transfer`, the transfer id, as `TransferUpdate.transfer_id`."},"tx":{"$ref":"#/components/schemas/Bytes32","description":"`bridge_transfer`: the deposit or `withdraw` transaction."},"book":{"$ref":"#/components/schemas/Bytes32","description":"The orderbook. Omitted on the terminal backstop cash sweep."},"px":{"type":"string","description":"`modify`: the price after the change. `modify_reject`: the price asked for."},"sz":{"type":"string","description":"`modify`: the size after the change, unsigned. `modify_reject`: the size asked for, unsigned. `backstop`: signed position size moved to the backstop."},"why":{"type":"string","description":"`modify_reject`, `cancel_reject`: the engine's reason, always present."},"b":{"type":"string","description":"`fill`: base filled by this fill."},"q":{"type":"string","description":"`fill`: quote filled by this fill."},"tb":{"type":"string","description":"Order's total base filled after this fill (`fill` only)."},"tq":{"type":"string","description":"Order's total quote filled, as `tb`."},"tf":{"type":"string","description":"Order's total fee, as `tb`."},"f":{"type":"string","description":"`fill`: the fee charged by this fill. Omitted on rows stored before it was recorded."},"st":{"type":"string","enum":["filled","canceled","margin_canceled","self_trade_canceled","expired","post_only_refused"],"description":"`fill`: present only on the fill that closed the order. `termination`: how the order left the book (never `filled`)."},"pa":{"type":"string","description":"`fill`: the owner's position after this fill on a perp book, signed. Omitted when no position moved."},"old_px":{"type":"string","description":"`modify`: the price before the change."},"old_sz":{"type":"string","description":"`modify`: the size before the change, unsigned."},"cash":{"type":"string","description":"`backstop`: signed cash moved with it."},"mark":{"type":"string","description":"`backstop`: mark price at the sweep."},"eq":{"type":"string","description":"`backstop`: account equity at the sweep (signed)."},"pnl":{"type":"string","description":"`backstop`: PnL the forced close realized (signed); `0` on the cash sweep."},"idx":{"type":"integer","description":"`bridge_transfer`: position among the tick's deposit outcomes; `0` for a withdrawal."},"cp":{"$ref":"#/components/schemas/Address","description":"`transfer`: the other side, the receiver when `amt` is negative and the sender otherwise; the account itself on a self-transfer."},"tok":{"$ref":"#/components/schemas/Address","description":"`bridge_transfer`, `transfer`: Pod-side token address."},"amt":{"type":"string","description":"`bridge_transfer`, `transfer`: signed amount in Pod's 18 decimals."},"err":{"type":"string","description":"`bridge_transfer`, `transfer`: why the movement was refused — for a deposit `already_processed` or `not_included`, for a withdrawal as `WithdrawalUpdate.error`, for a transfer as `TransferUpdate.error`. Nothing moved; `amt` still reports what was asked for. Absent when it succeeded; treat an unrecognised value as a failure."}}},"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 and lifecycle for one orderbook, streamed on the `pod_markets`\nsubscription (one object per orderbook). Optional fields are omitted (not null) when unset —\ne.g. perp-only fields 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)."},"internal":{"type":"boolean","description":"Perp only: `true` when `oracle_price` is a book-derived internal price because every oracle source was stale."},"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_settling_index":{"type":"string","description":"Perp only: the index positions settle against (decimal, 1e18) — see `Market.funding_settling_index`. Omitted until the market's first perp batch after a node start."},"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)."},"status":{"type":"string","enum":["pending","active","disabled","settled"],"description":"Market lifecycle status, as on `ob_getMarkets`."},"live_at_us":{"type":"integer","format":"int64","description":"Batch deadline (microseconds) from which a `pending` market may go `active`. Omitted when not scheduled."},"disable_at_us":{"type":"integer","format":"int64","description":"Batch deadline (microseconds) of a scheduled halt. Omitted when none is scheduled."},"settlement_price":{"type":"string","description":"Price every position was (or will be) closed at (decimal, 1e18). Present once the market is disabled with a settlement price."}}},"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":"What a withdrawal or transfer can take now (1e18 USD): `max(0, equity − max(initial_margin, transfer_margin_ratio × notional))`, where `notional` is `Σ |size| × mark` and `transfer_margin_ratio` is a network parameter (10% by default). Equity counts unrealized PnL."},"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":"`funding_settling_index × size − funding_basis` (signed, 1e18 USD). Authoritative and exact."},"funding_basis":{"type":"string","description":"The position's funding ledger, `Σ settling_index × Δsize` (signed,\n1e18 USD). Pair it with the market's live `funding_settling_index`\nto recompute `funding_accrued` exactly between snapshots.\n"},"cost_basis":{"type":"string","description":"The position's price ledger, `Σ clearing × Δsize` (signed, 1e18\nUSD). `mark × size − cost_basis` is `unrealized_pnl`, exactly.\n"},"entry_funding":{"type":"string","description":"Funding accumulator at entry, on `funding_index`'s base (undivided\nby the funding window). Truncating and approximate — the exact pair\nis `funding_basis` with `funding_settling_index`.\n"},"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 × size − cost_basis` — pure price drift (signed, 1e18 USD); funding is reported separately as `funding_accrued`."},"realized_pnl":{"type":"string","description":"Always `\"0\"`; a leg's realized PnL banks into cash when it reaches flat. The lifetime figure is the account-level `total_realized_pnl`."},"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/TimestampString","description":"Batch deadline the trigger was signed for (microseconds, decimal string)."},"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"],"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\nOmitted from an `Order` response when it is the default `none`.\n"},"TimestampString":{"type":"string","pattern":"^[0-9]+$","description":"Unix timestamp in microseconds as a string"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"},"WithdrawalUpdate":{"type":"object","description":"One outcome from `pod_withdrawals` — what became of a single bridge withdrawal when its\ntick executed. The REST backfill (`GET /v1/bridge/withdrawals[/{account}]?since=`) serves the\nidentical shape, so an outcome read after a reconnect is indistinguishable from one that\narrived live.\n\nA withdrawal debits the account's balance, is burned on Pod, and is claimed on the bridge's\nbridged chain; nothing is credited to a Pod account on the way. No `error` means it is on its\nway there. `insufficient_balance` and `not_included` both mean **nothing was debited** — the\nfunds are still on the account and no claim will ever exist — and this is the only\nsurface that carries the reason, so a client watching only the bridged chain waits forever for\nan event that cannot come.\n\nThe claim itself is not here: read it from `GET /v1/bridge/withdrawals/by-id/{tx_hash}`,\nwhich reports `claimable` / `pending` / `refused` and attaches the proof once a certificate\ncan be assembled.\n","required":["tx_hash","withdrawer","to","token","amount","timestamp_us"],"properties":{"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"The `withdraw` transaction's own hash, which is the withdrawal's identity. A withdrawal is always its own transaction — it targets the bridge precompile, so it can be neither a `submitBatch` sub-intent nor a `delegated` inner call — and this is the key the claim is fetched by. Rows predating this design carry a computed `keccak256(abi.encode(signer, nonce, sequence))` id here instead; the same lookups serve both, but only the current generation is a real transaction hash, so do not feed a historical value to `eth_getTransactionByHash`."},"withdrawer":{"$ref":"#/components/schemas/Address","description":"The debited account, and what the `account` subscription filter matches. It is also the transaction signer for current withdrawals; on rows predating this design it can differ, being the master of a delegated withdrawal rather than the delegate that signed."},"to":{"$ref":"#/components/schemas/Address","description":"Recipient **on the bridged chain**. Nothing is credited on Pod."},"token":{"$ref":"#/components/schemas/Address","description":"Pod-side token address. Map it to the asset the claim pays out using the token list from `GET /v1/bridge/config`."},"amount":{"type":"string","description":"Amount in Pod's 18 decimals, hex-encoded — what the user signed and what left the account. The claim carries this converted to the token's bridged-chain decimals, which differs by 10^12 for a 6-decimal token, so never pass this value to `claim`; take that one from the proof response. A refused withdrawal still reports the amount that was asked for."},"error":{"type":"string","enum":["insufficient_balance","not_included"],"description":"Names why the withdrawal was refused. `insufficient_balance` — the balance did not cover it at execution; admission deliberately does not check the balance, because pending fills can raise it before the tick runs. `not_included` — the solver omitted a finalized intent before its deadline passed. Treat an unrecognised value as a failure rather than as success: the vocabulary can grow. An absent `error` is the normal claimable case but is not a guarantee — a node whose bridge config does not cover the token records the row, signs nothing, and reports `refused` with no reason — so confirm against `status`/`proof` rather than treating absent-`error` as \"on its way\"."},"timestamp_us":{"type":"integer","format":"int64","description":"The tick's batch deadline, in microseconds — also the `since` cursor for this subscription and for the REST backfill, so a value read here can be handed straight to either."}}},"TransferUpdate":{"type":"object","description":"One outcome from `pod_transfers` — what became of a single account-to-account transfer when\nits tick executed.\n\nA transfer has no receipt of its own: it is a solver-gated intent that settles inside the\nsolver's `submitSolutions` transaction, and a refused one still consumes its nonce while\nchanging no state. This channel is therefore the only way to tell refused from succeeded.\n\nThe sibling of `WithdrawalUpdate` rather than the same shape: a transfer's `to` is an account\non **this** ledger and the funds land there, while a withdrawal's `to` is an address on the\nbridged chain. Every error here also means **nothing moved on either side**; retrying means a\nnew transaction, and so a new `transfer_id`.\n","required":["transfer_id","from","to","token","amount","timestamp_us"],"properties":{"transfer_id":{"$ref":"#/components/schemas/Bytes32","description":"Identity of the transfer intent, `keccak256(abi.encode(signer, nonce, sequence))`, where `sequence` is its position inside a `submitBatch` envelope (`0` for a standalone `transfer`). Computable before submitting."},"from":{"$ref":"#/components/schemas/Address","description":"The debited account, which is also the transaction signer — transfers are not delegable. Matched by the `account` subscription filter, as is `to`."},"to":{"$ref":"#/components/schemas/Address","description":"The credited account, **on this ledger**. Unlike a withdrawal's `to`, this is a Pod address and the funds land there."},"token":{"$ref":"#/components/schemas/Address","description":"Token address on Pod."},"amount":{"type":"string","description":"Amount in Pod's 18 decimals, hex-encoded. A refused transfer still reports the amount that was asked for."},"error":{"type":"string","enum":["insufficient_balance","recipient_not_resident","not_included"],"description":"Absent when the funds moved. `insufficient_balance` — the sender's withdrawable balance did not cover it at execution; admission deliberately does not check the balance, because pending fills can raise it before the tick runs. `recipient_not_resident` — the recipient's account was not resident when the tick ran, so the credit had nowhere to land. `not_included` — the solver omitted a finalized intent before its deadline passed. Treat an unrecognised value as a failure rather than as success: the vocabulary can grow."},"timestamp_us":{"type":"integer","format":"int64","description":"The tick's batch deadline, in microseconds — also the `since` cursor for this subscription."}}},"BlockHeader":{"type":"object","description":"One `newHeads` notification: a block header in the `eth_getBlockByNumber` shape, without\n`transactions`. `timestamp` is the block's batch deadline in seconds. Roots, `parentHash`,\n`mixHash`, `nonce`, `difficulty` and `extraData` are zero placeholders, and `gasLimit` /\n`gasUsed` are `0x0`.\n","properties":{"number":{"type":"string","description":"Block height (hex)."},"hash":{"$ref":"#/components/schemas/Bytes32"},"parentHash":{"$ref":"#/components/schemas/Bytes32"},"mixHash":{"$ref":"#/components/schemas/Bytes32"},"nonce":{"type":"string"},"sha3Uncles":{"$ref":"#/components/schemas/Bytes32"},"logsBloom":{"type":"string"},"transactionsRoot":{"$ref":"#/components/schemas/Bytes32"},"stateRoot":{"$ref":"#/components/schemas/Bytes32"},"receiptsRoot":{"$ref":"#/components/schemas/Bytes32"},"miner":{"$ref":"#/components/schemas/Address"},"difficulty":{"type":"string"},"extraData":{"type":"string"},"size":{"type":"string"},"gasLimit":{"type":"string"},"gasUsed":{"type":"string"},"timestamp":{"type":"string","description":"Batch deadline in seconds (hex)."},"uncles":{"type":"array","items":{"type":"string"}},"baseFeePerGas":{"type":"string"}}}}}}
````

## 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.\
> \- \`skip\_validation\` (boolean, optional): When true, a full node skips its local\
> &#x20; pre-validation. Default false.\
> \
> The wait ends when the transaction executes, when \`n − f\` validators attest, when \`f + 1\`\
> reject it permanently, or at the timeout; on a timeout the result reports what was heard so far. On a validator node the\
> call returns immediately with \`successes: 0\`.\
> \
> \*\*Errors\*\* (beyond invalid params):\
> \- \`999\` — account locked; \`data\` carries \`recovery\_target\` and \`recovery\_target\_nonce\`.\
> \- \`-32003\` — rejected permanently by at least \`f + 1\` validators; \`data\` lists the rejections.\
> \- \`997\` — an empty transaction is required at \`data.nonce\` to make progress.\
> \- \`-32000\` — the node is in read-only mode (see \`pod\_status\`), or local validation failed\
> &#x20; on a non-contract rule (reason in \`data\`).\
> \- \`3\` — \`execution reverted\`: local validation failed on a contract rule; \`data\` is the\
> &#x20; ABI-encoded \`Error(string)\` reason.\
> \- \`-32025\` — submission from a geo-restricted source.<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- `skip_validation` (boolean, optional): When true, a full node skips its local\n  pre-validation. Default false.\n\nThe wait ends when the transaction executes, when `n − f` validators attest, when `f + 1`\nreject it permanently, or at the timeout; on a timeout the result reports what was heard so far. On a validator node the\ncall returns immediately with `successes: 0`.\n\n**Errors** (beyond invalid params):\n- `999` — account locked; `data` carries `recovery_target` and `recovery_target_nonce`.\n- `-32003` — rejected permanently by at least `f + 1` validators; `data` lists the rejections.\n- `997` — an empty transaction is required at `data.nonce` to make progress.\n- `-32000` — the node is in read-only mode (see `pod_status`), or local validation failed\n  on a non-contract rule (reason in `data`).\n- `3` — `execution reverted`: local validation failed on a contract rule; `data` is the\n  ABI-encoded `Error(string)` reason.\n- `-32025` — submission from a geo-restricted source.\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\n3. `skip_validation` (boolean, optional): Skip the full node's local pre-validation\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","description":"Rejections heard from validators during the wait.","items":{"type":"object","properties":{"error":{"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."}}}}
```

## Get Validator Committee

> Returns the current validator committee and its quorum thresholds.

```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 the current validator committee and its quorum thresholds.","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":{"$ref":"#/components/schemas/CommitteeResponse"},"id":{"type":"integer"}}}}}}}}}},"components":{"schemas":{"CommitteeResponse":{"type":"object","description":"The current validator committee, returned by `pod_getCommittee`.","required":["validators","n","n_minus_3f","n_minus_f"],"properties":{"validators":{"type":"array","description":"`[validator_index, public_key]` pairs, where `public_key` is a `Secp256k1PublicKey`.","items":{"type":"array","minItems":2,"maxItems":2,"items":{"oneOf":[{"type":"integer"},{"$ref":"#/components/schemas/Secp256k1PublicKey"}]}}},"n":{"type":"integer","description":"Committee size."},"n_minus_3f":{"type":"integer","description":"Certificate threshold."},"n_minus_f":{"type":"integer","description":"Quorum."}}},"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)."}}}}
```

## Get Vote Batches

> Returns one validator's signed vote batches for the requested append-log sequence ranges.\
> \`validator\_index\` selects the validator; any node holding its batches can serve them,\
> including a full node. Without \`validator\_index\` the node serves its own batches; a full\
> node then returns an internal error ("node is not a validator").\
> \
> Each range is half-open, \`\[start, end)\`. The total across all ranges is capped by the node's\
> vote-sync batch size; ranges past the cap are dropped, so re-request what is missing.\
> \
> The result is a JSON array of vote batches, or with \`binary: true\` an object \`{ data }\`\
> holding the standard-base64 compact binary encoding of the same batches. Branch on the\
> result: an array is the batches, an object carries them in \`data\`.<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_getVoteBatches":{"post":{"tags":["Network & Consensus (pod_)"],"summary":"Get Vote Batches","operationId":"pod_getVoteBatches","description":"Returns one validator's signed vote batches for the requested append-log sequence ranges.\n`validator_index` selects the validator; any node holding its batches can serve them,\nincluding a full node. Without `validator_index` the node serves its own batches; a full\nnode then returns an internal error (\"node is not a validator\").\n\nEach range is half-open, `[start, end)`. The total across all ranges is capped by the node's\nvote-sync batch size; ranges past the cap are dropped, so re-request what is missing.\n\nThe result is a JSON array of vote batches, or with `binary: true` an object `{ data }`\nholding the standard-base64 compact binary encoding of the same batches. Branch on the\nresult: an array is the batches, an object carries them in `data`.\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_getVoteBatches"},"id":{"type":"integer","default":1},"params":{"type":"array","description":"Parameters:\n1. `ranges` (array of `[start, end]` integer pairs): half-open sequence ranges.\n2. `binary` (boolean, optional): return the base64 binary encoding. Default false.\n3. `validator_index` (integer, optional): the committee index whose batches to\n   return. Default: the serving validator's own.\n","items":{"oneOf":[{"type":"array","items":{"type":"array","items":{"type":"integer","format":"int64"},"minItems":2,"maxItems":2}},{"type":"boolean"},{"type":"integer"}]}}}}}}},"responses":{"200":{"description":"Array of vote batch objects, or `{ data }` when `binary` is true","content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string"},"result":{"oneOf":[{"type":"array","items":{"type":"object"}},{"type":"object","properties":{"data":{"type":"string","description":"Standard-base64 binary encoding of the batches."}}}]},"id":{"type":"integer"}}}}}}}}}}}
```

## 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, newest first, optionally filtered by sender and/or recipient.

```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, newest first, optionally filtered by sender and/or recipient.","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 (default and cap 10,000).\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, the votes seen for the next solution, and\
> its solving \`schedule\`. 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, the votes seen for the next solution, and\nits solving `schedule`. Only 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","schedule"],"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."},"schedule":{"$ref":"#/components/schemas/SolverScheduleStatus"}}},"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/TimestampString","description":"Batch deadline in microseconds, as a decimal string."},"tx_hash":{"$ref":"#/components/schemas/Bytes32"}}},"TimestampString":{"type":"string","pattern":"^[0-9]+$","description":"Unix timestamp in microseconds as a 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."},"SolverScheduleStatus":{"type":"object","description":"The batch-deadline window this instance solves for, and the decision it gives for the next tick.","required":["schedule","next_deadline","producing"],"properties":{"schedule":{"type":"object","nullable":true,"description":"The half-open window `[start_deadline, stop_deadline)` in microseconds; null when the instance is stood down.","properties":{"start_deadline":{"type":"integer","format":"int64"},"stop_deadline":{"type":"integer","format":"int64","nullable":true,"description":"Null means open-ended."}}},"next_deadline":{"$ref":"#/components/schemas/TimestampString","description":"Deadline of the tick the chain will produce next (microseconds, decimal string)."},"producing":{"type":"boolean","description":"Whether `next_deadline` falls inside the window."}}}}}}
```

## 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, min(expected_nonce, next_finalized_nonce + 256))`, so at most 256; when more are pending the newest 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. Votes are read for at most the 256 oldest pending nonces; when more\
> are pending, \`current\_vote\` (the vote on the latest pending nonce) reports \`not\_seen\`.<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. Votes are read for at most the 256 oldest pending nonces; when more\nare pending, `current_vote` (the vote on the latest pending nonce) reports `not_seen`.\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 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","margin_canceled","self_trade_canceled","post_only_refused","invalid"],"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- `margin_canceled`: The engine removed the order because the owner's margin capacity was exhausted\n- `self_trade_canceled`: The engine removed a resting order that was about to fill against another order of the same owner\n- `post_only_refused`: The engine removed a `post_only` order that would have taken liquidity in the batch that admitted (or re-priced) it. Distinct from `canceled` so an engine refusal can be told apart from a cancel the trader sent — see [Post-only orders](https://docs.v2.pod.network/api-reference/applications-precompiles/orderbook)\n- `invalid`: Rejected at execution and never entered the book; the reject reason travels with the status\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","30m","1h","4h","1d","1w","1M"],"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"],"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\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","adl","adl_counterparty","backstop_transfer"],"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- `adl`: synthetic order recording an auto-deleveraging close, on the bankrupt account whose position was closed\n- `adl_counterparty`: synthetic order recording the same ADL close on the account that covered it\n- `backstop_transfer`: synthetic order recording a position swept to the backstop during liquidation\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); the order's own price for ADL fills."}}},"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`. `post_only` is reported on both. 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/TimestampString","description":"Batch deadline the order was signed for (microseconds, as a decimal string)"},"end":{"$ref":"#/components/schemas/Timestamp","description":"Timestamp when order expires (microseconds)"},"included_batch":{"$ref":"#/components/schemas/Timestamp","description":"Deadline of the batch the order entered the book in, at or before `deadline`. `0` for engine-generated orders and orders indexed before this field existed."},"invalid_reason":{"type":"string","description":"Why the engine refused the order. Present only when `status` is `invalid`."},"realized_pnl":{"type":"string","description":"Perp only — aggregate realized PnL across this order's fills (signed decimal, 1e18 USD). Omitted on spot orders and on perp orders that never closed a slice."},"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, oldest first. Always present; empty unless the query sets `with_fills`."},"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},"post_only":{"type":"boolean","description":"Add-liquidity-only — the order could not trade in the batch that admitted it. Reported on\nboth market types, and **omitted when false**.\n"},"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","adl","adl_counterparty","backstop_transfer"],"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- `adl`: synthetic order recording an auto-deleveraging close, on the bankrupt account whose position was closed\n- `adl_counterparty`: synthetic order recording the same ADL close on the account that covered it\n- `backstop_transfer`: synthetic order recording a position swept to the backstop during liquidation\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","margin_canceled","self_trade_canceled","post_only_refused","invalid"],"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- `margin_canceled`: The engine removed the order because the owner's margin capacity was exhausted\n- `self_trade_canceled`: The engine removed a resting order that was about to fill against another order of the same owner\n- `post_only_refused`: The engine removed a `post_only` order that would have taken liquidity in the batch that admitted (or re-priced) it. Distinct from `canceled` so an engine refusal can be told apart from a cancel the trader sent — see [Post-only orders](https://docs.v2.pod.network/api-reference/applications-precompiles/orderbook)\n- `invalid`: Rejected at execution and never entered the book; the reject reason travels with the status\n"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"TimestampString":{"type":"string","pattern":"^[0-9]+$","description":"Unix timestamp in microseconds as a string"},"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); the order's own price for ADL fills."}}},"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"],"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\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":"Base volume traded during this candle period (1e18)"},"quote_volume":{"$ref":"#/components/schemas/HexUint256","description":"Quote (USD) notional traded during this candle period, `Σ(base × clearing price)` over its ticks (1e18)"}}},"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\")"},"status":{"type":"string","enum":["pending","active","disabled","settled"],"description":"Lifecycle status. `pending`: created, not yet trading (waiting for `live_at`\nand, for perps, a first oracle price). `active`: trading. `disabled`: halted\nat `disable_at`; every intent is refused, orders and positions stay put.\n`settled`: orders refunded and positions closed at `settlement_price`; kept\nfor history.\n"},"live_at":{"type":"integer","format":"int64","description":"Batch deadline (microseconds) from which a `pending` market may go `active`. Absent for markets that were live from genesis."},"disable_at":{"type":"integer","format":"int64","description":"Batch deadline (microseconds) of a scheduled halt. Present from the moment the `disableMarket` intent applies, i.e. throughout the notice window."},"settlement_price":{"$ref":"#/components/schemas/HexUint256","description":"Price every position was (or will be) closed at, 1e18-scaled. Present once the market is `disabled`."},"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":{"type":"string","nullable":true,"description":"Last auction clearing price (hex-encoded, quote/base with 1e18 scale). `null` until the market's first fill."},"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":{"type":"string","nullable":true,"description":"24-hour highest price (hex-encoded, 1e18). `null` until the market has a completed candle."},"low_24h":{"type":"string","nullable":true,"description":"24-hour lowest price (hex-encoded, 1e18). `null` until the market has a completed candle."},"price_change_24h":{"type":"integer","nullable":true,"description":"24-hour price change in basis points (signed JSON number; `300` = +3%). `null` until the market has a completed candle."},"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."},"min_notional":{"$ref":"#/components/schemas/HexUint256","description":"Minimum quote notional per order, hex-encoded with `1e18` scale. `0x0` means no floor. Orders below it are rejected at admission."},"maker_fee":{"type":"string","description":"Maker fee rate, a decimal fraction of the quote amount; `\"0.010000\"` is 1%."},"taker_fee":{"type":"string","description":"Taker fee rate, a decimal fraction of the quote amount; `\"0.010000\"` is 1%."},"max_leverage":{"type":"integer","description":"Maximum allowed leverage. Returned for both spot and perp markets, but only meaningful for perp."},"initial_margin":{"type":"string","description":"Initial-margin rate as the engine charges it (`1 / max_leverage`),\nhex-encoded 1e18-scaled; the maintenance rate is half of it. Use it\nrather than re-deriving from the integer `max_leverage`.\n"},"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), undivided\nand unquantized — see `funding_settling_index` for the base a\nposition's `funding_basis` uses. `null` for spot markets.\n"},"funding_settling_index":{"type":"string","nullable":true,"description":"Perp markets only. The index positions settle against: the\n`funding_index` accumulator divided by `funding_window_us` and\nquantized to the market's funding grid, as a signed decimal string\n(1e18-scaled). With a position's `funding_basis` this gives accrual\nexactly: `funding_settling_index × size − funding_basis`.\n`funding_index` is a DIFFERENT base and cannot be subtracted from a\nposition's basis. `null` for spot markets, and until the market's\nfirst perp batch after a node start.\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."},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer (hex-encoded with 0x prefix)"},"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"}}}}
```

## 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 ascending — the best bid is the last key"},"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","nullable":true,"description":"The transaction's position within its block (hex-encoded); null when `blockNumber` is\nnull.\n"},"blockHash":{"nullable":true,"description":"Hash of the block the transaction was sequenced in; null when it is in no block","allOf":[{"$ref":"#/components/schemas/Bytes32"}]},"blockNumber":{"type":"string","nullable":true,"description":"Block number (hex-encoded), or null when the transaction is in no block - `submitSolutions`,\nrecovery transactions, and an orderbook intent whose auction tick has not executed yet. A null\nblock is not a pending state: the receipt is final either way.\n"},"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)"},"blockHash":{"type":"string","nullable":true,"description":"Block of the emitting transaction. Set in the receipt of a transaction in a block; null in `eth_getLogs` results."},"blockNumber":{"type":"string","nullable":true,"description":"As `blockHash`."},"transactionHash":{"$ref":"#/components/schemas/Bytes32"},"transactionIndex":{"type":"string","nullable":true,"description":"As `blockHash`."},"logIndex":{"type":"string","description":"Position of the log within its transaction's logs (hex-encoded)."},"removed":{"type":"boolean","description":"Always false."}}},"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, in the standard Ethereum shape.\n`blockHash`, `blockNumber` and `transactionIndex` are set when a tick sequenced the\ntransaction into a block and null otherwise. EIP-1559 transactions carry `maxFeePerGas`,\n`maxPriorityFeePerGas`, `accessList` and `yParity`; legacy (EIP-155) ones omit them.\n","properties":{"type":{"type":"string","description":"Transaction type: `0x2` (EIP-1559) or `0x0` (legacy)."},"chainId":{"type":"string"},"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","description":"Effective gas price; for EIP-1559 transactions the `maxFeePerGas`."},"maxFeePerGas":{"type":"string"},"maxPriorityFeePerGas":{"type":"string"},"accessList":{"type":"array","items":{"type":"object"}},"input":{"type":"string"},"v":{"type":"string"},"yParity":{"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)"},"blockHash":{"type":"string","nullable":true,"description":"Block of the emitting transaction. Set in the receipt of a transaction in a block; null in `eth_getLogs` results."},"blockNumber":{"type":"string","nullable":true,"description":"As `blockHash`."},"transactionHash":{"$ref":"#/components/schemas/Bytes32"},"transactionIndex":{"type":"string","nullable":true,"description":"As `blockHash`."},"logIndex":{"type":"string","description":"Position of the log within its transaction's logs (hex-encoded)."},"removed":{"type":"boolean","description":"Always false."}}},"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 (exclusive) in microseconds. Unbounded if omitted."},"limit":{"type":"integer","description":"Maximum number of candles to return. Defaults to 500; a value above 500 is rejected."}}},"CandleResolution":{"type":"string","enum":["1m","5m","15m","30m","1h","4h","1d","1w","1M"],"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. Clamped to `[1, 200]`; defaults to 200."},"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, fill each order's per-batch partial `fills` array. Defaults to false, and `fills` is then empty."},"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","margin_canceled","self_trade_canceled","post_only_refused","invalid"],"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- `margin_canceled`: The engine removed the order because the owner's margin capacity was exhausted\n- `self_trade_canceled`: The engine removed a resting order that was about to fill against another order of the same owner\n- `post_only_refused`: The engine removed a `post_only` order that would have taken liquidity in the batch that admitted (or re-priced) it. Distinct from `canceled` so an engine refusal can be told apart from a cancel the trader sent — see [Post-only orders](https://docs.v2.pod.network/api-reference/applications-precompiles/orderbook)\n- `invalid`: Rejected at execution and never entered the book; the reject reason travels with the status\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 SolutionsQuery object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"SolutionsQuery":{"type":"object","description":"Query parameters for ob_getSolutions. All fields optional.","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32","description":"Restrict to one orderbook; omit for every orderbook."},"since":{"$ref":"#/components/schemas/Timestamp","description":"Inclusive lower bound on the batch deadline (microseconds)."},"until":{"$ref":"#/components/schemas/Timestamp","description":"Exclusive upper bound on the batch deadline (microseconds)."},"limit":{"type":"integer","description":"Ticks per page — a tick carries one row per orderbook. Clamped to `[1, 200]`; defaults to 200."}}},"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."},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```

## 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/TimestampString","description":"Batch deadline the trigger was signed for (microseconds, decimal string)."},"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"],"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\nOmitted from an `Order` response when it is the default `none`.\n"},"TimestampString":{"type":"string","pattern":"^[0-9]+$","description":"Unix timestamp in microseconds as a string"},"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/TimestampString","description":"Batch deadline the trigger was signed for (microseconds, decimal string)."},"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"],"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\nOmitted from an `Order` response when it is the default `none`.\n"},"TimestampString":{"type":"string","pattern":"^[0-9]+$","description":"Unix timestamp in microseconds as a string"},"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 on the terminal cash-sweep row, which belongs to no orderbook."},"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."},"eq":{"type":"string","description":"Account equity at the moment of the sweep (decimal int256, 1e18)."},"realized_pnl":{"type":"string","description":"PnL the forced close realized (decimal int256, 1e18). `0` on the terminal cash-sweep row and on rows recorded before this field existed."},"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 on the terminal cash-sweep row, which belongs to no orderbook."},"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."},"eq":{"type":"string","description":"Account equity at the moment of the sweep (decimal int256, 1e18)."},"realized_pnl":{"type":"string","description":"PnL the forced close realized (decimal int256, 1e18). `0` on the terminal cash-sweep row and on rows recorded before this field existed."},"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 SolutionResponse object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"SolutionResponse":{"type":"object","description":"One orderbook's record for one executed batch, as returned by `ob_getSolutions`. Perp-only fields are omitted on spot rows; replay inputs are also omitted on rows recorded before they were stored.","required":["orderbook_id","timestamp","mark_price","volume"],"properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"timestamp":{"$ref":"#/components/schemas/Timestamp","description":"Batch deadline (microseconds)."},"clearing_price":{"$ref":"#/components/schemas/HexUint256","description":"Clearing price (1e18). Omitted for a market that has never traded."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"Oracle-anchored mark (1e18); `0x0` for spot."},"volume":{"$ref":"#/components/schemas/HexUint256","description":"Base volume cleared this batch (1e18)."},"oracle_price":{"$ref":"#/components/schemas/HexUint256","description":"Perp only — oracle price used this batch (1e18)."},"funding_rate":{"type":"string","description":"Perp only — funding rate this batch (signed decimal, 1e18)."},"funding_index":{"type":"string","description":"Perp only — cumulative funding accumulator after this batch (signed decimal, 1e18), undivided and unquantized; divided by `funding_window` and grid-quantized it becomes the index positions settle against."},"open_interest":{"$ref":"#/components/schemas/HexUint256","description":"Perp only — open interest (1e18 USD notional)."},"mark_best_bid":{"$ref":"#/components/schemas/HexUint256","description":"Perp only — the clean best bid the mark path read. Describes the previous batch."},"mark_best_ask":{"$ref":"#/components/schemas/HexUint256","description":"Perp only — the clean best ask the mark path read. Describes the previous batch."},"premium_ema":{"type":"string","description":"Perp only — premium EMA after the previous batch's step (signed decimal, 1e18)."},"book_median_ema":{"$ref":"#/components/schemas/HexUint256","description":"Perp only — book-median EMA after the previous batch's step. Omitted until seeded."},"impact_bid":{"$ref":"#/components/schemas/HexUint256","description":"Perp only — impact bid price funding consumed this batch."},"impact_ask":{"$ref":"#/components/schemas/HexUint256","description":"Perp only — impact ask price funding consumed this 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."},"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 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."},"internal":{"type":"boolean","description":"`true` when `oracle_price` is a book-derived internal price because every oracle source was stale."}}},"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\nint256, 1e18; may be negative), undivided and unquantized. A\nposition's `funding_basis` is NOT on this base — see\n`funding_settling_index`.\n"},"funding_settling_index":{"type":"string","description":"The index positions settle against: `funding_index` divided by the\nmarket's `funding_window_us` and quantized to its funding grid\n(signed decimal int256, 1e18). `funding_settling_index × size −\nfunding_basis` is a position's `funding_accrued`, exactly. Omitted\nuntil the orderbook's first perp batch after a node start — treat\na missing value as unknown, never as zero.\n"},"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 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` / `pod_activity` require `account` (alias `bidder`).\n`newHeads` reads none of them. Which fields take effect 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  `pod_activity` / `pod_withdrawals` / `pod_transfers`.\n- `depth` — `pod_orderbook` only; at least 1.\n- `bidder` (alias `account`) — optional for `pod_orders` / `pod_orders_v2` /\n  `pod_withdrawals` / `pod_transfers`; **required** for `pod_positions`, `pod_triggers` and\n  `pod_activity`.\n- `bidders` — `pod_orders_v2` only, to follow several accounts on one subscription.\n  Mutually exclusive with `bidder`.\n- `since` — every channel but `newHeads` (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, at least 1. 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_orders_v2`, `pod_candles`, `pod_markets`; ignored by the account-scoped and tick-level channels (`pod_positions`, `pod_triggers`, `pod_activity`, `pod_withdrawals`, `pod_transfers`)."},"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` / `pod_activity` this is required: the account whose positions / triggers / activity to stream. On `pod_orders_v2` it is the single-account form of `bidders`, and sending both is an error. On `pod_withdrawals` it is optional and matches `withdrawer` — the debited account. On `pod_transfers` it is optional and matches either side of the transfer, `from` or `to`."},"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 (`pod_orders_v2` from the tick at it, see `since_book`); state channels emit one current snapshot then stream live. Omit for live-only. If a delta channel's `since` predates the retained buffer, or the buffer is empty, the subscription is rejected with `-32602`."},"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_orders_v2` → an `OrdersFrameV2`.\n- `pod_activity` → an `ActivityFrame`.\n- `pod_candles` → a `CandleTick`.\n- `pod_markets` → a `MarketDynamicEntry`.\n- `pod_positions` → a `PositionsUpdate`.\n- `pod_triggers` → a `TriggersUpdate`.\n- `pod_withdrawals` → an array of `WithdrawalUpdate`.\n- `pod_transfers` → an array of `TransferUpdate`.\n- `newHeads` → a `BlockHeader`.\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/OrdersFrameV2"},{"$ref":"#/components/schemas/ActivityFrame"},{"$ref":"#/components/schemas/CandleTick"},{"$ref":"#/components/schemas/MarketDynamicEntry"},{"$ref":"#/components/schemas/PositionsUpdate"},{"$ref":"#/components/schemas/TriggersUpdate"},{"type":"array","items":{"$ref":"#/components/schemas/WithdrawalUpdate"}},{"type":"array","items":{"$ref":"#/components/schemas/TransferUpdate"}},{"$ref":"#/components/schemas/BlockHeader"}]}}}}},"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 ascending — the best bid is the last key"},"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. This variant carries no\n  status, so an engine removal — such as a refused post-only order — is\n  indistinguishable from a cancel the trader sent. Use `pod_orders_v2`, whose `cancel` event\n  carries `st`, if you need to tell them apart.\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`)."}}},"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 cancellations, then\nrefused cancels, then modifications, then refused amendments, then fills ascending by\norder id, then the engine's matching-walk removals (`cancel` with `st`\n`post_only_refused` / `self_trade_canceled` / `margin_canceled`), then expirations, then\nADL closes, then backstop sweeps.\n\nThe order is not arbitrary: apply events as they arrive and your book is never transiently\nwrong. Cancellations precede the fills so you never hold an order that has already been\nremoved, and the matching-walk removals sit after the modifications and the fills, so an\norder repriced onto a crossing level and refused for it ends the frame removed, and a\nfill it took before removal lands on a live order.\n"}}},"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."},"book":{"$ref":"#/components/schemas/Bytes32","description":"Absent on `pod_orders_v2`, whose frame names the orderbook; `pod_activity` has its own entries."},"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."},"post_only":{"type":"boolean","description":"Add-liquidity-only — the order may not trade in the batch that admitted it, so it can rest\nthrough a batch it appeared to cross. Omitted means false.\n"},"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","cancel_reject","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. A removal by the matching walk carries\n  `st` (`post_only_refused`, `self_trade_canceled` or `margin_canceled`); a cancel the\n  owner sent, or one the engine made before matching, omits it.\n- `cancel_reject` — a cancel the engine refused. The order still rests; it is named by\n  `id`, the requester by `by`, and `code`/`why` say why.\n- `expire` — removed on reaching its TTL, or an IOC remainder killed in its admission batch.\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` and `cancel_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` and `cancel_reject`: 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","size_above_maximum","size_off_lot","notional_overflow","notional_above_cap","delegation_expired","post_only_ioc","post_only_market_order","unspecified"],"description":"`modify_reject` and `cancel_reject`: 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`. The fee of one fill is `f`.\n"},"f":{"type":"string","description":"`fill` only. The fee charged by this fill, 1e18-scaled decimal."},"st":{"type":"string","enum":["filled","canceled","margin_canceled","self_trade_canceled","expired","post_only_refused"],"description":"The terminal status an event closed the order with.\n\nOn `fill`: present only on the fill that **closed** the order; its absence there means the\norder is still working.\n\nOn `cancel`: present only when the **engine** removed the order rather than the owner\ncancelling it — `post_only_refused` (a `post_only` order that would have taken liquidity in\nthe batch that admitted or re-priced it), `self_trade_canceled` (a resting order that was\nabout to fill against the same owner), or `margin_canceled`. An ordinary cancel\nomits `st`, so a client that ignores the field reads every `cancel` exactly as it did\nbefore.\n\nAn engine removal is ordered after the `modify` and `fill` events in its frame, unlike every other cancel.\nAn order repriced onto a crossing level and refused for it emits `modify` and then `cancel`:\napply them in the order given and the order ends the frame removed, rather than resurrected\nat the refused price.\n"},"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."}}},"ActivityFrame":{"type":"object","description":"One `pod_activity` notification: a map with one key, the tick's deadline in microseconds as\na decimal string (also the `since` to resume from), to the subscribed account's entries in\nthat tick. `GET /v1/clob/activity/{account}` serves the same shape with many keys.\n","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/ActivityEntry"}}},"ActivityEntry":{"type":"object","description":"One `pod_activity` entry, discriminated by `k`. Within a tick, entries are ordered by kind\nin the order of the `k` enum, then by book ascending, then in engine order. Amounts and\nprices are 1e18-scaled decimal strings. Optional fields are omitted rather than `null`;\nboolean flags are omitted when false. Ignore kinds and fields you do not recognise.\n\n- `order` — a placement, as the `Order` object of `GET /v1/clob/orders/{account}` with `k`\n  added (`order_id, orderbook_id, tx_hash, nonce, kind, order_type, status, side, price,\n  initial_size, ...`; its amounts follow that schema, unsigned ones `0x` hex), in its\n  admission state: `status` `active`, or `invalid` with `invalid_reason`, zero totals and\n  `fills: []`. ADL closes appear as orders with `kind` `adl` or `adl_counterparty`,\n  followed by their `fill`s.\n- `fill` — `id, book, b, q, tb, tq, tf, f?, st?, pa?`.\n- `modify` — a resting order changed in place: `id, book, px, sz, old_px, old_sz`.\n- `termination` — an order left the book other than by filling: `id, book, st`.\n- `backstop` — a perp position swept to the backstop (`book` set), or the terminal cash\n  sweep (`book` omitted): `book?, sz, cash, mark, eq, pnl`.\n- `bridge_transfer` — a bridge deposit (positive `amt`) or withdrawal (negative):\n  `tx, idx, tok, amt, err?`.\n- `transfer` — an account-to-account transfer, debit negative, credit positive: `id, cp,\n  tok, amt, err?`. `cp` is the other side: the receiver on a debit, the sender on a credit.\n  A self-transfer is two entries, the debit first. A refused transfer is reported to the\n  sender only.\n- `modify_reject` — an amendment the engine refused; the order is untouched: `id, book, px,\n  sz, why`.\n- `cancel_reject` — a cancel the engine refused; the order still rests: `id, book, why`.\n\nEvery other order entry names its order by `id` and `book`; for an order placed before the\nclient's history, fetch its terms from `GET /v1/clob/orders/{account}`.\n","required":["k"],"properties":{"k":{"type":"string","enum":["order","fill","modify","termination","backstop","bridge_transfer","transfer","modify_reject","cancel_reject"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"The order id; on `transfer`, the transfer id, as `TransferUpdate.transfer_id`."},"tx":{"$ref":"#/components/schemas/Bytes32","description":"`bridge_transfer`: the deposit or `withdraw` transaction."},"book":{"$ref":"#/components/schemas/Bytes32","description":"The orderbook. Omitted on the terminal backstop cash sweep."},"px":{"type":"string","description":"`modify`: the price after the change. `modify_reject`: the price asked for."},"sz":{"type":"string","description":"`modify`: the size after the change, unsigned. `modify_reject`: the size asked for, unsigned. `backstop`: signed position size moved to the backstop."},"why":{"type":"string","description":"`modify_reject`, `cancel_reject`: the engine's reason, always present."},"b":{"type":"string","description":"`fill`: base filled by this fill."},"q":{"type":"string","description":"`fill`: quote filled by this fill."},"tb":{"type":"string","description":"Order's total base filled after this fill (`fill` only)."},"tq":{"type":"string","description":"Order's total quote filled, as `tb`."},"tf":{"type":"string","description":"Order's total fee, as `tb`."},"f":{"type":"string","description":"`fill`: the fee charged by this fill. Omitted on rows stored before it was recorded."},"st":{"type":"string","enum":["filled","canceled","margin_canceled","self_trade_canceled","expired","post_only_refused"],"description":"`fill`: present only on the fill that closed the order. `termination`: how the order left the book (never `filled`)."},"pa":{"type":"string","description":"`fill`: the owner's position after this fill on a perp book, signed. Omitted when no position moved."},"old_px":{"type":"string","description":"`modify`: the price before the change."},"old_sz":{"type":"string","description":"`modify`: the size before the change, unsigned."},"cash":{"type":"string","description":"`backstop`: signed cash moved with it."},"mark":{"type":"string","description":"`backstop`: mark price at the sweep."},"eq":{"type":"string","description":"`backstop`: account equity at the sweep (signed)."},"pnl":{"type":"string","description":"`backstop`: PnL the forced close realized (signed); `0` on the cash sweep."},"idx":{"type":"integer","description":"`bridge_transfer`: position among the tick's deposit outcomes; `0` for a withdrawal."},"cp":{"$ref":"#/components/schemas/Address","description":"`transfer`: the other side, the receiver when `amt` is negative and the sender otherwise; the account itself on a self-transfer."},"tok":{"$ref":"#/components/schemas/Address","description":"`bridge_transfer`, `transfer`: Pod-side token address."},"amt":{"type":"string","description":"`bridge_transfer`, `transfer`: signed amount in Pod's 18 decimals."},"err":{"type":"string","description":"`bridge_transfer`, `transfer`: why the movement was refused — for a deposit `already_processed` or `not_included`, for a withdrawal as `WithdrawalUpdate.error`, for a transfer as `TransferUpdate.error`. Nothing moved; `amt` still reports what was asked for. Absent when it succeeded; treat an unrecognised value as a failure."}}},"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 and lifecycle for one orderbook, streamed on the `pod_markets`\nsubscription (one object per orderbook). Optional fields are omitted (not null) when unset —\ne.g. perp-only fields 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)."},"internal":{"type":"boolean","description":"Perp only: `true` when `oracle_price` is a book-derived internal price because every oracle source was stale."},"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_settling_index":{"type":"string","description":"Perp only: the index positions settle against (decimal, 1e18) — see `Market.funding_settling_index`. Omitted until the market's first perp batch after a node start."},"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)."},"status":{"type":"string","enum":["pending","active","disabled","settled"],"description":"Market lifecycle status, as on `ob_getMarkets`."},"live_at_us":{"type":"integer","format":"int64","description":"Batch deadline (microseconds) from which a `pending` market may go `active`. Omitted when not scheduled."},"disable_at_us":{"type":"integer","format":"int64","description":"Batch deadline (microseconds) of a scheduled halt. Omitted when none is scheduled."},"settlement_price":{"type":"string","description":"Price every position was (or will be) closed at (decimal, 1e18). Present once the market is disabled with a settlement price."}}},"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":"What a withdrawal or transfer can take now (1e18 USD): `max(0, equity − max(initial_margin, transfer_margin_ratio × notional))`, where `notional` is `Σ |size| × mark` and `transfer_margin_ratio` is a network parameter (10% by default). Equity counts unrealized PnL."},"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":"`funding_settling_index × size − funding_basis` (signed, 1e18 USD). Authoritative and exact."},"funding_basis":{"type":"string","description":"The position's funding ledger, `Σ settling_index × Δsize` (signed,\n1e18 USD). Pair it with the market's live `funding_settling_index`\nto recompute `funding_accrued` exactly between snapshots.\n"},"cost_basis":{"type":"string","description":"The position's price ledger, `Σ clearing × Δsize` (signed, 1e18\nUSD). `mark × size − cost_basis` is `unrealized_pnl`, exactly.\n"},"entry_funding":{"type":"string","description":"Funding accumulator at entry, on `funding_index`'s base (undivided\nby the funding window). Truncating and approximate — the exact pair\nis `funding_basis` with `funding_settling_index`.\n"},"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 × size − cost_basis` — pure price drift (signed, 1e18 USD); funding is reported separately as `funding_accrued`."},"realized_pnl":{"type":"string","description":"Always `\"0\"`; a leg's realized PnL banks into cash when it reaches flat. The lifetime figure is the account-level `total_realized_pnl`."},"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/TimestampString","description":"Batch deadline the trigger was signed for (microseconds, decimal string)."},"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"],"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\nOmitted from an `Order` response when it is the default `none`.\n"},"TimestampString":{"type":"string","pattern":"^[0-9]+$","description":"Unix timestamp in microseconds as a string"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"},"WithdrawalUpdate":{"type":"object","description":"One outcome from `pod_withdrawals` — what became of a single bridge withdrawal when its\ntick executed. The REST backfill (`GET /v1/bridge/withdrawals[/{account}]?since=`) serves the\nidentical shape, so an outcome read after a reconnect is indistinguishable from one that\narrived live.\n\nA withdrawal debits the account's balance, is burned on Pod, and is claimed on the bridge's\nbridged chain; nothing is credited to a Pod account on the way. No `error` means it is on its\nway there. `insufficient_balance` and `not_included` both mean **nothing was debited** — the\nfunds are still on the account and no claim will ever exist — and this is the only\nsurface that carries the reason, so a client watching only the bridged chain waits forever for\nan event that cannot come.\n\nThe claim itself is not here: read it from `GET /v1/bridge/withdrawals/by-id/{tx_hash}`,\nwhich reports `claimable` / `pending` / `refused` and attaches the proof once a certificate\ncan be assembled.\n","required":["tx_hash","withdrawer","to","token","amount","timestamp_us"],"properties":{"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"The `withdraw` transaction's own hash, which is the withdrawal's identity. A withdrawal is always its own transaction — it targets the bridge precompile, so it can be neither a `submitBatch` sub-intent nor a `delegated` inner call — and this is the key the claim is fetched by. Rows predating this design carry a computed `keccak256(abi.encode(signer, nonce, sequence))` id here instead; the same lookups serve both, but only the current generation is a real transaction hash, so do not feed a historical value to `eth_getTransactionByHash`."},"withdrawer":{"$ref":"#/components/schemas/Address","description":"The debited account, and what the `account` subscription filter matches. It is also the transaction signer for current withdrawals; on rows predating this design it can differ, being the master of a delegated withdrawal rather than the delegate that signed."},"to":{"$ref":"#/components/schemas/Address","description":"Recipient **on the bridged chain**. Nothing is credited on Pod."},"token":{"$ref":"#/components/schemas/Address","description":"Pod-side token address. Map it to the asset the claim pays out using the token list from `GET /v1/bridge/config`."},"amount":{"type":"string","description":"Amount in Pod's 18 decimals, hex-encoded — what the user signed and what left the account. The claim carries this converted to the token's bridged-chain decimals, which differs by 10^12 for a 6-decimal token, so never pass this value to `claim`; take that one from the proof response. A refused withdrawal still reports the amount that was asked for."},"error":{"type":"string","enum":["insufficient_balance","not_included"],"description":"Names why the withdrawal was refused. `insufficient_balance` — the balance did not cover it at execution; admission deliberately does not check the balance, because pending fills can raise it before the tick runs. `not_included` — the solver omitted a finalized intent before its deadline passed. Treat an unrecognised value as a failure rather than as success: the vocabulary can grow. An absent `error` is the normal claimable case but is not a guarantee — a node whose bridge config does not cover the token records the row, signs nothing, and reports `refused` with no reason — so confirm against `status`/`proof` rather than treating absent-`error` as \"on its way\"."},"timestamp_us":{"type":"integer","format":"int64","description":"The tick's batch deadline, in microseconds — also the `since` cursor for this subscription and for the REST backfill, so a value read here can be handed straight to either."}}},"TransferUpdate":{"type":"object","description":"One outcome from `pod_transfers` — what became of a single account-to-account transfer when\nits tick executed.\n\nA transfer has no receipt of its own: it is a solver-gated intent that settles inside the\nsolver's `submitSolutions` transaction, and a refused one still consumes its nonce while\nchanging no state. This channel is therefore the only way to tell refused from succeeded.\n\nThe sibling of `WithdrawalUpdate` rather than the same shape: a transfer's `to` is an account\non **this** ledger and the funds land there, while a withdrawal's `to` is an address on the\nbridged chain. Every error here also means **nothing moved on either side**; retrying means a\nnew transaction, and so a new `transfer_id`.\n","required":["transfer_id","from","to","token","amount","timestamp_us"],"properties":{"transfer_id":{"$ref":"#/components/schemas/Bytes32","description":"Identity of the transfer intent, `keccak256(abi.encode(signer, nonce, sequence))`, where `sequence` is its position inside a `submitBatch` envelope (`0` for a standalone `transfer`). Computable before submitting."},"from":{"$ref":"#/components/schemas/Address","description":"The debited account, which is also the transaction signer — transfers are not delegable. Matched by the `account` subscription filter, as is `to`."},"to":{"$ref":"#/components/schemas/Address","description":"The credited account, **on this ledger**. Unlike a withdrawal's `to`, this is a Pod address and the funds land there."},"token":{"$ref":"#/components/schemas/Address","description":"Token address on Pod."},"amount":{"type":"string","description":"Amount in Pod's 18 decimals, hex-encoded. A refused transfer still reports the amount that was asked for."},"error":{"type":"string","enum":["insufficient_balance","recipient_not_resident","not_included"],"description":"Absent when the funds moved. `insufficient_balance` — the sender's withdrawable balance did not cover it at execution; admission deliberately does not check the balance, because pending fills can raise it before the tick runs. `recipient_not_resident` — the recipient's account was not resident when the tick ran, so the credit had nowhere to land. `not_included` — the solver omitted a finalized intent before its deadline passed. Treat an unrecognised value as a failure rather than as success: the vocabulary can grow."},"timestamp_us":{"type":"integer","format":"int64","description":"The tick's batch deadline, in microseconds — also the `since` cursor for this subscription."}}},"BlockHeader":{"type":"object","description":"One `newHeads` notification: a block header in the `eth_getBlockByNumber` shape, without\n`transactions`. `timestamp` is the block's batch deadline in seconds. Roots, `parentHash`,\n`mixHash`, `nonce`, `difficulty` and `extraData` are zero placeholders, and `gasLimit` /\n`gasUsed` are `0x0`.\n","properties":{"number":{"type":"string","description":"Block height (hex)."},"hash":{"$ref":"#/components/schemas/Bytes32"},"parentHash":{"$ref":"#/components/schemas/Bytes32"},"mixHash":{"$ref":"#/components/schemas/Bytes32"},"nonce":{"type":"string"},"sha3Uncles":{"$ref":"#/components/schemas/Bytes32"},"logsBloom":{"type":"string"},"transactionsRoot":{"$ref":"#/components/schemas/Bytes32"},"stateRoot":{"$ref":"#/components/schemas/Bytes32"},"receiptsRoot":{"$ref":"#/components/schemas/Bytes32"},"miner":{"$ref":"#/components/schemas/Address"},"difficulty":{"type":"string"},"extraData":{"type":"string"},"size":{"type":"string"},"gasLimit":{"type":"string"},"gasUsed":{"type":"string"},"timestamp":{"type":"string","description":"Batch deadline in seconds (hex)."},"uncles":{"type":"array","items":{"type":"string"}},"baseFeePerGas":{"type":"string"}}}}}}
```

## 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 cancellations, then\nrefused cancels, then modifications, then refused amendments, then fills ascending by\norder id, then the engine's matching-walk removals (`cancel` with `st`\n`post_only_refused` / `self_trade_canceled` / `margin_canceled`), then expirations, then\nADL closes, then backstop sweeps.\n\nThe order is not arbitrary: apply events as they arrive and your book is never transiently\nwrong. Cancellations precede the fills so you never hold an order that has already been\nremoved, and the matching-walk removals sit after the modifications and the fills, so an\norder repriced onto a crossing level and refused for it ends the frame removed, and a\nfill it took before removal lands on a live order.\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."},"book":{"$ref":"#/components/schemas/Bytes32","description":"Absent on `pod_orders_v2`, whose frame names the orderbook; `pod_activity` has its own entries."},"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."},"post_only":{"type":"boolean","description":"Add-liquidity-only — the order may not trade in the batch that admitted it, so it can rest\nthrough a batch it appeared to cross. Omitted means false.\n"},"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","cancel_reject","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. A removal by the matching walk carries\n  `st` (`post_only_refused`, `self_trade_canceled` or `margin_canceled`); a cancel the\n  owner sent, or one the engine made before matching, omits it.\n- `cancel_reject` — a cancel the engine refused. The order still rests; it is named by\n  `id`, the requester by `by`, and `code`/`why` say why.\n- `expire` — removed on reaching its TTL, or an IOC remainder killed in its admission batch.\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` and `cancel_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` and `cancel_reject`: 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","size_above_maximum","size_off_lot","notional_overflow","notional_above_cap","delegation_expired","post_only_ioc","post_only_market_order","unspecified"],"description":"`modify_reject` and `cancel_reject`: 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`. The fee of one fill is `f`.\n"},"f":{"type":"string","description":"`fill` only. The fee charged by this fill, 1e18-scaled decimal."},"st":{"type":"string","enum":["filled","canceled","margin_canceled","self_trade_canceled","expired","post_only_refused"],"description":"The terminal status an event closed the order with.\n\nOn `fill`: present only on the fill that **closed** the order; its absence there means the\norder is still working.\n\nOn `cancel`: present only when the **engine** removed the order rather than the owner\ncancelling it — `post_only_refused` (a `post_only` order that would have taken liquidity in\nthe batch that admitted or re-priced it), `self_trade_canceled` (a resting order that was\nabout to fill against the same owner), or `margin_canceled`. An ordinary cancel\nomits `st`, so a client that ignores the field reads every `cancel` exactly as it did\nbefore.\n\nAn engine removal is ordered after the `modify` and `fill` events in its frame, unlike every other cancel.\nAn order repriced onto a crossing level and refused for it emits `modify` and then `cancel`:\napply them in the order given and the order ends the frame removed, rather than resurrected\nat the refused price.\n"},"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."},"book":{"$ref":"#/components/schemas/Bytes32","description":"Absent on `pod_orders_v2`, whose frame names the orderbook; `pod_activity` has its own entries."},"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."},"post_only":{"type":"boolean","description":"Add-liquidity-only — the order may not trade in the batch that admitted it, so it can rest\nthrough a batch it appeared to cross. Omitted means false.\n"},"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","cancel_reject","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. A removal by the matching walk carries\n  `st` (`post_only_refused`, `self_trade_canceled` or `margin_canceled`); a cancel the\n  owner sent, or one the engine made before matching, omits it.\n- `cancel_reject` — a cancel the engine refused. The order still rests; it is named by\n  `id`, the requester by `by`, and `code`/`why` say why.\n- `expire` — removed on reaching its TTL, or an IOC remainder killed in its admission batch.\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` and `cancel_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` and `cancel_reject`: 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","size_above_maximum","size_off_lot","notional_overflow","notional_above_cap","delegation_expired","post_only_ioc","post_only_market_order","unspecified"],"description":"`modify_reject` and `cancel_reject`: 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`. The fee of one fill is `f`.\n"},"f":{"type":"string","description":"`fill` only. The fee charged by this fill, 1e18-scaled decimal."},"st":{"type":"string","enum":["filled","canceled","margin_canceled","self_trade_canceled","expired","post_only_refused"],"description":"The terminal status an event closed the order with.\n\nOn `fill`: present only on the fill that **closed** the order; its absence there means the\norder is still working.\n\nOn `cancel`: present only when the **engine** removed the order rather than the owner\ncancelling it — `post_only_refused` (a `post_only` order that would have taken liquidity in\nthe batch that admitted or re-priced it), `self_trade_canceled` (a resting order that was\nabout to fill against the same owner), or `margin_canceled`. An ordinary cancel\nomits `st`, so a client that ignores the field reads every `cancel` exactly as it did\nbefore.\n\nAn engine removal is ordered after the `modify` and `fill` events in its frame, unlike every other cancel.\nAn order repriced onto a crossing level and refused for it emits `modify` and then `cancel`:\napply them in the order given and the order ends the frame removed, rather than resurrected\nat the refused price.\n"},"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. This variant carries no\n  status, so an engine removal — such as a refused post-only order — is\n  indistinguishable from a cancel the trader sent. Use `pod_orders_v2`, whose `cancel` event\n  carries `st`, if you need to tell them apart.\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 — the owner's signed position (1e18) before this fill."},"position_after":{"type":"string","nullable":true,"description":"Perp only — signed position (1e18) after this fill."},"realized_pnl":{"type":"string","nullable":true,"description":"Perp only — realized PnL (signed, 1e18 USD) this fill booked on the slice it closed. Null on an opening/increasing fill and on every spot 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","margin_canceled","self_trade_canceled","post_only_refused","invalid"],"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- `margin_canceled`: The engine removed the order because the owner's margin capacity was exhausted\n- `self_trade_canceled`: The engine removed a resting order that was about to fill against another order of the same owner\n- `post_only_refused`: The engine removed a `post_only` order that would have taken liquidity in the batch that admitted (or re-priced) it. Distinct from `canceled` so an engine refusal can be told apart from a cancel the trader sent — see [Post-only orders](https://docs.v2.pod.network/api-reference/applications-precompiles/orderbook)\n- `invalid`: Rejected at execution and never entered the book; the reject reason travels with the status\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":"`funding_settling_index × size − funding_basis` (signed, 1e18 USD). Authoritative and exact."},"funding_basis":{"type":"string","description":"The position's funding ledger, `Σ settling_index × Δsize` (signed,\n1e18 USD). Pair it with the market's live `funding_settling_index`\nto recompute `funding_accrued` exactly between snapshots.\n"},"cost_basis":{"type":"string","description":"The position's price ledger, `Σ clearing × Δsize` (signed, 1e18\nUSD). `mark × size − cost_basis` is `unrealized_pnl`, exactly.\n"},"entry_funding":{"type":"string","description":"Funding accumulator at entry, on `funding_index`'s base (undivided\nby the funding window). Truncating and approximate — the exact pair\nis `funding_basis` with `funding_settling_index`.\n"},"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 × size − cost_basis` — pure price drift (signed, 1e18 USD); funding is reported separately as `funding_accrued`."},"realized_pnl":{"type":"string","description":"Always `\"0\"`; a leg's realized PnL banks into cash when it reaches flat. The lifetime figure is the account-level `total_realized_pnl`."},"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":"`funding_settling_index × size − funding_basis` (signed, 1e18 USD). Authoritative and exact."},"funding_basis":{"type":"string","description":"The position's funding ledger, `Σ settling_index × Δsize` (signed,\n1e18 USD). Pair it with the market's live `funding_settling_index`\nto recompute `funding_accrued` exactly between snapshots.\n"},"cost_basis":{"type":"string","description":"The position's price ledger, `Σ clearing × Δsize` (signed, 1e18\nUSD). `mark × size − cost_basis` is `unrealized_pnl`, exactly.\n"},"entry_funding":{"type":"string","description":"Funding accumulator at entry, on `funding_index`'s base (undivided\nby the funding window). Truncating and approximate — the exact pair\nis `funding_basis` with `funding_settling_index`.\n"},"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 × size − cost_basis` — pure price drift (signed, 1e18 USD); funding is reported separately as `funding_accrued`."},"realized_pnl":{"type":"string","description":"Always `\"0\"`; a leg's realized PnL banks into cash when it reaches flat. The lifetime figure is the account-level `total_realized_pnl`."},"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":"What a withdrawal or transfer can take now (1e18 USD): `max(0, equity − max(initial_margin, transfer_margin_ratio × notional))`, where `notional` is `Σ |size| × mark` and `transfer_margin_ratio` is a network parameter (10% by default). Equity counts unrealized PnL."},"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":"`funding_settling_index × size − funding_basis` (signed, 1e18 USD). Authoritative and exact."},"funding_basis":{"type":"string","description":"The position's funding ledger, `Σ settling_index × Δsize` (signed,\n1e18 USD). Pair it with the market's live `funding_settling_index`\nto recompute `funding_accrued` exactly between snapshots.\n"},"cost_basis":{"type":"string","description":"The position's price ledger, `Σ clearing × Δsize` (signed, 1e18\nUSD). `mark × size − cost_basis` is `unrealized_pnl`, exactly.\n"},"entry_funding":{"type":"string","description":"Funding accumulator at entry, on `funding_index`'s base (undivided\nby the funding window). Truncating and approximate — the exact pair\nis `funding_basis` with `funding_settling_index`.\n"},"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 × size − cost_basis` — pure price drift (signed, 1e18 USD); funding is reported separately as `funding_accrued`."},"realized_pnl":{"type":"string","description":"Always `\"0\"`; a leg's realized PnL banks into cash when it reaches flat. The lifetime figure is the account-level `total_realized_pnl`."},"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 CommitteeResponse object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"CommitteeResponse":{"type":"object","description":"The current validator committee, returned by `pod_getCommittee`.","required":["validators","n","n_minus_3f","n_minus_f"],"properties":{"validators":{"type":"array","description":"`[validator_index, public_key]` pairs, where `public_key` is a `Secp256k1PublicKey`.","items":{"type":"array","minItems":2,"maxItems":2,"items":{"oneOf":[{"type":"integer"},{"$ref":"#/components/schemas/Secp256k1PublicKey"}]}}},"n":{"type":"integer","description":"Committee size."},"n_minus_3f":{"type":"integer","description":"Certificate threshold."},"n_minus_f":{"type":"integer","description":"Quorum."}}},"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/TimestampString","description":"Batch deadline in microseconds, as a decimal string."},"tx_hash":{"$ref":"#/components/schemas/Bytes32"}}},"TimestampString":{"type":"string","pattern":"^[0-9]+$","description":"Unix timestamp in microseconds as a 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."}}}}
```

## 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","schedule"],"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."},"schedule":{"$ref":"#/components/schemas/SolverScheduleStatus"}}},"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/TimestampString","description":"Batch deadline in microseconds, as a decimal string."},"tx_hash":{"$ref":"#/components/schemas/Bytes32"}}},"TimestampString":{"type":"string","pattern":"^[0-9]+$","description":"Unix timestamp in microseconds as a 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."},"SolverScheduleStatus":{"type":"object","description":"The batch-deadline window this instance solves for, and the decision it gives for the next tick.","required":["schedule","next_deadline","producing"],"properties":{"schedule":{"type":"object","nullable":true,"description":"The half-open window `[start_deadline, stop_deadline)` in microseconds; null when the instance is stood down.","properties":{"start_deadline":{"type":"integer","format":"int64"},"stop_deadline":{"type":"integer","format":"int64","nullable":true,"description":"Null means open-ended."}}},"next_deadline":{"$ref":"#/components/schemas/TimestampString","description":"Deadline of the tick the chain will produce next (microseconds, decimal string)."},"producing":{"type":"boolean","description":"Whether `next_deadline` falls inside the window."}}}}}}
```

## The SolverScheduleStatus object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"SolverScheduleStatus":{"type":"object","description":"The batch-deadline window this instance solves for, and the decision it gives for the next tick.","required":["schedule","next_deadline","producing"],"properties":{"schedule":{"type":"object","nullable":true,"description":"The half-open window `[start_deadline, stop_deadline)` in microseconds; null when the instance is stood down.","properties":{"start_deadline":{"type":"integer","format":"int64"},"stop_deadline":{"type":"integer","format":"int64","nullable":true,"description":"Null means open-ended."}}},"next_deadline":{"$ref":"#/components/schemas/TimestampString","description":"Deadline of the tick the chain will produce next (microseconds, decimal string)."},"producing":{"type":"boolean","description":"Whether `next_deadline` falls inside the window."}}},"TimestampString":{"type":"string","pattern":"^[0-9]+$","description":"Unix timestamp in microseconds as a string"}}}}
```

## 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, min(expected_nonce, next_finalized_nonce + 256))`, so at most 256; when more are pending the newest 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 and lifecycle for one orderbook, streamed on the `pod_markets`\nsubscription (one object per orderbook). Optional fields are omitted (not null) when unset —\ne.g. perp-only fields 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)."},"internal":{"type":"boolean","description":"Perp only: `true` when `oracle_price` is a book-derived internal price because every oracle source was stale."},"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_settling_index":{"type":"string","description":"Perp only: the index positions settle against (decimal, 1e18) — see `Market.funding_settling_index`. Omitted until the market's first perp batch after a node start."},"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)."},"status":{"type":"string","enum":["pending","active","disabled","settled"],"description":"Market lifecycle status, as on `ob_getMarkets`."},"live_at_us":{"type":"integer","format":"int64","description":"Batch deadline (microseconds) from which a `pending` market may go `active`. Omitted when not scheduled."},"disable_at_us":{"type":"integer","format":"int64","description":"Batch deadline (microseconds) of a scheduled halt. Omitted when none is scheduled."},"settlement_price":{"type":"string","description":"Price every position was (or will be) closed at (decimal, 1e18). Present once the market is disabled with a settlement price."}}},"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":"What a withdrawal or transfer can take now (1e18 USD): `max(0, equity − max(initial_margin, transfer_margin_ratio × notional))`, where `notional` is `Σ |size| × mark` and `transfer_margin_ratio` is a network parameter (10% by default). Equity counts unrealized PnL."},"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":"`funding_settling_index × size − funding_basis` (signed, 1e18 USD). Authoritative and exact."},"funding_basis":{"type":"string","description":"The position's funding ledger, `Σ settling_index × Δsize` (signed,\n1e18 USD). Pair it with the market's live `funding_settling_index`\nto recompute `funding_accrued` exactly between snapshots.\n"},"cost_basis":{"type":"string","description":"The position's price ledger, `Σ clearing × Δsize` (signed, 1e18\nUSD). `mark × size − cost_basis` is `unrealized_pnl`, exactly.\n"},"entry_funding":{"type":"string","description":"Funding accumulator at entry, on `funding_index`'s base (undivided\nby the funding window). Truncating and approximate — the exact pair\nis `funding_basis` with `funding_settling_index`.\n"},"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 × size − cost_basis` — pure price drift (signed, 1e18 USD); funding is reported separately as `funding_accrued`."},"realized_pnl":{"type":"string","description":"Always `\"0\"`; a leg's realized PnL banks into cash when it reaches flat. The lifetime figure is the account-level `total_realized_pnl`."},"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/TimestampString","description":"Batch deadline the trigger was signed for (microseconds, decimal string)."},"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"],"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\nOmitted from an `Order` response when it is the default `none`.\n"},"TimestampString":{"type":"string","pattern":"^[0-9]+$","description":"Unix timestamp in microseconds as a string"},"Timestamp":{"type":"integer","format":"int64","description":"Unix timestamp in microseconds (not milliseconds or seconds)"}}}}
```

## The WithdrawalUpdate object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"WithdrawalUpdate":{"type":"object","description":"One outcome from `pod_withdrawals` — what became of a single bridge withdrawal when its\ntick executed. The REST backfill (`GET /v1/bridge/withdrawals[/{account}]?since=`) serves the\nidentical shape, so an outcome read after a reconnect is indistinguishable from one that\narrived live.\n\nA withdrawal debits the account's balance, is burned on Pod, and is claimed on the bridge's\nbridged chain; nothing is credited to a Pod account on the way. No `error` means it is on its\nway there. `insufficient_balance` and `not_included` both mean **nothing was debited** — the\nfunds are still on the account and no claim will ever exist — and this is the only\nsurface that carries the reason, so a client watching only the bridged chain waits forever for\nan event that cannot come.\n\nThe claim itself is not here: read it from `GET /v1/bridge/withdrawals/by-id/{tx_hash}`,\nwhich reports `claimable` / `pending` / `refused` and attaches the proof once a certificate\ncan be assembled.\n","required":["tx_hash","withdrawer","to","token","amount","timestamp_us"],"properties":{"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"The `withdraw` transaction's own hash, which is the withdrawal's identity. A withdrawal is always its own transaction — it targets the bridge precompile, so it can be neither a `submitBatch` sub-intent nor a `delegated` inner call — and this is the key the claim is fetched by. Rows predating this design carry a computed `keccak256(abi.encode(signer, nonce, sequence))` id here instead; the same lookups serve both, but only the current generation is a real transaction hash, so do not feed a historical value to `eth_getTransactionByHash`."},"withdrawer":{"$ref":"#/components/schemas/Address","description":"The debited account, and what the `account` subscription filter matches. It is also the transaction signer for current withdrawals; on rows predating this design it can differ, being the master of a delegated withdrawal rather than the delegate that signed."},"to":{"$ref":"#/components/schemas/Address","description":"Recipient **on the bridged chain**. Nothing is credited on Pod."},"token":{"$ref":"#/components/schemas/Address","description":"Pod-side token address. Map it to the asset the claim pays out using the token list from `GET /v1/bridge/config`."},"amount":{"type":"string","description":"Amount in Pod's 18 decimals, hex-encoded — what the user signed and what left the account. The claim carries this converted to the token's bridged-chain decimals, which differs by 10^12 for a 6-decimal token, so never pass this value to `claim`; take that one from the proof response. A refused withdrawal still reports the amount that was asked for."},"error":{"type":"string","enum":["insufficient_balance","not_included"],"description":"Names why the withdrawal was refused. `insufficient_balance` — the balance did not cover it at execution; admission deliberately does not check the balance, because pending fills can raise it before the tick runs. `not_included` — the solver omitted a finalized intent before its deadline passed. Treat an unrecognised value as a failure rather than as success: the vocabulary can grow. An absent `error` is the normal claimable case but is not a guarantee — a node whose bridge config does not cover the token records the row, signs nothing, and reports `refused` with no reason — so confirm against `status`/`proof` rather than treating absent-`error` as \"on its way\"."},"timestamp_us":{"type":"integer","format":"int64","description":"The tick's batch deadline, in microseconds — also the `since` cursor for this subscription and for the REST backfill, so a value read here can be handed straight to either."}}},"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 TransferUpdate object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"TransferUpdate":{"type":"object","description":"One outcome from `pod_transfers` — what became of a single account-to-account transfer when\nits tick executed.\n\nA transfer has no receipt of its own: it is a solver-gated intent that settles inside the\nsolver's `submitSolutions` transaction, and a refused one still consumes its nonce while\nchanging no state. This channel is therefore the only way to tell refused from succeeded.\n\nThe sibling of `WithdrawalUpdate` rather than the same shape: a transfer's `to` is an account\non **this** ledger and the funds land there, while a withdrawal's `to` is an address on the\nbridged chain. Every error here also means **nothing moved on either side**; retrying means a\nnew transaction, and so a new `transfer_id`.\n","required":["transfer_id","from","to","token","amount","timestamp_us"],"properties":{"transfer_id":{"$ref":"#/components/schemas/Bytes32","description":"Identity of the transfer intent, `keccak256(abi.encode(signer, nonce, sequence))`, where `sequence` is its position inside a `submitBatch` envelope (`0` for a standalone `transfer`). Computable before submitting."},"from":{"$ref":"#/components/schemas/Address","description":"The debited account, which is also the transaction signer — transfers are not delegable. Matched by the `account` subscription filter, as is `to`."},"to":{"$ref":"#/components/schemas/Address","description":"The credited account, **on this ledger**. Unlike a withdrawal's `to`, this is a Pod address and the funds land there."},"token":{"$ref":"#/components/schemas/Address","description":"Token address on Pod."},"amount":{"type":"string","description":"Amount in Pod's 18 decimals, hex-encoded. A refused transfer still reports the amount that was asked for."},"error":{"type":"string","enum":["insufficient_balance","recipient_not_resident","not_included"],"description":"Absent when the funds moved. `insufficient_balance` — the sender's withdrawable balance did not cover it at execution; admission deliberately does not check the balance, because pending fills can raise it before the tick runs. `recipient_not_resident` — the recipient's account was not resident when the tick ran, so the credit had nowhere to land. `not_included` — the solver omitted a finalized intent before its deadline passed. Treat an unrecognised value as a failure rather than as success: the vocabulary can grow."},"timestamp_us":{"type":"integer","format":"int64","description":"The tick's batch deadline, in microseconds — also the `since` cursor for this subscription."}}},"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 ActivityFrame object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"ActivityFrame":{"type":"object","description":"One `pod_activity` notification: a map with one key, the tick's deadline in microseconds as\na decimal string (also the `since` to resume from), to the subscribed account's entries in\nthat tick. `GET /v1/clob/activity/{account}` serves the same shape with many keys.\n","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/ActivityEntry"}}},"ActivityEntry":{"type":"object","description":"One `pod_activity` entry, discriminated by `k`. Within a tick, entries are ordered by kind\nin the order of the `k` enum, then by book ascending, then in engine order. Amounts and\nprices are 1e18-scaled decimal strings. Optional fields are omitted rather than `null`;\nboolean flags are omitted when false. Ignore kinds and fields you do not recognise.\n\n- `order` — a placement, as the `Order` object of `GET /v1/clob/orders/{account}` with `k`\n  added (`order_id, orderbook_id, tx_hash, nonce, kind, order_type, status, side, price,\n  initial_size, ...`; its amounts follow that schema, unsigned ones `0x` hex), in its\n  admission state: `status` `active`, or `invalid` with `invalid_reason`, zero totals and\n  `fills: []`. ADL closes appear as orders with `kind` `adl` or `adl_counterparty`,\n  followed by their `fill`s.\n- `fill` — `id, book, b, q, tb, tq, tf, f?, st?, pa?`.\n- `modify` — a resting order changed in place: `id, book, px, sz, old_px, old_sz`.\n- `termination` — an order left the book other than by filling: `id, book, st`.\n- `backstop` — a perp position swept to the backstop (`book` set), or the terminal cash\n  sweep (`book` omitted): `book?, sz, cash, mark, eq, pnl`.\n- `bridge_transfer` — a bridge deposit (positive `amt`) or withdrawal (negative):\n  `tx, idx, tok, amt, err?`.\n- `transfer` — an account-to-account transfer, debit negative, credit positive: `id, cp,\n  tok, amt, err?`. `cp` is the other side: the receiver on a debit, the sender on a credit.\n  A self-transfer is two entries, the debit first. A refused transfer is reported to the\n  sender only.\n- `modify_reject` — an amendment the engine refused; the order is untouched: `id, book, px,\n  sz, why`.\n- `cancel_reject` — a cancel the engine refused; the order still rests: `id, book, why`.\n\nEvery other order entry names its order by `id` and `book`; for an order placed before the\nclient's history, fetch its terms from `GET /v1/clob/orders/{account}`.\n","required":["k"],"properties":{"k":{"type":"string","enum":["order","fill","modify","termination","backstop","bridge_transfer","transfer","modify_reject","cancel_reject"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"The order id; on `transfer`, the transfer id, as `TransferUpdate.transfer_id`."},"tx":{"$ref":"#/components/schemas/Bytes32","description":"`bridge_transfer`: the deposit or `withdraw` transaction."},"book":{"$ref":"#/components/schemas/Bytes32","description":"The orderbook. Omitted on the terminal backstop cash sweep."},"px":{"type":"string","description":"`modify`: the price after the change. `modify_reject`: the price asked for."},"sz":{"type":"string","description":"`modify`: the size after the change, unsigned. `modify_reject`: the size asked for, unsigned. `backstop`: signed position size moved to the backstop."},"why":{"type":"string","description":"`modify_reject`, `cancel_reject`: the engine's reason, always present."},"b":{"type":"string","description":"`fill`: base filled by this fill."},"q":{"type":"string","description":"`fill`: quote filled by this fill."},"tb":{"type":"string","description":"Order's total base filled after this fill (`fill` only)."},"tq":{"type":"string","description":"Order's total quote filled, as `tb`."},"tf":{"type":"string","description":"Order's total fee, as `tb`."},"f":{"type":"string","description":"`fill`: the fee charged by this fill. Omitted on rows stored before it was recorded."},"st":{"type":"string","enum":["filled","canceled","margin_canceled","self_trade_canceled","expired","post_only_refused"],"description":"`fill`: present only on the fill that closed the order. `termination`: how the order left the book (never `filled`)."},"pa":{"type":"string","description":"`fill`: the owner's position after this fill on a perp book, signed. Omitted when no position moved."},"old_px":{"type":"string","description":"`modify`: the price before the change."},"old_sz":{"type":"string","description":"`modify`: the size before the change, unsigned."},"cash":{"type":"string","description":"`backstop`: signed cash moved with it."},"mark":{"type":"string","description":"`backstop`: mark price at the sweep."},"eq":{"type":"string","description":"`backstop`: account equity at the sweep (signed)."},"pnl":{"type":"string","description":"`backstop`: PnL the forced close realized (signed); `0` on the cash sweep."},"idx":{"type":"integer","description":"`bridge_transfer`: position among the tick's deposit outcomes; `0` for a withdrawal."},"cp":{"$ref":"#/components/schemas/Address","description":"`transfer`: the other side, the receiver when `amt` is negative and the sender otherwise; the account itself on a self-transfer."},"tok":{"$ref":"#/components/schemas/Address","description":"`bridge_transfer`, `transfer`: Pod-side token address."},"amt":{"type":"string","description":"`bridge_transfer`, `transfer`: signed amount in Pod's 18 decimals."},"err":{"type":"string","description":"`bridge_transfer`, `transfer`: why the movement was refused — for a deposit `already_processed` or `not_included`, for a withdrawal as `WithdrawalUpdate.error`, for a transfer as `TransferUpdate.error`. Nothing moved; `amt` still reports what was asked for. Absent when it succeeded; treat an unrecognised value as a failure."}}},"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 ActivityEntry object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"ActivityEntry":{"type":"object","description":"One `pod_activity` entry, discriminated by `k`. Within a tick, entries are ordered by kind\nin the order of the `k` enum, then by book ascending, then in engine order. Amounts and\nprices are 1e18-scaled decimal strings. Optional fields are omitted rather than `null`;\nboolean flags are omitted when false. Ignore kinds and fields you do not recognise.\n\n- `order` — a placement, as the `Order` object of `GET /v1/clob/orders/{account}` with `k`\n  added (`order_id, orderbook_id, tx_hash, nonce, kind, order_type, status, side, price,\n  initial_size, ...`; its amounts follow that schema, unsigned ones `0x` hex), in its\n  admission state: `status` `active`, or `invalid` with `invalid_reason`, zero totals and\n  `fills: []`. ADL closes appear as orders with `kind` `adl` or `adl_counterparty`,\n  followed by their `fill`s.\n- `fill` — `id, book, b, q, tb, tq, tf, f?, st?, pa?`.\n- `modify` — a resting order changed in place: `id, book, px, sz, old_px, old_sz`.\n- `termination` — an order left the book other than by filling: `id, book, st`.\n- `backstop` — a perp position swept to the backstop (`book` set), or the terminal cash\n  sweep (`book` omitted): `book?, sz, cash, mark, eq, pnl`.\n- `bridge_transfer` — a bridge deposit (positive `amt`) or withdrawal (negative):\n  `tx, idx, tok, amt, err?`.\n- `transfer` — an account-to-account transfer, debit negative, credit positive: `id, cp,\n  tok, amt, err?`. `cp` is the other side: the receiver on a debit, the sender on a credit.\n  A self-transfer is two entries, the debit first. A refused transfer is reported to the\n  sender only.\n- `modify_reject` — an amendment the engine refused; the order is untouched: `id, book, px,\n  sz, why`.\n- `cancel_reject` — a cancel the engine refused; the order still rests: `id, book, why`.\n\nEvery other order entry names its order by `id` and `book`; for an order placed before the\nclient's history, fetch its terms from `GET /v1/clob/orders/{account}`.\n","required":["k"],"properties":{"k":{"type":"string","enum":["order","fill","modify","termination","backstop","bridge_transfer","transfer","modify_reject","cancel_reject"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"The order id; on `transfer`, the transfer id, as `TransferUpdate.transfer_id`."},"tx":{"$ref":"#/components/schemas/Bytes32","description":"`bridge_transfer`: the deposit or `withdraw` transaction."},"book":{"$ref":"#/components/schemas/Bytes32","description":"The orderbook. Omitted on the terminal backstop cash sweep."},"px":{"type":"string","description":"`modify`: the price after the change. `modify_reject`: the price asked for."},"sz":{"type":"string","description":"`modify`: the size after the change, unsigned. `modify_reject`: the size asked for, unsigned. `backstop`: signed position size moved to the backstop."},"why":{"type":"string","description":"`modify_reject`, `cancel_reject`: the engine's reason, always present."},"b":{"type":"string","description":"`fill`: base filled by this fill."},"q":{"type":"string","description":"`fill`: quote filled by this fill."},"tb":{"type":"string","description":"Order's total base filled after this fill (`fill` only)."},"tq":{"type":"string","description":"Order's total quote filled, as `tb`."},"tf":{"type":"string","description":"Order's total fee, as `tb`."},"f":{"type":"string","description":"`fill`: the fee charged by this fill. Omitted on rows stored before it was recorded."},"st":{"type":"string","enum":["filled","canceled","margin_canceled","self_trade_canceled","expired","post_only_refused"],"description":"`fill`: present only on the fill that closed the order. `termination`: how the order left the book (never `filled`)."},"pa":{"type":"string","description":"`fill`: the owner's position after this fill on a perp book, signed. Omitted when no position moved."},"old_px":{"type":"string","description":"`modify`: the price before the change."},"old_sz":{"type":"string","description":"`modify`: the size before the change, unsigned."},"cash":{"type":"string","description":"`backstop`: signed cash moved with it."},"mark":{"type":"string","description":"`backstop`: mark price at the sweep."},"eq":{"type":"string","description":"`backstop`: account equity at the sweep (signed)."},"pnl":{"type":"string","description":"`backstop`: PnL the forced close realized (signed); `0` on the cash sweep."},"idx":{"type":"integer","description":"`bridge_transfer`: position among the tick's deposit outcomes; `0` for a withdrawal."},"cp":{"$ref":"#/components/schemas/Address","description":"`transfer`: the other side, the receiver when `amt` is negative and the sender otherwise; the account itself on a self-transfer."},"tok":{"$ref":"#/components/schemas/Address","description":"`bridge_transfer`, `transfer`: Pod-side token address."},"amt":{"type":"string","description":"`bridge_transfer`, `transfer`: signed amount in Pod's 18 decimals."},"err":{"type":"string","description":"`bridge_transfer`, `transfer`: why the movement was refused — for a deposit `already_processed` or `not_included`, for a withdrawal as `WithdrawalUpdate.error`, for a transfer as `TransferUpdate.error`. Nothing moved; `amt` still reports what was asked for. Absent when it succeeded; treat an unrecognised value as a failure."}}},"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 BlockHeader object

```json
{"openapi":"3.0.0","info":{"title":"JSON-RPC API","version":"1.0.0"},"components":{"schemas":{"BlockHeader":{"type":"object","description":"One `newHeads` notification: a block header in the `eth_getBlockByNumber` shape, without\n`transactions`. `timestamp` is the block's batch deadline in seconds. Roots, `parentHash`,\n`mixHash`, `nonce`, `difficulty` and `extraData` are zero placeholders, and `gasLimit` /\n`gasUsed` are `0x0`.\n","properties":{"number":{"type":"string","description":"Block height (hex)."},"hash":{"$ref":"#/components/schemas/Bytes32"},"parentHash":{"$ref":"#/components/schemas/Bytes32"},"mixHash":{"$ref":"#/components/schemas/Bytes32"},"nonce":{"type":"string"},"sha3Uncles":{"$ref":"#/components/schemas/Bytes32"},"logsBloom":{"type":"string"},"transactionsRoot":{"$ref":"#/components/schemas/Bytes32"},"stateRoot":{"$ref":"#/components/schemas/Bytes32"},"receiptsRoot":{"$ref":"#/components/schemas/Bytes32"},"miner":{"$ref":"#/components/schemas/Address"},"difficulty":{"type":"string"},"extraData":{"type":"string"},"size":{"type":"string"},"gasLimit":{"type":"string"},"gasUsed":{"type":"string"},"timestamp":{"type":"string","description":"Batch deadline in seconds (hex)."},"uncles":{"type":"array","items":{"type":"string"}},"baseFeePerGas":{"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)"}}}}
```


# REST API

Pod full nodes serve a read-only REST API under `/v1` on the JSON-RPC port. The base URL is the RPC URL plus `/v1`; for the testnet, `https://rpc.podtestnet.dev/v1`. All routes are `GET` and allow any origin (CORS).

* Markets, Account and Explorer routes (`/v1/clob/*`, `/v1/tx/{hash}`, `/v1/transactions`) require a node running the CLOB indexer.
* Bridge routes (`/v1/bridge/*`) are served by every node.

Errors are plain text: `400` for a malformed path or query parameter, `404` where a route says so, and `503` (`clob indexer unavailable`) when the indexer or execution engine could not answer. Bridge routes answer a failed read with an empty `500`.

***

### Caching

Responses carry a `Cache-Control` header:

| Header                                | Routes                                                                                                                                                                                                                        |
| ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `public, max-age=31536000, immutable` | `candles` once every bucket of the requested window has closed; `orders` once the page's upper bound has been reached by solution time and every order on it is terminal; `activity` once `to` is at or below `solution_now`. |
| `public, max-age=60`                  | `markets`.                                                                                                                                                                                                                    |
| `no-store`                            | Everything else under `/v1/clob`, `/v1/tx` and `/v1/transactions`, and the cases above that are not yet final.                                                                                                                |

Bridge routes set no `Cache-Control` header.

To get a cacheable page, bound it in the past: pass `to` on `candles` and `activity` (an `activity` page's `next` is the `to` for the older page), and `until` or a `cursor` on `orders`.

An `activity` page holds whole batches: `limit` counts entries, but the newest batch is always served whole, so a page can exceed `limit` when one batch alone holds more.

### Encodings

| Value                                                                          | Encoding                                                                                                                                                                                                                                                          |
| ------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Addresses, hashes, orderbook ids                                               | `0x` hex. Orderbook ids are always the full 32 bytes.                                                                                                                                                                                                             |
| Timestamps                                                                     | Microseconds, as JSON numbers — except order and trigger `deadline` and the `activity` batch keys and `next`, which are decimal strings. Order `end` is a number that can exceed a JavaScript safe integer (`18446744073709551615` for orders that never expire). |
| Unsigned amounts and prices (1e18)                                             | `0x` hex on `candles`, `orderbook` (price-level keys are decimal strings), `solutions`, `orders`, `fills`, `positions`, `balances`, `triggers`, the `order` entries of `activity`, and the bridge routes.                                                         |
| Signed amounts (sizes, PnL, funding)                                           | Decimal strings everywhere.                                                                                                                                                                                                                                       |
| `markets`, `markets/stats`, `backstop-transfers`, non-order `activity` entries | Every amount and price is a decimal string.                                                                                                                                                                                                                       |
| Bridge `proof`, `aux_tx_suffix`                                                | JSON arrays of byte values.                                                                                                                                                                                                                                       |

Query parameters follow their route: `candles` `from`/`to` and `orders` `until` are unix seconds; every other time parameter is microseconds.

### REST then websocket

REST seeds state; the [websocket subscriptions](/guides-references/references/json-rpc) keep it current. Seed responses carry `solution_now` (`solution_now_us` on `candles`), the newest batch deadline they reflect. Subscribe with `since` set to that value. Delta channels replay every tick after it; state channels (`pod_markets`, `pod_positions`, `pod_triggers`) send one current snapshot. If the channel rejects `since` as too old, seed from REST again.

| Seed from                          | Then subscribe to                                                                                                                                                                                   |
| ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `/v1/clob/orders/{account}`        | `pod_orders_v2`                                                                                                                                                                                     |
| `/v1/clob/activity/{account}`      | `pod_activity`                                                                                                                                                                                      |
| `/v1/clob/candles/{orderbook}`     | `pod_candles` (`since` is the forming bucket's start − 1µs, so its earlier trades replay; replay holds 16,384 ticks, about 2.3h, so above `1h` seed the forming bar from closed `1h` candles first) |
| `/v1/clob/markets/stats`           | `pod_markets`                                                                                                                                                                                       |
| `/v1/bridge/withdrawals/{account}` | `pod_withdrawals` (`since` is the last `timestamp_us`)                                                                                                                                              |


# Markets

Market configuration, live statistics, candles, the resting book and per-tick solution history.

&#x20;   &#x20;

## Get Solution Time

> The indexer's solution time: the newest indexed batch deadline, in microseconds.\
> Use it as \`since\` when subscribing over the websocket after a REST read.\
> \
> \`Cache-Control: no-store\`.<br>

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"tags":[{"name":"Markets","description":"Market configuration, live statistics, candles, the resting book and per-tick\nsolution history.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/v1","description":"Pod testnet"}],"paths":{"/clob/status":{"get":{"tags":["Markets"],"summary":"Get Solution Time","operationId":"getClobStatus","description":"The indexer's solution time: the newest indexed batch deadline, in microseconds.\nUse it as `since` when subscribing over the websocket after a REST read.\n\n`Cache-Control: no-store`.\n","responses":{"200":{"description":"Solution time","content":{"application/json":{"schema":{"type":"object","required":["solution_now"],"properties":{"solution_now":{"$ref":"#/components/schemas/Timestamp"}}}}}},"503":{"$ref":"#/components/responses/Unavailable"}}}}},"components":{"schemas":{"Timestamp":{"type":"integer","format":"int64","description":"Unix time in microseconds, as a JSON number"}},"responses":{"Unavailable":{"description":"The indexer or execution engine read failed. Body `clob indexer unavailable`, with `Cache-Control: no-store`.","content":{"text/plain":{"schema":{"type":"string"}}}}}}}
```

## List Markets

> Every market's static configuration and lifecycle status, including markets\
> created after the node started. Live statistics are on \`/clob/markets/stats\`.\
> \
> \`Cache-Control: public, max-age=60\`.<br>

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"tags":[{"name":"Markets","description":"Market configuration, live statistics, candles, the resting book and per-tick\nsolution history.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/v1","description":"Pod testnet"}],"paths":{"/clob/markets":{"get":{"tags":["Markets"],"summary":"List Markets","operationId":"getMarkets","description":"Every market's static configuration and lifecycle status, including markets\ncreated after the node started. Live statistics are on `/clob/markets/stats`.\n\n`Cache-Control: public, max-age=60`.\n","responses":{"200":{"description":"Market list","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MarketStatic"}}}}}}}}},"components":{"schemas":{"MarketStatic":{"type":"object","description":"Static market configuration. Numeric amounts are decimal strings.","properties":{"status":{"type":"string","enum":["pending","active","disabled","settled"],"description":"Lifecycle status."},"id":{"$ref":"#/components/schemas/Bytes32"},"name":{"type":"string","description":"`{base_symbol}/{quote_symbol}`"},"base_token_address":{"$ref":"#/components/schemas/Address"},"quote_token_address":{"$ref":"#/components/schemas/Address"},"base_token_symbol":{"type":"string"},"quote_token_symbol":{"type":"string"},"base_token_name":{"type":"string"},"quote_token_name":{"type":"string"},"market_type":{"type":"string","enum":["spot","perp"],"description":"Order rows spell this `perpetual`."},"auction_interval_us":{"type":"integer","format":"int64","description":"Batch interval, microseconds"},"maker_fee":{"type":"string","description":"Fee rate as a decimal fraction, six places (`\"0.000150\"` is 1.5 bps)."},"taker_fee":{"type":"string","description":"Fee rate as a decimal fraction, six places."},"tick_precision":{"$ref":"#/components/schemas/DecimalUint256"},"lot_size":{"$ref":"#/components/schemas/DecimalUint256"},"min_notional":{"type":"string","description":"Minimum quote notional per order, 1e18-scaled decimal string. `\"0\"` is no floor."},"max_leverage":{"type":"integer"},"initial_margin":{"type":"string","description":"Initial-margin rate, 1e18-scaled decimal string, unrounded (`max_leverage` is rounded)."},"funding_window_us":{"type":"integer","format":"int64","description":"Period `funding_rate` applies over, microseconds"},"live_at_us":{"type":"integer","format":"int64","description":"When a `pending` market goes live, microseconds. Omitted when not scheduled."},"disable_at_us":{"type":"integer","format":"int64","description":"Scheduled halt, microseconds. Omitted when none."},"settlement_price":{"type":"string","description":"Price open positions settle at, fixed when a perp market halts. 1e18-scaled decimal string. Omitted until then."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"DecimalUint256":{"type":"string","pattern":"^[0-9]+$","description":"Unsigned 256-bit integer, decimal string"}}}}
```

## Get Market Statistics

> Live per-market statistics, overlaying the forming candle. Same entry shape as the\
> \`pod\_markets\` websocket channel. Sorted by \`orderbook\_id\`.\
> \
> \`Cache-Control: no-store\`.<br>

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"tags":[{"name":"Markets","description":"Market configuration, live statistics, candles, the resting book and per-tick\nsolution history.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/v1","description":"Pod testnet"}],"paths":{"/clob/markets/stats":{"get":{"tags":["Markets"],"summary":"Get Market Statistics","operationId":"getMarketStats","description":"Live per-market statistics, overlaying the forming candle. Same entry shape as the\n`pod_markets` websocket channel. Sorted by `orderbook_id`.\n\n`Cache-Control: no-store`.\n","responses":{"200":{"description":"Statistics for every market","content":{"application/json":{"schema":{"type":"object","required":["solution_now","markets"],"properties":{"solution_now":{"$ref":"#/components/schemas/Timestamp"},"markets":{"type":"array","items":{"$ref":"#/components/schemas/MarketStats"}}}}}}},"503":{"$ref":"#/components/responses/Unavailable"}}}}},"components":{"schemas":{"Timestamp":{"type":"integer","format":"int64","description":"Unix time in microseconds, as a JSON number"},"MarketStats":{"type":"object","description":"Live statistics for one market. Prices and amounts are 1e18-scaled decimal\nstrings. Optional fields are omitted until the data exists.\n","required":["orderbook_id","volume_24h"],"properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"last_clearing_price":{"type":"string","description":"Omitted until the market's first fill."},"volume_24h":{"type":"string","description":"Quote notional traded over 24 hours."},"high_24h":{"type":"string","description":"Omitted until the market has a closed candle."},"low_24h":{"type":"string","description":"Omitted until the market has a closed candle."},"price_change_24h":{"type":"integer","description":"24-hour price change in basis points."},"oracle_price":{"type":"string","description":"Perp only."},"internal":{"type":"boolean","description":"`true` when `oracle_price` is derived from the book because every oracle source was stale."},"mark_price":{"type":"string","description":"Perp only."},"funding_rate":{"type":"string","description":"Perp only. Signed."},"funding_index":{"type":"string","description":"Perp only. Signed, undivided funding accumulator."},"funding_settling_index":{"type":"string","description":"Perp only. The index positions settle against (`funding_settling_index × size − funding_basis` is a position's accrual). Absent until the market's first perp batch after the node started."},"funding_last_updated_us":{"type":"integer","format":"int64","description":"Perp only."},"open_interest":{"type":"string","description":"Perp only. USD notional."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."}},"responses":{"Unavailable":{"description":"The indexer or execution engine read failed. Body `clob indexer unavailable`, with `Cache-Control: no-store`.","content":{"text/plain":{"schema":{"type":"string"}}}}}}}
```

## Get Candles

> Closed OHLCV bars in the half-open window \`\[from, to)\`, newest first. The forming\
> bar is dropped after \`limit\` applies, so a page that reaches the present can hold\
> one bar fewer than \`limit\`.\
> \
> Page back with \`to = range.from\_us / 1e6\`. The forming bar is the bucket containing\
> \`solution\_now\_us\`; build it from the \`pod\_candles\` websocket channel, subscribed\
> with \`since\` one microsecond before that bucket's start.\
> \
> An orderbook id that names no book returns an empty window.\
> \
> \`Cache-Control: public, max-age=31536000, immutable\` once every bucket of the\
> window has closed, otherwise \`no-store\`.<br>

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"tags":[{"name":"Markets","description":"Market configuration, live statistics, candles, the resting book and per-tick\nsolution history.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/v1","description":"Pod testnet"}],"paths":{"/clob/candles/{orderbook}":{"get":{"tags":["Markets"],"summary":"Get Candles","operationId":"getCandles","description":"Closed OHLCV bars in the half-open window `[from, to)`, newest first. The forming\nbar is dropped after `limit` applies, so a page that reaches the present can hold\none bar fewer than `limit`.\n\nPage back with `to = range.from_us / 1e6`. The forming bar is the bucket containing\n`solution_now_us`; build it from the `pod_candles` websocket channel, subscribed\nwith `since` one microsecond before that bucket's start.\n\nAn orderbook id that names no book returns an empty window.\n\n`Cache-Control: public, max-age=31536000, immutable` once every bucket of the\nwindow has closed, otherwise `no-store`.\n","parameters":[{"$ref":"#/components/parameters/OrderbookPath"},{"name":"resolution","in":"query","required":true,"schema":{"$ref":"#/components/schemas/CandleResolution"}},{"name":"from","in":"query","description":"Window start, unix seconds, inclusive.","schema":{"type":"integer","format":"int64","default":0}},{"name":"to","in":"query","description":"Window end, unix seconds, exclusive. Defaults to solution time.","schema":{"type":"integer","format":"int64"}},{"name":"limit","in":"query","description":"Maximum bars. Above 500 is a `400`.","schema":{"type":"integer","minimum":0,"maximum":500,"default":500}}],"responses":{"200":{"description":"Candle page","content":{"application/json":{"schema":{"type":"object","required":["candles","resolution","range","solution_now_us"],"properties":{"candles":{"type":"array","items":{"$ref":"#/components/schemas/Candle"}},"resolution":{"$ref":"#/components/schemas/CandleResolution"},"range":{"type":"object","nullable":true,"description":"Bucket starts of the oldest and newest bar returned, in microseconds. `null` when no bar matched.","properties":{"from_us":{"type":"integer","format":"int64"},"to_us":{"type":"integer","format":"int64"}}},"solution_now_us":{"$ref":"#/components/schemas/Timestamp"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"503":{"$ref":"#/components/responses/Unavailable"}}}}},"components":{"parameters":{"OrderbookPath":{"name":"orderbook","in":"path","required":true,"description":"32-byte orderbook id.","schema":{"$ref":"#/components/schemas/Bytes32"}}},"schemas":{"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"CandleResolution":{"type":"string","enum":["1m","5m","15m","30m","1h","4h","1d","1w","1M"]},"Candle":{"type":"object","description":"One closed OHLCV bar. Prices and volumes are 1e18-scaled `0x` hex.","properties":{"timestamp":{"$ref":"#/components/schemas/Timestamp"},"open":{"$ref":"#/components/schemas/HexUint256"},"close":{"$ref":"#/components/schemas/HexUint256"},"high":{"$ref":"#/components/schemas/HexUint256"},"low":{"$ref":"#/components/schemas/HexUint256"},"volume":{"$ref":"#/components/schemas/HexUint256","description":"Base volume traded in the bucket."},"quote_volume":{"$ref":"#/components/schemas/HexUint256","description":"Quote notional traded in the bucket."}}},"Timestamp":{"type":"integer","format":"int64","description":"Unix time in microseconds, as a JSON number"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"}},"responses":{"BadRequest":{"description":"Malformed path or query parameter. Plain-text reason.","content":{"text/plain":{"schema":{"type":"string"}}}},"Unavailable":{"description":"The indexer or execution engine read failed. Body `clob indexer unavailable`, with `Cache-Control: no-store`.","content":{"text/plain":{"schema":{"type":"string"}}}}}}}
```

## Get Orderbook

> The resting book as of the latest batch that cleared this orderbook. Optionally\
> truncated to the best \`depth\` price levels per side; \`buys\_count\` and\
> \`sells\_count\` still count the full book.\
> \
> \`Cache-Control: no-store\`.<br>

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"tags":[{"name":"Markets","description":"Market configuration, live statistics, candles, the resting book and per-tick\nsolution history.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/v1","description":"Pod testnet"}],"paths":{"/clob/orderbook/{orderbook}":{"get":{"tags":["Markets"],"summary":"Get Orderbook","operationId":"getOrderbook","description":"The resting book as of the latest batch that cleared this orderbook. Optionally\ntruncated to the best `depth` price levels per side; `buys_count` and\n`sells_count` still count the full book.\n\n`Cache-Control: no-store`.\n","parameters":[{"$ref":"#/components/parameters/OrderbookPath"},{"name":"depth","in":"query","description":"Best price levels per side. `0` is a `400`. Omit for the whole book.","schema":{"type":"integer","minimum":1}}],"responses":{"200":{"description":"Orderbook snapshot","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderbookSnapshot"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"description":"No batch has cleared this orderbook since the node started, or the id names no\nbook. Body `no orderbook snapshot yet`.\n","content":{"text/plain":{"schema":{"type":"string"}}}}}}}},"components":{"parameters":{"OrderbookPath":{"name":"orderbook","in":"path","required":true,"description":"32-byte orderbook id.","schema":{"$ref":"#/components/schemas/Bytes32"}}},"schemas":{"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"OrderbookSnapshot":{"type":"object","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"buys":{"type":"object","additionalProperties":{"type":"object","properties":{"volume":{"$ref":"#/components/schemas/HexUint256"}}},"description":"Buy levels keyed by price (decimal string), price-ascending; the best bid is the last key."},"sells":{"type":"object","additionalProperties":{"type":"object","properties":{"volume":{"$ref":"#/components/schemas/HexUint256"}}},"description":"Sell levels keyed by price (decimal string), price-ascending; the best ask is the first key."},"buys_count":{"type":"integer","description":"Buy levels in the full book."},"sells_count":{"type":"integer","description":"Sell levels in the full book."},"grouping_precision":{"$ref":"#/components/schemas/HexUint256"},"timestamp":{"$ref":"#/components/schemas/Timestamp"},"new_orders_count":{"type":"integer"},"clearing_price":{"$ref":"#/components/schemas/HexUint256","description":"The orderbook's current mark, carried forward on ticks without fills."},"oracle_price":{"type":"string","nullable":true,"description":"Perp only, `0x` hex. `null` for spot."},"funding_rate":{"type":"string","nullable":true,"description":"Perp only, signed decimal string. `null` for spot."},"funding_index":{"type":"string","nullable":true,"description":"Perp only, signed decimal string. `null` for spot."},"funding_last_updated":{"type":"integer","format":"int64","nullable":true,"description":"Perp only, microseconds. `null` for spot."}}},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"},"Timestamp":{"type":"integer","format":"int64","description":"Unix time in microseconds, as a JSON number"}},"responses":{"BadRequest":{"description":"Malformed path or query parameter. Plain-text reason.","content":{"text/plain":{"schema":{"type":"string"}}}}}}}
```

## Get Solutions

> Per-tick solution history: clearing, mark and oracle prices, volume, funding,\
> open interest and the mark/funding inputs. Newest first, in whole ticks: \`limit\`\
> counts ticks, and a tick carries one row per orderbook.\
> \
> Page back by passing the oldest \`timestamp\` of the previous page as \`until\_us\`.\
> \
> An orderbook id that names no book returns no rows.\
> \
> \`Cache-Control: no-store\`.<br>

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"tags":[{"name":"Markets","description":"Market configuration, live statistics, candles, the resting book and per-tick\nsolution history.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/v1","description":"Pod testnet"}],"paths":{"/clob/solutions":{"get":{"tags":["Markets"],"summary":"Get Solutions","operationId":"getSolutions","description":"Per-tick solution history: clearing, mark and oracle prices, volume, funding,\nopen interest and the mark/funding inputs. Newest first, in whole ticks: `limit`\ncounts ticks, and a tick carries one row per orderbook.\n\nPage back by passing the oldest `timestamp` of the previous page as `until_us`.\n\nAn orderbook id that names no book returns no rows.\n\n`Cache-Control: no-store`.\n","parameters":[{"$ref":"#/components/parameters/OrderbookQuery"},{"name":"since_us","in":"query","description":"Lower bound on the batch deadline, microseconds, inclusive.","schema":{"$ref":"#/components/schemas/TimestampString"}},{"name":"until_us","in":"query","description":"Upper bound on the batch deadline, microseconds, exclusive.","schema":{"$ref":"#/components/schemas/TimestampString"}},{"name":"limit","in":"query","description":"Ticks per page, clamped to `[1, 200]`.","schema":{"type":"integer","minimum":1,"maximum":200,"default":200}}],"responses":{"200":{"description":"Solution rows","content":{"application/json":{"schema":{"type":"object","required":["solutions"],"properties":{"solutions":{"type":"array","items":{"$ref":"#/components/schemas/Solution"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"503":{"$ref":"#/components/responses/Unavailable"}}}}},"components":{"parameters":{"OrderbookQuery":{"name":"orderbook","in":"query","description":"Restrict to one orderbook (32-byte id).","schema":{"$ref":"#/components/schemas/Bytes32"}}},"schemas":{"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"TimestampString":{"type":"string","pattern":"^[0-9]+$","description":"Unix time in microseconds, as a decimal string"},"Solution":{"type":"object","description":"One orderbook's record for one tick. Unsigned values are 1e18-scaled `0x` hex,\nsigned values decimal strings. Perp-only fields are omitted on spot ticks and on\nrows recorded before the field existed.\n","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"timestamp":{"$ref":"#/components/schemas/Timestamp","description":"Batch deadline."},"clearing_price":{"$ref":"#/components/schemas/HexUint256","description":"Omitted for a market that has never traded."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"`0x0` for spot."},"volume":{"$ref":"#/components/schemas/HexUint256"},"oracle_price":{"$ref":"#/components/schemas/HexUint256"},"funding_rate":{"$ref":"#/components/schemas/DecimalInt256"},"funding_index":{"$ref":"#/components/schemas/DecimalInt256"},"open_interest":{"$ref":"#/components/schemas/HexUint256"},"mark_best_bid":{"$ref":"#/components/schemas/HexUint256"},"mark_best_ask":{"$ref":"#/components/schemas/HexUint256"},"premium_ema":{"$ref":"#/components/schemas/DecimalInt256"},"book_median_ema":{"$ref":"#/components/schemas/HexUint256"},"impact_bid":{"$ref":"#/components/schemas/HexUint256"},"impact_ask":{"$ref":"#/components/schemas/HexUint256"}}},"Timestamp":{"type":"integer","format":"int64","description":"Unix time in microseconds, as a JSON number"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"},"DecimalInt256":{"type":"string","pattern":"^-?[0-9]+$","description":"Signed 256-bit integer, decimal string"}},"responses":{"BadRequest":{"description":"Malformed path or query parameter. Plain-text reason.","content":{"text/plain":{"schema":{"type":"string"}}}},"Unavailable":{"description":"The indexer or execution engine read failed. Body `clob indexer unavailable`, with `Cache-Control: no-store`.","content":{"text/plain":{"schema":{"type":"string"}}}}}}}
```


# Account

One account's orders, fills, positions, balances, triggers, backstop transfers and unified activity feed. `{account}` is a 20-byte `0x` address.

&#x20;   &#x20;

## Get Orders

> The account's orders with their fills, newest first by \`(deadline, nonce,\
> order\_id)\`. \`/clob/fills/{account}\` and the activity \`fill\` entries are the per-fill\
> record that also carries the fee and running totals. Backstop position transfers\
> appear as terminal rows with \`kind: backstop\_transfer\`.\
> \
> Two paging modes:\
> \- Cursor (default): pass \`next\_cursor\` back as \`cursor\`; \`null\` on the last page.\
> &#x20; \`until\` bounds the first page.\
> \- Offset: set \`offset\`. \`cursor\` and \`until\` are then ignored and \`next\_cursor\`\
> &#x20; is \`null\`; page with \`offset += limit\` while \`offset < total\_count\`.\
> \
> \`Cache-Control: public, max-age=31536000, immutable\` when the page's upper bound\
> (\`cursor\` or \`until\`) has been reached by solution time and every returned order\
> is terminal, otherwise \`no-store\`. Offset pages are \`no-store\`.<br>

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"tags":[{"name":"Account","description":"One account's orders, fills, positions, balances, triggers, backstop transfers and\nunified activity feed. `{account}` is a 20-byte `0x` address.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/v1","description":"Pod testnet"}],"paths":{"/clob/orders/{account}":{"get":{"tags":["Account"],"summary":"Get Orders","operationId":"getOrders","description":"The account's orders with their fills, newest first by `(deadline, nonce,\norder_id)`. `/clob/fills/{account}` and the activity `fill` entries are the per-fill\nrecord that also carries the fee and running totals. Backstop position transfers\nappear as terminal rows with `kind: backstop_transfer`.\n\nTwo paging modes:\n- Cursor (default): pass `next_cursor` back as `cursor`; `null` on the last page.\n  `until` bounds the first page.\n- Offset: set `offset`. `cursor` and `until` are then ignored and `next_cursor`\n  is `null`; page with `offset += limit` while `offset < total_count`.\n\n`Cache-Control: public, max-age=31536000, immutable` when the page's upper bound\n(`cursor` or `until`) has been reached by solution time and every returned order\nis terminal, otherwise `no-store`. Offset pages are `no-store`.\n","parameters":[{"$ref":"#/components/parameters/AccountPath"},{"name":"until","in":"query","description":"Upper bound on order deadline, unix seconds. Ignored when `cursor` or `offset` is set.","schema":{"type":"integer","format":"int64"}},{"name":"limit","in":"query","description":"Page size, capped at 500.","schema":{"type":"integer","minimum":0,"maximum":500,"default":500}},{"name":"cursor","in":"query","description":"`next_cursor` from the previous page, `\"{deadline_us}:{nonce}:{order_id_hex}\"`. Malformed is a `400`.","schema":{"type":"string"}},{"name":"offset","in":"query","description":"Skip this many newest-first rows. Switches to offset mode.","schema":{"type":"integer","minimum":0}},{"name":"orderbook","in":"query","description":"Restrict to one orderbook. An id wider than the node's 32-bit form is a `400`.","schema":{"$ref":"#/components/schemas/Bytes32"}},{"name":"status","in":"query","description":"Restrict to one status. Unknown values are a `400`.","schema":{"$ref":"#/components/schemas/OrderStatus"}}],"responses":{"200":{"description":"Order page","content":{"application/json":{"schema":{"type":"object","required":["orders","next_cursor","total_count","solution_now"],"properties":{"orders":{"type":"array","items":{"$ref":"#/components/schemas/Order"}},"next_cursor":{"type":"string","nullable":true,"description":"Cursor for the next page. `null` on the last page and in offset mode."},"total_count":{"type":"integer","description":"Orders matching the filters, across all pages."},"solution_now":{"$ref":"#/components/schemas/Timestamp"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"503":{"$ref":"#/components/responses/Unavailable"}}}}},"components":{"parameters":{"AccountPath":{"name":"account","in":"path","required":true,"schema":{"$ref":"#/components/schemas/Address"}}},"schemas":{"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"OrderStatus":{"type":"string","enum":["pending","active","filled","expired","canceled","margin_canceled","self_trade_canceled","post_only_refused","invalid"],"description":"- `pending`: submitted, not yet in the book\n- `active`: resting in the book\n- `filled`: completely filled\n- `expired`: TTL passed\n- `canceled`: canceled by the owner\n- `margin_canceled`: removed by the engine because the owner's margin was exhausted\n- `self_trade_canceled`: removed by the engine because it was about to fill against an order of the same owner\n- `post_only_refused`: a `post_only` order removed because it would have taken liquidity in the batch that admitted it\n- `invalid`: rejected at execution and never entered the book; see `invalid_reason`\n\nEverything except `pending` and `active` is terminal.\n"},"Order":{"type":"object","description":"An order with its fills. Unsigned amounts and prices are 1e18-scaled `0x` hex,\nsigned ones decimal strings. Perp-only fields are omitted on spot orders.\n","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"market_type":{"$ref":"#/components/schemas/MarketType"},"kind":{"$ref":"#/components/schemas/OrderKind"},"order_id":{"$ref":"#/components/schemas/Bytes32"},"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"Creating transaction. Zero for engine-generated orders."},"bidder":{"$ref":"#/components/schemas/Address"},"nonce":{"type":"integer","format":"int64"},"order_type":{"type":"string","enum":["limit","market"]},"status":{"$ref":"#/components/schemas/OrderStatus"},"side":{"type":"string","enum":["buy","sell"]},"price":{"$ref":"#/components/schemas/HexUint256"},"initial_size":{"$ref":"#/components/schemas/DecimalInt256","description":"Signed; positive buy/long, negative sell/short."},"filled_base_amount":{"$ref":"#/components/schemas/HexUint256"},"filled_quote_amount":{"$ref":"#/components/schemas/HexUint256"},"fee":{"$ref":"#/components/schemas/HexUint256"},"deadline":{"$ref":"#/components/schemas/TimestampString","description":"The batch the order targets, microseconds, as a string."},"end":{"$ref":"#/components/schemas/Timestamp","description":"TTL expiry, microseconds. Orders that never expire carry `18446744073709551615`, which exceeds a JavaScript safe integer."},"included_batch":{"$ref":"#/components/schemas/Timestamp","description":"Deadline of the batch that first included the order. `0` for engine-generated orders and older rows."},"invalid_reason":{"type":"string","description":"Why the engine rejected the order. Only when `status` is `invalid`."},"effective_price":{"$ref":"#/components/schemas/HexUint256","description":"`filled_quote / filled_base` so far."},"fills":{"type":"array","items":{"$ref":"#/components/schemas/PartialFill"},"description":"Always present, oldest first."},"reduce_only":{"type":"boolean","description":"Perp only."},"ioc":{"type":"boolean","description":"Perp only."},"post_only":{"type":"boolean","description":"Omitted when false."},"direction":{"$ref":"#/components/schemas/OrderDirection"},"realized_pnl":{"$ref":"#/components/schemas/DecimalInt256","description":"Perp only, present once a fill closed exposure. Price drift minus funding across the slices it closed."},"grouping":{"$ref":"#/components/schemas/TriggerGrouping","description":"Inherited from the parent trigger. Omitted when `none`."},"trigger_type":{"$ref":"#/components/schemas/TriggerType","description":"Set only on orders a fired trigger produced (`kind` `triggered`)."}}},"MarketType":{"type":"string","enum":["spot","perpetual"]},"OrderKind":{"type":"string","enum":["user_signed","liquidation","triggered","adl","adl_counterparty","backstop_transfer"],"description":"- `user_signed`: submitted by the account\n- `liquidation`: generated by the engine when the account fell below maintenance margin\n- `triggered`: the order a fired TP/SL trigger produced\n- `adl`: auto-deleveraging close of this account's position\n- `adl_counterparty`: this account's side covering an auto-deleveraging close\n- `backstop_transfer`: a backstop sweep of this account's position, shown as a terminal order\n"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"},"DecimalInt256":{"type":"string","pattern":"^-?[0-9]+$","description":"Signed 256-bit integer, decimal string"},"TimestampString":{"type":"string","pattern":"^[0-9]+$","description":"Unix time in microseconds, as a decimal string"},"Timestamp":{"type":"integer","format":"int64","description":"Unix time in microseconds, as a JSON number"},"PartialFill":{"type":"object","properties":{"base_amount":{"$ref":"#/components/schemas/HexUint256"},"quote_amount":{"$ref":"#/components/schemas/HexUint256"},"timestamp":{"$ref":"#/components/schemas/Timestamp"},"price":{"$ref":"#/components/schemas/HexUint256","description":"The batch's clearing price; the order's own price for ADL fills."}}},"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":"Spot orders use `buy`/`sell`. Perp orders use the position effect of their fills; `liquidation` when `kind` is `liquidation`."},"TriggerGrouping":{"type":"string","enum":["none","asset"],"description":"- `none`: standalone; removed only by cancel, TTL expiry or its own fire\n- `asset`: removed, with any resting order it produced, once the owner's position on the pair (perp) or base holding (spot) reaches zero\n"},"TriggerType":{"type":"string","enum":["take_profit","stop_loss"]}},"responses":{"BadRequest":{"description":"Malformed path or query parameter. Plain-text reason.","content":{"text/plain":{"schema":{"type":"string"}}}},"Unavailable":{"description":"The indexer or execution engine read failed. Body `clob indexer unavailable`, with `Cache-Control: no-store`.","content":{"text/plain":{"schema":{"type":"string"}}}}}}}
```

## Get Fills

> The account's fills in the window \`\[from\_us, to\_us)\`, newest first. Capped at 500\
> rows; narrow the window to read further back.\
> \
> An orderbook id that names no book returns no rows.\
> \
> \`Cache-Control: no-store\`.<br>

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"tags":[{"name":"Account","description":"One account's orders, fills, positions, balances, triggers, backstop transfers and\nunified activity feed. `{account}` is a 20-byte `0x` address.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/v1","description":"Pod testnet"}],"paths":{"/clob/fills/{account}":{"get":{"tags":["Account"],"summary":"Get Fills","operationId":"getFills","description":"The account's fills in the window `[from_us, to_us)`, newest first. Capped at 500\nrows; narrow the window to read further back.\n\nAn orderbook id that names no book returns no rows.\n\n`Cache-Control: no-store`.\n","parameters":[{"$ref":"#/components/parameters/AccountPath"},{"$ref":"#/components/parameters/OrderbookQuery"},{"name":"from_us","in":"query","description":"Window start, microseconds, inclusive.","schema":{"$ref":"#/components/schemas/TimestampString"}},{"name":"to_us","in":"query","description":"Window end, microseconds, exclusive. Defaults to the node's current time.","schema":{"$ref":"#/components/schemas/TimestampString"}},{"name":"limit","in":"query","description":"Maximum rows, clamped to `[1, 500]`.","schema":{"type":"integer","minimum":1,"maximum":500,"default":500}}],"responses":{"200":{"description":"Fills","content":{"application/json":{"schema":{"type":"object","required":["fills"],"properties":{"fills":{"type":"array","items":{"$ref":"#/components/schemas/Fill"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"503":{"$ref":"#/components/responses/Unavailable"}}}}},"components":{"parameters":{"AccountPath":{"name":"account","in":"path","required":true,"schema":{"$ref":"#/components/schemas/Address"}},"OrderbookQuery":{"name":"orderbook","in":"query","description":"Restrict to one orderbook (32-byte id).","schema":{"$ref":"#/components/schemas/Bytes32"}}},"schemas":{"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"TimestampString":{"type":"string","pattern":"^[0-9]+$","description":"Unix time in microseconds, as a decimal string"},"Fill":{"type":"object","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_token":{"$ref":"#/components/schemas/Address"},"quote_token":{"$ref":"#/components/schemas/Address"},"order_id":{"$ref":"#/components/schemas/Bytes32"},"order_type":{"type":"string","enum":["limit","market"]},"initial_size":{"$ref":"#/components/schemas/DecimalInt256"},"fee":{"$ref":"#/components/schemas/HexUint256"},"base_amount":{"$ref":"#/components/schemas/HexUint256"},"quote_amount":{"$ref":"#/components/schemas/HexUint256"},"timestamp":{"$ref":"#/components/schemas/Timestamp"},"price":{"$ref":"#/components/schemas/HexUint256"}}},"DecimalInt256":{"type":"string","pattern":"^-?[0-9]+$","description":"Signed 256-bit integer, decimal string"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"},"Timestamp":{"type":"integer","format":"int64","description":"Unix time in microseconds, as a JSON number"}},"responses":{"BadRequest":{"description":"Malformed path or query parameter. Plain-text reason.","content":{"text/plain":{"schema":{"type":"string"}}}},"Unavailable":{"description":"The indexer or execution engine read failed. Body `clob indexer unavailable`, with `Cache-Control: no-store`.","content":{"text/plain":{"schema":{"type":"string"}}}}}}}
```

## Get Perp Positions

> The account's live perp positions and account-level aggregates, read from the\
> execution engine. Spot holdings are on \`/clob/balances/{account}\`. An account the\
> node has never seen returns an empty list and zero aggregates.\
> \
> \`Cache-Control: no-store\`.<br>

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"tags":[{"name":"Account","description":"One account's orders, fills, positions, balances, triggers, backstop transfers and\nunified activity feed. `{account}` is a 20-byte `0x` address.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/v1","description":"Pod testnet"}],"paths":{"/clob/positions/{account}":{"get":{"tags":["Account"],"summary":"Get Perp Positions","operationId":"getPositions","description":"The account's live perp positions and account-level aggregates, read from the\nexecution engine. Spot holdings are on `/clob/balances/{account}`. An account the\nnode has never seen returns an empty list and zero aggregates.\n\n`Cache-Control: no-store`.\n","parameters":[{"$ref":"#/components/parameters/AccountPath"}],"responses":{"200":{"description":"Positions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PositionsResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"503":{"$ref":"#/components/responses/Unavailable"}}}}},"components":{"parameters":{"AccountPath":{"name":"account","in":"path","required":true,"schema":{"$ref":"#/components/schemas/Address"}}},"schemas":{"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"PositionsResponse":{"type":"object","properties":{"positions":{"type":"array","items":{"$ref":"#/components/schemas/PerpPosition"}},"total_unrealized_pnl":{"$ref":"#/components/schemas/DecimalInt256"},"total_realized_pnl":{"$ref":"#/components/schemas/DecimalInt256","description":"Lifetime, spot and perp."},"perps_equity":{"$ref":"#/components/schemas/DecimalInt256","description":"Cash adjusted for unsettled funding, plus perp unrealized PnL."},"account_value":{"$ref":"#/components/schemas/DecimalInt256","description":"`perps_equity` plus the mark value of spot holdings and quote escrowed in resting spot buys."},"cash":{"$ref":"#/components/schemas/DecimalInt256"},"withdrawable_cash":{"$ref":"#/components/schemas/HexUint256","description":"What a withdrawal or transfer can take now: `max(0, equity − max(initial_margin, transfer_margin_ratio × notional))`, where `notional` is `Σ |size| × mark` and `transfer_margin_ratio` is a network parameter (10% by default). Equity counts unrealized PnL."},"net_deposits":{"$ref":"#/components/schemas/DecimalInt256","description":"Native collateral deposited minus withdrawn. Lifetime PnL is `account_value − net_deposits`."}}},"PerpPosition":{"type":"object","description":"One open perp position. 1e18-scaled; unsigned `0x` hex, signed decimal strings.","properties":{"kind":{"type":"string","enum":["perp"]},"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"side":{"type":"string","enum":["long","short"]},"size":{"$ref":"#/components/schemas/DecimalInt256","description":"Positive long, negative short."},"notional":{"$ref":"#/components/schemas/HexUint256"},"entry_price":{"$ref":"#/components/schemas/HexUint256","description":"Rounded against the holder; `unrealized_pnl` is exact."},"mark_price":{"$ref":"#/components/schemas/HexUint256"},"margin":{"$ref":"#/components/schemas/HexUint256"},"leverage":{"$ref":"#/components/schemas/HexUint256"},"funding_accrued":{"$ref":"#/components/schemas/DecimalInt256","description":"Funding owed on the position, quote wei. Positive is owed by the holder."},"funding_basis":{"$ref":"#/components/schemas/DecimalInt256"},"cost_basis":{"$ref":"#/components/schemas/DecimalInt256"},"entry_funding":{"$ref":"#/components/schemas/DecimalInt256"},"liquidation_price":{"$ref":"#/components/schemas/HexUint256"},"unrealized_pnl":{"$ref":"#/components/schemas/DecimalInt256"},"realized_pnl":{"$ref":"#/components/schemas/DecimalInt256","description":"Always `\"0\"`; realized PnL is banked into cash and `total_realized_pnl`."},"stop_loss":{"type":"string","nullable":true,"description":"Always `null`."},"take_profit":{"type":"string","nullable":true,"description":"Always `null`."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"DecimalInt256":{"type":"string","pattern":"^-?[0-9]+$","description":"Signed 256-bit integer, decimal string"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"}},"responses":{"BadRequest":{"description":"Malformed path or query parameter. Plain-text reason.","content":{"text/plain":{"schema":{"type":"string"}}}},"Unavailable":{"description":"The indexer or execution engine read failed. Body `clob indexer unavailable`, with `Cache-Control: no-store`.","content":{"text/plain":{"schema":{"type":"string"}}}}}}}
```

## Get Balances

> The account's live spot holdings and cash, read from the execution engine.\
> \
> \`Cache-Control: no-store\`.<br>

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"tags":[{"name":"Account","description":"One account's orders, fills, positions, balances, triggers, backstop transfers and\nunified activity feed. `{account}` is a 20-byte `0x` address.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/v1","description":"Pod testnet"}],"paths":{"/clob/balances/{account}":{"get":{"tags":["Account"],"summary":"Get Balances","operationId":"getBalances","description":"The account's live spot holdings and cash, read from the execution engine.\n\n`Cache-Control: no-store`.\n","parameters":[{"$ref":"#/components/parameters/AccountPath"}],"responses":{"200":{"description":"Balances","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BalancesResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"503":{"$ref":"#/components/responses/Unavailable"}}}}},"components":{"parameters":{"AccountPath":{"name":"account","in":"path","required":true,"schema":{"$ref":"#/components/schemas/Address"}}},"schemas":{"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"BalancesResponse":{"type":"object","properties":{"balances":{"type":"array","items":{"$ref":"#/components/schemas/SpotHolding"}},"cash":{"$ref":"#/components/schemas/DecimalInt256"},"withdrawable_cash":{"$ref":"#/components/schemas/HexUint256"},"net_deposits":{"$ref":"#/components/schemas/DecimalInt256"}}},"SpotHolding":{"type":"object","description":"One spot token holding. 1e18-scaled; unsigned `0x` hex, signed decimal strings.","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"balance":{"$ref":"#/components/schemas/HexUint256","description":"`free_balance + locked_balance`."},"free_balance":{"$ref":"#/components/schemas/HexUint256"},"locked_balance":{"$ref":"#/components/schemas/HexUint256","description":"Locked in open sell orders."},"cost_basis":{"$ref":"#/components/schemas/HexUint256"},"mark_price":{"$ref":"#/components/schemas/HexUint256"},"unrealized_pnl":{"$ref":"#/components/schemas/DecimalInt256"},"realized_pnl":{"$ref":"#/components/schemas/DecimalInt256","description":"Portfolio-wide lifetime spot realized PnL."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"},"DecimalInt256":{"type":"string","pattern":"^-?[0-9]+$","description":"Signed 256-bit integer, decimal string"}},"responses":{"BadRequest":{"description":"Malformed path or query parameter. Plain-text reason.","content":{"text/plain":{"schema":{"type":"string"}}}},"Unavailable":{"description":"The indexer or execution engine read failed. Body `clob indexer unavailable`, with `Cache-Control: no-store`.","content":{"text/plain":{"schema":{"type":"string"}}}}}}}
```

## Get Triggers

> The account's armed TP/SL triggers, read from the execution engine, sorted by\
> \`(orderbook\_id, order\_id)\`. Pass \`next\_cursor\` back as \`cursor\` for the next page.\
> \
> \`Cache-Control: no-store\`.<br>

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"tags":[{"name":"Account","description":"One account's orders, fills, positions, balances, triggers, backstop transfers and\nunified activity feed. `{account}` is a 20-byte `0x` address.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/v1","description":"Pod testnet"}],"paths":{"/clob/triggers/{account}":{"get":{"tags":["Account"],"summary":"Get Triggers","operationId":"getTriggers","description":"The account's armed TP/SL triggers, read from the execution engine, sorted by\n`(orderbook_id, order_id)`. Pass `next_cursor` back as `cursor` for the next page.\n\n`Cache-Control: no-store`.\n","parameters":[{"$ref":"#/components/parameters/AccountPath"},{"$ref":"#/components/parameters/OrderbookQuery"},{"name":"limit","in":"query","description":"Page size, clamped to `[1, 200]`.","schema":{"type":"integer","minimum":1,"maximum":200,"default":200}},{"name":"cursor","in":"query","description":"`next_cursor` from the previous page, `\"{orderbook_id}:{order_id}\"` (both `0x` hex). Malformed is a `400`.","schema":{"type":"string"}}],"responses":{"200":{"description":"Trigger page","content":{"application/json":{"schema":{"type":"object","required":["triggers","total_count","next_cursor"],"properties":{"triggers":{"type":"array","items":{"$ref":"#/components/schemas/Trigger"}},"total_count":{"type":"integer","description":"Triggers matching the filter, before paging."},"next_cursor":{"type":"string","nullable":true,"description":"Cursor for the next page. `null` on the last page."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"503":{"$ref":"#/components/responses/Unavailable"}}}}},"components":{"parameters":{"AccountPath":{"name":"account","in":"path","required":true,"schema":{"$ref":"#/components/schemas/Address"}},"OrderbookQuery":{"name":"orderbook","in":"query","description":"Restrict to one orderbook (32-byte id).","schema":{"$ref":"#/components/schemas/Bytes32"}}},"schemas":{"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"Trigger":{"type":"object","description":"An armed TP/SL trigger.","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"order_id":{"$ref":"#/components/schemas/Bytes32"},"tx_hash":{"$ref":"#/components/schemas/Bytes32"},"bidder":{"$ref":"#/components/schemas/Address"},"nonce":{"type":"integer","format":"int64"},"size":{"$ref":"#/components/schemas/DecimalInt256","description":"Signed. `\"0\"` (only with `grouping` `asset`) sizes from the owner's exposure when the trigger fires."},"limit_price":{"$ref":"#/components/schemas/HexUint256"},"trigger_price":{"$ref":"#/components/schemas/HexUint256"},"trigger_type":{"$ref":"#/components/schemas/TriggerType"},"grouping":{"$ref":"#/components/schemas/TriggerGrouping"},"reduce_only":{"type":"boolean"},"ioc":{"type":"boolean"},"deadline":{"$ref":"#/components/schemas/TimestampString"},"end":{"type":"integer","description":"TTL expiry, microseconds, as a JSON number."}}},"DecimalInt256":{"type":"string","pattern":"^-?[0-9]+$","description":"Signed 256-bit integer, decimal string"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"},"TriggerType":{"type":"string","enum":["take_profit","stop_loss"]},"TriggerGrouping":{"type":"string","enum":["none","asset"],"description":"- `none`: standalone; removed only by cancel, TTL expiry or its own fire\n- `asset`: removed, with any resting order it produced, once the owner's position on the pair (perp) or base holding (spot) reaches zero\n"},"TimestampString":{"type":"string","pattern":"^[0-9]+$","description":"Unix time in microseconds, as a decimal string"}},"responses":{"BadRequest":{"description":"Malformed path or query parameter. Plain-text reason.","content":{"text/plain":{"schema":{"type":"string"}}}},"Unavailable":{"description":"The indexer or execution engine read failed. Body `clob indexer unavailable`, with `Cache-Control: no-store`.","content":{"text/plain":{"schema":{"type":"string"}}}}}}}
```

## Get Backstop Transfers

> The account's backstop sweeps as raw events, newest first, with the cash and\
> equity detail the orders feed omits.\
> \
> With no query parameters the route returns the whole list, capped at 500, and no\
> \`next\_cursor\`. Setting any of \`orderbook\`, \`limit\` or \`cursor\` switches to paged\
> reads of at most 200 rows; pass \`next\_cursor\` back as \`cursor\`.\
> \
> An orderbook id that names no book returns no rows.\
> \
> \`Cache-Control: no-store\`.<br>

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"tags":[{"name":"Account","description":"One account's orders, fills, positions, balances, triggers, backstop transfers and\nunified activity feed. `{account}` is a 20-byte `0x` address.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/v1","description":"Pod testnet"}],"paths":{"/clob/backstop-transfers/{account}":{"get":{"tags":["Account"],"summary":"Get Backstop Transfers","operationId":"getBackstopTransfers","description":"The account's backstop sweeps as raw events, newest first, with the cash and\nequity detail the orders feed omits.\n\nWith no query parameters the route returns the whole list, capped at 500, and no\n`next_cursor`. Setting any of `orderbook`, `limit` or `cursor` switches to paged\nreads of at most 200 rows; pass `next_cursor` back as `cursor`.\n\nAn orderbook id that names no book returns no rows.\n\n`Cache-Control: no-store`.\n","parameters":[{"$ref":"#/components/parameters/AccountPath"},{"$ref":"#/components/parameters/OrderbookQuery"},{"name":"limit","in":"query","description":"Page size, clamped to `[1, 200]`.","schema":{"type":"integer","minimum":1,"maximum":200,"default":200}},{"name":"cursor","in":"query","description":"`next_cursor` from the previous page, `\"{ts}:{id}\"`. Malformed is a `400`.","schema":{"type":"string"}}],"responses":{"200":{"description":"Backstop transfers","content":{"application/json":{"schema":{"type":"object","required":["backstop_transfers","total_count","solution_now"],"properties":{"backstop_transfers":{"type":"array","items":{"$ref":"#/components/schemas/BackstopTransfer"}},"total_count":{"type":"integer"},"next_cursor":{"type":"string","description":"Cursor for the next page. Omitted on the last page and when unpaged."},"solution_now":{"$ref":"#/components/schemas/Timestamp"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"503":{"$ref":"#/components/responses/Unavailable"}}}}},"components":{"parameters":{"AccountPath":{"name":"account","in":"path","required":true,"schema":{"$ref":"#/components/schemas/Address"}},"OrderbookQuery":{"name":"orderbook","in":"query","description":"Restrict to one orderbook (32-byte id).","schema":{"$ref":"#/components/schemas/Bytes32"}}},"schemas":{"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"BackstopTransfer":{"type":"object","description":"One backstop sweep. Amounts are 1e18-scaled decimal strings.","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32","description":"The swept position's market. Omitted on the cash-sweep row."},"size":{"type":"string","description":"Signed position size moved."},"cash":{"type":"string","description":"Signed."},"mark_price":{"type":"string"},"equity":{"type":"string","description":"Signed account equity when the sweep triggered."},"realized_pnl":{"type":"string","description":"Signed. `\"0\"` on the cash-sweep row and older rows."},"timestamp_us":{"$ref":"#/components/schemas/Timestamp"}}},"Timestamp":{"type":"integer","format":"int64","description":"Unix time in microseconds, as a JSON number"}},"responses":{"BadRequest":{"description":"Malformed path or query parameter. Plain-text reason.","content":{"text/plain":{"schema":{"type":"string"}}}},"Unavailable":{"description":"The indexer or execution engine read failed. Body `clob indexer unavailable`, with `Cache-Control: no-store`.","content":{"text/plain":{"schema":{"type":"string"}}}}}}}
```

## Get Account Activity

> Everything that happened to the account, as an \`ActivityFrame\`: a map from batch\
> deadline to that batch's entries. Entries are tagged by \`k\` (\`ActivityEntry\`). Within a batch, entries are ordered by kind\
> (\`order\`, \`fill\`, \`modify\`, \`termination\`, \`backstop\`, \`bridge\_transfer\`,\
> \`transfer\`, \`modify\_reject\`, \`cancel\_reject\`), then by book ascending, then in engine order.\
> \
> Pages are newest first and hold whole batches. Batches are added while the entry\
> count stays within \`limit\`; the newest batch in the window is always served, even\
> when it alone exceeds \`limit\`. Pass \`next\` back as \`to\` for the older page.\
> \
> An \`order\` entry, at the batch that admitted it, is the order as\
> \`/clob/orders/{account}\` serves it: its current status, totals and fills, so it needs no\
> folding of the later entries. A \`fill\`, \`modify\`, \`termination\`, \`modify\_reject\` or \`cancel\_reject\` names\
> its order by \`id\` and \`book\`; one of an order placed before the window is not\
> hydrated.\
> \
> Seed from this route, then subscribe to the \`pod\_activity\` websocket channel with\
> \`since\` = \`solution\_now\`.\
> \
> \`Cache-Control: public, max-age=31536000, immutable\` when \`to <= solution\_now\` and\
> every \`order\` on the page is terminal, otherwise \`no-store\`.<br>

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"tags":[{"name":"Account","description":"One account's orders, fills, positions, balances, triggers, backstop transfers and\nunified activity feed. `{account}` is a 20-byte `0x` address.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/v1","description":"Pod testnet"}],"paths":{"/clob/activity/{account}":{"get":{"tags":["Account"],"summary":"Get Account Activity","operationId":"getActivity","description":"Everything that happened to the account, as an `ActivityFrame`: a map from batch\ndeadline to that batch's entries. Entries are tagged by `k` (`ActivityEntry`). Within a batch, entries are ordered by kind\n(`order`, `fill`, `modify`, `termination`, `backstop`, `bridge_transfer`,\n`transfer`, `modify_reject`, `cancel_reject`), then by book ascending, then in engine order.\n\nPages are newest first and hold whole batches. Batches are added while the entry\ncount stays within `limit`; the newest batch in the window is always served, even\nwhen it alone exceeds `limit`. Pass `next` back as `to` for the older page.\n\nAn `order` entry, at the batch that admitted it, is the order as\n`/clob/orders/{account}` serves it: its current status, totals and fills, so it needs no\nfolding of the later entries. A `fill`, `modify`, `termination`, `modify_reject` or `cancel_reject` names\nits order by `id` and `book`; one of an order placed before the window is not\nhydrated.\n\nSeed from this route, then subscribe to the `pod_activity` websocket channel with\n`since` = `solution_now`.\n\n`Cache-Control: public, max-age=31536000, immutable` when `to <= solution_now` and\nevery `order` on the page is terminal, otherwise `no-store`.\n","parameters":[{"$ref":"#/components/parameters/AccountPath"},{"name":"from","in":"query","description":"Lowest batch deadline, microseconds, inclusive. Defaults to `0`.","schema":{"$ref":"#/components/schemas/TimestampString"}},{"name":"to","in":"query","description":"Highest batch deadline, microseconds, inclusive. Defaults to the whole history. `from > to` is a `422` (`from must not exceed to`).","schema":{"$ref":"#/components/schemas/TimestampString"}},{"name":"limit","in":"query","description":"Entries per page after the type filter, clamped to `[1, 2000]`. A page can exceed it by its newest batch.","schema":{"type":"integer","minimum":1,"maximum":2000,"default":500}},{"name":"activity_types","in":"query","description":"Comma-separated kinds to include: `order`, `fill`, `modify`, `termination`,\n`backstop`, `bridge_transfer`, `transfer`, `modify_reject`, `cancel_reject`. Defaults to all. An unknown or empty\nname is a `400` (`invalid activity_types`).\n","schema":{"type":"string"}}],"responses":{"200":{"description":"Activity page","content":{"application/json":{"schema":{"type":"object","required":["activity","next","solution_now"],"properties":{"activity":{"$ref":"#/components/schemas/ActivityFrame"},"next":{"type":"string","pattern":"^[0-9]+$","nullable":true,"description":"The oldest served batch minus 1µs when older history may exist, otherwise `null`. Pass it as `to`."},"solution_now":{"$ref":"#/components/schemas/Timestamp"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"422":{"description":"`from > to`. Plain-text reason.","content":{"text/plain":{"schema":{"type":"string"}}}},"503":{"$ref":"#/components/responses/Unavailable"}}}}},"components":{"parameters":{"AccountPath":{"name":"account","in":"path","required":true,"schema":{"$ref":"#/components/schemas/Address"}}},"schemas":{"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"TimestampString":{"type":"string","pattern":"^[0-9]+$","description":"Unix time in microseconds, as a decimal string"},"ActivityFrame":{"type":"object","description":"One account's activity: batch deadline (microseconds, as a decimal-string key) to that\nbatch's entries, in the order given on the route. The `pod_activity` websocket channel\nsends the same shape with one key per tick.\n","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/ActivityEntry"}}},"ActivityEntry":{"description":"One activity entry, discriminated by `k`. Amounts and prices are 1e18-scaled decimal\nstrings. Optional fields are omitted rather than `null`; boolean flags are omitted when\nfalse. Ignore kinds and fields you do not recognise.\n","oneOf":[{"$ref":"#/components/schemas/ActivityOrder"},{"$ref":"#/components/schemas/ActivityFill"},{"$ref":"#/components/schemas/ActivityModify"},{"$ref":"#/components/schemas/ActivityTermination"},{"$ref":"#/components/schemas/ActivityBackstop"},{"$ref":"#/components/schemas/ActivityBridgeTransfer"},{"$ref":"#/components/schemas/ActivityTransfer"},{"$ref":"#/components/schemas/ActivityModifyReject"},{"$ref":"#/components/schemas/ActivityCancelReject"}],"discriminator":{"propertyName":"k","mapping":{"order":"#/components/schemas/ActivityOrder","fill":"#/components/schemas/ActivityFill","modify":"#/components/schemas/ActivityModify","termination":"#/components/schemas/ActivityTermination","backstop":"#/components/schemas/ActivityBackstop","bridge_transfer":"#/components/schemas/ActivityBridgeTransfer","transfer":"#/components/schemas/ActivityTransfer","modify_reject":"#/components/schemas/ActivityModifyReject","cancel_reject":"#/components/schemas/ActivityCancelReject"}}},"ActivityOrder":{"description":"The order as `/clob/orders/{account}` serves it, at the batch that admitted it, in its\ncurrent state. On the `pod_activity` channel it is the admission state instead:\n`active`, or `invalid` with `invalid_reason`, zero totals and `fills: []`. ADL closes\nappear as orders with `kind` `adl` or `adl_counterparty`; backstop sweeps appear only\nas `backstop` entries.\n","allOf":[{"type":"object","required":["k"],"properties":{"k":{"type":"string","enum":["order"]}}},{"$ref":"#/components/schemas/Order"}]},"Order":{"type":"object","description":"An order with its fills. Unsigned amounts and prices are 1e18-scaled `0x` hex,\nsigned ones decimal strings. Perp-only fields are omitted on spot orders.\n","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"market_type":{"$ref":"#/components/schemas/MarketType"},"kind":{"$ref":"#/components/schemas/OrderKind"},"order_id":{"$ref":"#/components/schemas/Bytes32"},"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"Creating transaction. Zero for engine-generated orders."},"bidder":{"$ref":"#/components/schemas/Address"},"nonce":{"type":"integer","format":"int64"},"order_type":{"type":"string","enum":["limit","market"]},"status":{"$ref":"#/components/schemas/OrderStatus"},"side":{"type":"string","enum":["buy","sell"]},"price":{"$ref":"#/components/schemas/HexUint256"},"initial_size":{"$ref":"#/components/schemas/DecimalInt256","description":"Signed; positive buy/long, negative sell/short."},"filled_base_amount":{"$ref":"#/components/schemas/HexUint256"},"filled_quote_amount":{"$ref":"#/components/schemas/HexUint256"},"fee":{"$ref":"#/components/schemas/HexUint256"},"deadline":{"$ref":"#/components/schemas/TimestampString","description":"The batch the order targets, microseconds, as a string."},"end":{"$ref":"#/components/schemas/Timestamp","description":"TTL expiry, microseconds. Orders that never expire carry `18446744073709551615`, which exceeds a JavaScript safe integer."},"included_batch":{"$ref":"#/components/schemas/Timestamp","description":"Deadline of the batch that first included the order. `0` for engine-generated orders and older rows."},"invalid_reason":{"type":"string","description":"Why the engine rejected the order. Only when `status` is `invalid`."},"effective_price":{"$ref":"#/components/schemas/HexUint256","description":"`filled_quote / filled_base` so far."},"fills":{"type":"array","items":{"$ref":"#/components/schemas/PartialFill"},"description":"Always present, oldest first."},"reduce_only":{"type":"boolean","description":"Perp only."},"ioc":{"type":"boolean","description":"Perp only."},"post_only":{"type":"boolean","description":"Omitted when false."},"direction":{"$ref":"#/components/schemas/OrderDirection"},"realized_pnl":{"$ref":"#/components/schemas/DecimalInt256","description":"Perp only, present once a fill closed exposure. Price drift minus funding across the slices it closed."},"grouping":{"$ref":"#/components/schemas/TriggerGrouping","description":"Inherited from the parent trigger. Omitted when `none`."},"trigger_type":{"$ref":"#/components/schemas/TriggerType","description":"Set only on orders a fired trigger produced (`kind` `triggered`)."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"MarketType":{"type":"string","enum":["spot","perpetual"]},"OrderKind":{"type":"string","enum":["user_signed","liquidation","triggered","adl","adl_counterparty","backstop_transfer"],"description":"- `user_signed`: submitted by the account\n- `liquidation`: generated by the engine when the account fell below maintenance margin\n- `triggered`: the order a fired TP/SL trigger produced\n- `adl`: auto-deleveraging close of this account's position\n- `adl_counterparty`: this account's side covering an auto-deleveraging close\n- `backstop_transfer`: a backstop sweep of this account's position, shown as a terminal order\n"},"OrderStatus":{"type":"string","enum":["pending","active","filled","expired","canceled","margin_canceled","self_trade_canceled","post_only_refused","invalid"],"description":"- `pending`: submitted, not yet in the book\n- `active`: resting in the book\n- `filled`: completely filled\n- `expired`: TTL passed\n- `canceled`: canceled by the owner\n- `margin_canceled`: removed by the engine because the owner's margin was exhausted\n- `self_trade_canceled`: removed by the engine because it was about to fill against an order of the same owner\n- `post_only_refused`: a `post_only` order removed because it would have taken liquidity in the batch that admitted it\n- `invalid`: rejected at execution and never entered the book; see `invalid_reason`\n\nEverything except `pending` and `active` is terminal.\n"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"},"DecimalInt256":{"type":"string","pattern":"^-?[0-9]+$","description":"Signed 256-bit integer, decimal string"},"Timestamp":{"type":"integer","format":"int64","description":"Unix time in microseconds, as a JSON number"},"PartialFill":{"type":"object","properties":{"base_amount":{"$ref":"#/components/schemas/HexUint256"},"quote_amount":{"$ref":"#/components/schemas/HexUint256"},"timestamp":{"$ref":"#/components/schemas/Timestamp"},"price":{"$ref":"#/components/schemas/HexUint256","description":"The batch's clearing price; the order's own price for ADL fills."}}},"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":"Spot orders use `buy`/`sell`. Perp orders use the position effect of their fills; `liquidation` when `kind` is `liquidation`."},"TriggerGrouping":{"type":"string","enum":["none","asset"],"description":"- `none`: standalone; removed only by cancel, TTL expiry or its own fire\n- `asset`: removed, with any resting order it produced, once the owner's position on the pair (perp) or base holding (spot) reaches zero\n"},"TriggerType":{"type":"string","enum":["take_profit","stop_loss"]},"ActivityFill":{"type":"object","description":"One fill of an order. `tb`, `tq`, `tf`, `f` and `st` are omitted on rows indexed before they\nwere recorded.\n","required":["k","id","book","b","q"],"properties":{"k":{"type":"string","enum":["fill"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"Order id."},"book":{"$ref":"#/components/schemas/Bytes32"},"b":{"$ref":"#/components/schemas/DecimalUint256","description":"Base filled by this fill."},"q":{"$ref":"#/components/schemas/DecimalUint256","description":"Quote filled by this fill."},"tb":{"$ref":"#/components/schemas/DecimalUint256","description":"Order's total base filled after this fill."},"tq":{"$ref":"#/components/schemas/DecimalUint256","description":"Order's total quote filled after this fill."},"tf":{"$ref":"#/components/schemas/DecimalUint256","description":"Order's total fee after this fill."},"f":{"$ref":"#/components/schemas/DecimalUint256","description":"Fee charged by this fill."},"st":{"type":"string","enum":["filled","canceled","margin_canceled","self_trade_canceled","expired","post_only_refused"],"description":"Terminal status, present only on the fill that closed the order."},"pa":{"$ref":"#/components/schemas/DecimalInt256","description":"The position after this fill on a perp book. Omitted when no position moved."}}},"DecimalUint256":{"type":"string","pattern":"^[0-9]+$","description":"Unsigned 256-bit integer, decimal string"},"ActivityModify":{"type":"object","description":"A resting order's price and/or size changed in place. Sizes are unsigned.","required":["k","id","book","px","sz","old_px","old_sz"],"properties":{"k":{"type":"string","enum":["modify"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"Order id."},"book":{"$ref":"#/components/schemas/Bytes32"},"px":{"$ref":"#/components/schemas/DecimalUint256"},"sz":{"$ref":"#/components/schemas/DecimalUint256"},"old_px":{"$ref":"#/components/schemas/DecimalUint256"},"old_sz":{"$ref":"#/components/schemas/DecimalUint256"}}},"ActivityTermination":{"type":"object","description":"An order left the book other than by filling.","required":["k","id","book","st"],"properties":{"k":{"type":"string","enum":["termination"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"Order id."},"book":{"$ref":"#/components/schemas/Bytes32"},"st":{"type":"string","enum":["canceled","margin_canceled","self_trade_canceled","expired","post_only_refused"]}}},"ActivityBackstop":{"type":"object","description":"A perp position swept to the backstop (`book` set), or the terminal cash sweep (`book` omitted).","required":["k","sz","cash","mark","eq","pnl"],"properties":{"k":{"type":"string","enum":["backstop"]},"book":{"$ref":"#/components/schemas/Bytes32"},"sz":{"$ref":"#/components/schemas/DecimalInt256","description":"Position size moved."},"cash":{"$ref":"#/components/schemas/DecimalInt256"},"mark":{"$ref":"#/components/schemas/DecimalUint256","description":"Mark price at the sweep."},"eq":{"$ref":"#/components/schemas/DecimalInt256","description":"Account equity at the sweep."},"pnl":{"$ref":"#/components/schemas/DecimalInt256","description":"Realized PnL; `\"0\"` on the cash sweep."}}},"ActivityBridgeTransfer":{"type":"object","description":"A bridge deposit (positive `amt`) or withdrawal (negative). `err` set means it was\nrefused and nothing moved.\n","required":["k","tx","idx","tok","amt"],"properties":{"k":{"type":"string","enum":["bridge_transfer"]},"tx":{"$ref":"#/components/schemas/Bytes32","description":"The bridge transaction."},"idx":{"type":"integer","description":"Position among the tick's deposits; `0` for a withdrawal."},"tok":{"$ref":"#/components/schemas/Address"},"amt":{"$ref":"#/components/schemas/DecimalInt256"},"err":{"type":"string"}}},"ActivityTransfer":{"type":"object","description":"An account-to-account transfer, signed from the account's side: debit negative, credit\npositive. A self-transfer is two entries, the debit first. A refused transfer is reported\nto the sender only, with `err`.\n","required":["k","id","cp","tok","amt"],"properties":{"k":{"type":"string","enum":["transfer"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"Transfer id."},"cp":{"$ref":"#/components/schemas/Address","description":"The other side of the transfer, the receiver when `amt` is negative and the sender otherwise; the account itself on a self-transfer."},"tok":{"$ref":"#/components/schemas/Address"},"amt":{"$ref":"#/components/schemas/DecimalInt256"},"err":{"type":"string"}}},"ActivityModifyReject":{"type":"object","description":"An amendment the engine refused; the order is untouched. `px` and `sz` are what was asked for, `sz` unsigned.","required":["k","id","book","px","sz","why"],"properties":{"k":{"type":"string","enum":["modify_reject"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"Order id."},"book":{"$ref":"#/components/schemas/Bytes32"},"px":{"$ref":"#/components/schemas/DecimalUint256"},"sz":{"$ref":"#/components/schemas/DecimalUint256"},"why":{"type":"string","description":"The engine's reason."}}},"ActivityCancelReject":{"type":"object","description":"A cancel the engine refused; the order still rests.","required":["k","id","book","why"],"properties":{"k":{"type":"string","enum":["cancel_reject"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"Order id."},"book":{"$ref":"#/components/schemas/Bytes32"},"why":{"type":"string","description":"The engine's reason."}}}},"responses":{"BadRequest":{"description":"Malformed path or query parameter. Plain-text reason.","content":{"text/plain":{"schema":{"type":"string"}}}},"Unavailable":{"description":"The indexer or execution engine read failed. Body `clob indexer unavailable`, with `Cache-Control: no-store`.","content":{"text/plain":{"schema":{"type":"string"}}}}}}}
```


# Explorer

Transactions with their receipt, validator attestations and decoded calldata.

&#x20;   &#x20;

## Get Transaction

> One transaction as a single flat object: transaction fields, receipt fields,\
> validator attestations and decoded calldata. Recent transactions are served from\
> memory; older ones from the node's ledger database.\
> \
> \`Cache-Control: no-store\`.<br>

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"tags":[{"name":"Explorer","description":"Transactions with their receipt, validator attestations and decoded calldata.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/v1","description":"Pod testnet"}],"paths":{"/tx/{hash}":{"get":{"tags":["Explorer"],"summary":"Get Transaction","operationId":"getTransaction","description":"One transaction as a single flat object: transaction fields, receipt fields,\nvalidator attestations and decoded calldata. Recent transactions are served from\nmemory; older ones from the node's ledger database.\n\n`Cache-Control: no-store`.\n","parameters":[{"name":"hash","in":"path","required":true,"schema":{"$ref":"#/components/schemas/Bytes32"}}],"responses":{"200":{"description":"Transaction","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExplorerTransaction"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"description":"Unknown transaction. Body `transaction not found`.","content":{"text/plain":{"schema":{"type":"string"}}}},"503":{"$ref":"#/components/responses/Unavailable"}}}}},"components":{"schemas":{"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"ExplorerTransaction":{"type":"object","description":"Receipt fields merged with Ethereum JSON transaction fields (receipt wins on\noverlap; the receipt's `transactionHash` is dropped for the transaction's `hash`),\nplus `attestations`, `committee_epoch` and `decoded`. Block fields are absent or\n`null` while the transaction is served from the recent cache.\n","additionalProperties":true,"properties":{"hash":{"$ref":"#/components/schemas/Bytes32"},"from":{"$ref":"#/components/schemas/Address"},"to":{"$ref":"#/components/schemas/Address"},"nonce":{"type":"string","description":"`0x` hex"},"input":{"type":"string","description":"`0x` hex calldata"},"status":{"type":"string","description":"`0x1` success, `0x0` failure"},"blockNumber":{"type":"string","nullable":true},"blockHash":{"type":"string","nullable":true},"transactionIndex":{"type":"string","nullable":true},"logs":{"type":"array","items":{"type":"object"}},"attestations":{"type":"array","items":{"type":"object","properties":{"validator_address":{"$ref":"#/components/schemas/Address"},"sequence_number":{"type":"integer","format":"int64"},"batch_index":{"type":"integer"},"timestamp":{"$ref":"#/components/schemas/Timestamp"},"signature":{"type":"string"}}}},"committee_epoch":{"type":"integer","format":"int64"},"decoded":{"$ref":"#/components/schemas/DecodedCalldata"}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"Timestamp":{"type":"integer","format":"int64","description":"Unix time in microseconds, as a JSON number"},"DecodedCalldata":{"type":"object","description":"Calldata decoded against Pod's precompiles. For an unrecognized target or\nselector, `contract` is `null` and only `selector` and `raw` are set.\n","properties":{"contract":{"type":"string","nullable":true},"address":{"$ref":"#/components/schemas/Address"},"symbol":{"type":"string"},"function":{"type":"string"},"args":{"type":"object","additionalProperties":true},"order_id":{"$ref":"#/components/schemas/Bytes32","description":"Resting order id the call creates (`submitOrder`, `submitTrigger`)."},"sequence":{"type":"integer","description":"Position inside the parent `submitBatch`."},"intents":{"type":"array","description":"Decoded sub-intents of a `submitBatch`.","items":{"type":"object"}},"selector":{"type":"string","description":"4-byte selector, `0x` hex."},"raw":{"type":"string","description":"Raw calldata, `0x` hex."}}}},"responses":{"BadRequest":{"description":"Malformed path or query parameter. Plain-text reason.","content":{"text/plain":{"schema":{"type":"string"}}}},"Unavailable":{"description":"The indexer or execution engine read failed. Body `clob indexer unavailable`, with `Cache-Control: no-store`.","content":{"text/plain":{"schema":{"type":"string"}}}}}}}
```

## List Recent Transactions

> Newest-first page of the node's in-memory ring of recent transactions (1000 by\
> default, \`POD\_RECENT\_TX\_CACHE\_CAP\`). Older transactions are served by \`/tx/{hash}\`.\
> Each entry has the \`/tx/{hash}\` shape.\
> \
> \`Cache-Control: no-store\`.<br>

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"tags":[{"name":"Explorer","description":"Transactions with their receipt, validator attestations and decoded calldata.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/v1","description":"Pod testnet"}],"paths":{"/transactions":{"get":{"tags":["Explorer"],"summary":"List Recent Transactions","operationId":"listTransactions","description":"Newest-first page of the node's in-memory ring of recent transactions (1000 by\ndefault, `POD_RECENT_TX_CACHE_CAP`). Older transactions are served by `/tx/{hash}`.\nEach entry has the `/tx/{hash}` shape.\n\n`Cache-Control: no-store`.\n","parameters":[{"name":"limit","in":"query","description":"Page size, clamped to `[1, 200]`.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"offset","in":"query","description":"Skip this many newest entries.","schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Transaction page","content":{"application/json":{"schema":{"type":"object","required":["transactions","next_offset"],"properties":{"transactions":{"type":"array","items":{"$ref":"#/components/schemas/ExplorerTransaction"}},"next_offset":{"type":"integer","nullable":true,"description":"`offset` for the next page. `null` once the ring is exhausted."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"}}}}},"components":{"schemas":{"ExplorerTransaction":{"type":"object","description":"Receipt fields merged with Ethereum JSON transaction fields (receipt wins on\noverlap; the receipt's `transactionHash` is dropped for the transaction's `hash`),\nplus `attestations`, `committee_epoch` and `decoded`. Block fields are absent or\n`null` while the transaction is served from the recent cache.\n","additionalProperties":true,"properties":{"hash":{"$ref":"#/components/schemas/Bytes32"},"from":{"$ref":"#/components/schemas/Address"},"to":{"$ref":"#/components/schemas/Address"},"nonce":{"type":"string","description":"`0x` hex"},"input":{"type":"string","description":"`0x` hex calldata"},"status":{"type":"string","description":"`0x1` success, `0x0` failure"},"blockNumber":{"type":"string","nullable":true},"blockHash":{"type":"string","nullable":true},"transactionIndex":{"type":"string","nullable":true},"logs":{"type":"array","items":{"type":"object"}},"attestations":{"type":"array","items":{"type":"object","properties":{"validator_address":{"$ref":"#/components/schemas/Address"},"sequence_number":{"type":"integer","format":"int64"},"batch_index":{"type":"integer"},"timestamp":{"$ref":"#/components/schemas/Timestamp"},"signature":{"type":"string"}}}},"committee_epoch":{"type":"integer","format":"int64"},"decoded":{"$ref":"#/components/schemas/DecodedCalldata"}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"Timestamp":{"type":"integer","format":"int64","description":"Unix time in microseconds, as a JSON number"},"DecodedCalldata":{"type":"object","description":"Calldata decoded against Pod's precompiles. For an unrecognized target or\nselector, `contract` is `null` and only `selector` and `raw` are set.\n","properties":{"contract":{"type":"string","nullable":true},"address":{"$ref":"#/components/schemas/Address"},"symbol":{"type":"string"},"function":{"type":"string"},"args":{"type":"object","additionalProperties":true},"order_id":{"$ref":"#/components/schemas/Bytes32","description":"Resting order id the call creates (`submitOrder`, `submitTrigger`)."},"sequence":{"type":"integer","description":"Position inside the parent `submitBatch`."},"intents":{"type":"array","description":"Decoded sub-intents of a `submitBatch`.","items":{"type":"object"}},"selector":{"type":"string","description":"4-byte selector, `0x` hex."},"raw":{"type":"string","description":"Raw calldata, `0x` hex."}}}},"responses":{"BadRequest":{"description":"Malformed path or query parameter. Plain-text reason.","content":{"text/plain":{"schema":{"type":"string"}}}}}}}
```


# Bridge

Bridge configuration and withdrawal outcomes, with the claim proof for a single withdrawal. Served by every node.

&#x20;   &#x20;

## Get Bridge Configuration

> The chain withdrawals are claimable on, its bridge contract, the bridge version,\
> and every bridged token.\
> \
> \`claim\_chain\_id\` and \`source\_contract\` are zero and \`tokens\` is empty when the node\
> has no bridge configured. No withdrawal is admissible then.\
> \
> No \`Cache-Control\` header is set.<br>

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"tags":[{"name":"Bridge","description":"Bridge configuration and withdrawal outcomes, with the claim proof for a single\nwithdrawal. Served by every node.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/v1","description":"Pod testnet"}],"paths":{"/bridge/config":{"get":{"tags":["Bridge"],"summary":"Get Bridge Configuration","operationId":"getBridgeConfig","description":"The chain withdrawals are claimable on, its bridge contract, the bridge version,\nand every bridged token.\n\n`claim_chain_id` and `source_contract` are zero and `tokens` is empty when the node\nhas no bridge configured. No withdrawal is admissible then.\n\nNo `Cache-Control` header is set.\n","responses":{"200":{"description":"Bridge configuration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BridgeConfig"}}}}}}}},"components":{"schemas":{"BridgeConfig":{"type":"object","properties":{"claim_chain_id":{"type":"integer","format":"int64","description":"The one chain withdrawals are claimable on. `0` when no bridge is configured."},"source_contract":{"$ref":"#/components/schemas/Address","description":"Bridge contract on that chain. Zero address when no bridge is configured."},"version":{"type":"integer","format":"int64","description":"Bridge version; feeds the claim-hash domain separator."},"tokens":{"type":"array","description":"Every bridged token, ordered by `pod_token`. The only source of the Pod-token to bridged-chain-token mapping. Empty when no bridge is configured.","items":{"type":"object","properties":{"pod_token":{"$ref":"#/components/schemas/Address"},"l1_token":{"$ref":"#/components/schemas/Address"},"decimals":{"type":"integer","description":"Decimals on the bridged chain. A withdrawal amount must be a multiple of `10^(18 - decimals)` wei."},"min":{"$ref":"#/components/schemas/HexUint256","description":"Minimum withdrawal, bridged-chain decimals."},"max":{"$ref":"#/components/schemas/HexUint256","description":"Maximum withdrawal, bridged-chain decimals."}}}}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"}}}}
```

## List Withdrawals

> Withdrawal outcomes for every account, oldest first by \`(timestamp\_us,\
> tx\_hash)\`. Same entries as the \`pod\_withdrawals\` websocket channel, and \`since\` is\
> the same cursor. To continue, pass the last entry's \`timestamp\_us\` as \`since\` and its\
> \`tx\_hash\` as \`since\_id\`.\
> \
> Legacy \`Bridge.withdraw\` rows are excluded.\
> \
> No \`Cache-Control\` header is set.<br>

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"tags":[{"name":"Bridge","description":"Bridge configuration and withdrawal outcomes, with the claim proof for a single\nwithdrawal. Served by every node.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/v1","description":"Pod testnet"}],"paths":{"/bridge/withdrawals":{"get":{"tags":["Bridge"],"summary":"List Withdrawals","operationId":"listWithdrawals","description":"Withdrawal outcomes for every account, oldest first by `(timestamp_us,\ntx_hash)`. Same entries as the `pod_withdrawals` websocket channel, and `since` is\nthe same cursor. To continue, pass the last entry's `timestamp_us` as `since` and its\n`tx_hash` as `since_id`.\n\nLegacy `Bridge.withdraw` rows are excluded.\n\nNo `Cache-Control` header is set.\n","parameters":[{"$ref":"#/components/parameters/WithdrawalSince"},{"$ref":"#/components/parameters/WithdrawalSinceId"},{"$ref":"#/components/parameters/WithdrawalLimit"}],"responses":{"200":{"description":"Withdrawal outcomes","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Withdrawal"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalError"}}}}},"components":{"parameters":{"WithdrawalSince":{"name":"since","in":"query","description":"Batch deadline in microseconds; returns outcomes strictly after it, or within it after `since_id`.","schema":{"type":"integer","format":"int64","default":0}},"WithdrawalSinceId":{"name":"since_id","in":"query","description":"Last `tx_hash` already seen within the `since` tick, to resume a page that ended mid-tick. Omit to resume after the whole tick.","schema":{"$ref":"#/components/schemas/Bytes32"}},"WithdrawalLimit":{"name":"limit","in":"query","description":"Page size. Values above 1000 are capped at 1000.","schema":{"type":"integer","minimum":0,"maximum":1000,"default":500}}},"schemas":{"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"Withdrawal":{"type":"object","description":"One withdrawal outcome, as `pod_withdrawals` delivers it.","required":["tx_hash","withdrawer","to","token","amount","timestamp_us"],"properties":{"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"The withdraw transaction's hash, the withdrawal's id."},"withdrawer":{"$ref":"#/components/schemas/Address","description":"The debited account; the master for a delegated withdrawal."},"to":{"$ref":"#/components/schemas/Address","description":"Recipient on the bridged chain."},"token":{"$ref":"#/components/schemas/Address","description":"Pod-side token."},"amount":{"$ref":"#/components/schemas/HexUint256","description":"Pod's 18 decimals, as signed. `claim` takes `proof.amount`."},"error":{"type":"string","enum":["insufficient_balance","not_included"],"description":"Why the withdrawal was refused. Omitted otherwise."},"timestamp_us":{"type":"integer","format":"int64","description":"The tick's batch deadline, microseconds. Also the `since` cursor."}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"}},"responses":{"BadRequest":{"description":"Malformed path or query parameter. Plain-text reason.","content":{"text/plain":{"schema":{"type":"string"}}}},"InternalError":{"description":"The ledger read failed. Empty body."}}}}
```

## List Account Withdrawals

> As \`/bridge/withdrawals\`, restricted to withdrawals debited from \`account\` (the\
> \`withdrawer\`, which is the master for a delegated withdrawal).\
> \
> No \`Cache-Control\` header is set.<br>

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"tags":[{"name":"Bridge","description":"Bridge configuration and withdrawal outcomes, with the claim proof for a single\nwithdrawal. Served by every node.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/v1","description":"Pod testnet"}],"paths":{"/bridge/withdrawals/{account}":{"get":{"tags":["Bridge"],"summary":"List Account Withdrawals","operationId":"listAccountWithdrawals","description":"As `/bridge/withdrawals`, restricted to withdrawals debited from `account` (the\n`withdrawer`, which is the master for a delegated withdrawal).\n\nNo `Cache-Control` header is set.\n","parameters":[{"$ref":"#/components/parameters/AccountPath"},{"$ref":"#/components/parameters/WithdrawalSince"},{"$ref":"#/components/parameters/WithdrawalSinceId"},{"$ref":"#/components/parameters/WithdrawalLimit"}],"responses":{"200":{"description":"Withdrawal outcomes","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Withdrawal"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalError"}}}}},"components":{"parameters":{"AccountPath":{"name":"account","in":"path","required":true,"schema":{"$ref":"#/components/schemas/Address"}},"WithdrawalSince":{"name":"since","in":"query","description":"Batch deadline in microseconds; returns outcomes strictly after it, or within it after `since_id`.","schema":{"type":"integer","format":"int64","default":0}},"WithdrawalSinceId":{"name":"since_id","in":"query","description":"Last `tx_hash` already seen within the `since` tick, to resume a page that ended mid-tick. Omit to resume after the whole tick.","schema":{"$ref":"#/components/schemas/Bytes32"}},"WithdrawalLimit":{"name":"limit","in":"query","description":"Page size. Values above 1000 are capped at 1000.","schema":{"type":"integer","minimum":0,"maximum":1000,"default":500}}},"schemas":{"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"Withdrawal":{"type":"object","description":"One withdrawal outcome, as `pod_withdrawals` delivers it.","required":["tx_hash","withdrawer","to","token","amount","timestamp_us"],"properties":{"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"The withdraw transaction's hash, the withdrawal's id."},"withdrawer":{"$ref":"#/components/schemas/Address","description":"The debited account; the master for a delegated withdrawal."},"to":{"$ref":"#/components/schemas/Address","description":"Recipient on the bridged chain."},"token":{"$ref":"#/components/schemas/Address","description":"Pod-side token."},"amount":{"$ref":"#/components/schemas/HexUint256","description":"Pod's 18 decimals, as signed. `claim` takes `proof.amount`."},"error":{"type":"string","enum":["insufficient_balance","not_included"],"description":"Why the withdrawal was refused. Omitted otherwise."},"timestamp_us":{"type":"integer","format":"int64","description":"The tick's batch deadline, microseconds. Also the `since` cursor."}}},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"}},"responses":{"BadRequest":{"description":"Malformed path or query parameter. Plain-text reason.","content":{"text/plain":{"schema":{"type":"string"}}}},"InternalError":{"description":"The ledger read failed. Empty body."}}}}
```

## Get Withdrawal and Claim Proof

> One withdrawal, keyed by the withdraw transaction's hash, with where it stands and\
> the claim proof once one can be assembled.\
> \
> \- \`claimable\`: \`proof\` is attached and the bridge contract will accept it.\
> \- \`pending\`: fewer than \`n - f\` signatures are held, or this node failed to\
> &#x20; assemble a proof it should have. The node asks its peers for the missing\
> &#x20; signatures itself; keep polling, or ask another node.\
> \- \`refused\`: refused at execution. Nothing was debited and no claim will exist;\
> &#x20; resubmitting yields a new \`tx\_hash\`. \`withdrawal.error\` usually names the\
> &#x20; reason but can be absent.\
> \
> Branch on the presence of \`proof\`: treat \`refused\` as terminal and anything else\
> as "ask again".\
> \
> \`404\` until the withdrawal has executed, a tick after admission.\
> \
> No \`Cache-Control\` header is set.<br>

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"tags":[{"name":"Bridge","description":"Bridge configuration and withdrawal outcomes, with the claim proof for a single\nwithdrawal. Served by every node.\n\n&nbsp; &nbsp; &nbsp;\n"}],"servers":[{"url":"https://rpc.podtestnet.dev/v1","description":"Pod testnet"}],"paths":{"/bridge/withdrawals/by-id/{tx_hash}":{"get":{"tags":["Bridge"],"summary":"Get Withdrawal and Claim Proof","operationId":"getWithdrawalById","description":"One withdrawal, keyed by the withdraw transaction's hash, with where it stands and\nthe claim proof once one can be assembled.\n\n- `claimable`: `proof` is attached and the bridge contract will accept it.\n- `pending`: fewer than `n - f` signatures are held, or this node failed to\n  assemble a proof it should have. The node asks its peers for the missing\n  signatures itself; keep polling, or ask another node.\n- `refused`: refused at execution. Nothing was debited and no claim will exist;\n  resubmitting yields a new `tx_hash`. `withdrawal.error` usually names the\n  reason but can be absent.\n\nBranch on the presence of `proof`: treat `refused` as terminal and anything else\nas \"ask again\".\n\n`404` until the withdrawal has executed, a tick after admission.\n\nNo `Cache-Control` header is set.\n","parameters":[{"name":"tx_hash","in":"path","required":true,"description":"Hash of the withdraw transaction.","schema":{"$ref":"#/components/schemas/Bytes32"}}],"responses":{"200":{"description":"Withdrawal detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WithdrawalDetail"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"description":"No withdrawal with this id has executed on this node. Empty body."},"500":{"$ref":"#/components/responses/InternalError"}}}}},"components":{"schemas":{"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"WithdrawalDetail":{"type":"object","required":["withdrawal","status"],"properties":{"withdrawal":{"$ref":"#/components/schemas/Withdrawal"},"status":{"type":"string","enum":["claimable","pending","refused"],"description":"May gain values. Treat an unfamiliar one as `pending`."},"proof":{"$ref":"#/components/schemas/BridgeClaimProof"}}},"Withdrawal":{"type":"object","description":"One withdrawal outcome, as `pod_withdrawals` delivers it.","required":["tx_hash","withdrawer","to","token","amount","timestamp_us"],"properties":{"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"The withdraw transaction's hash, the withdrawal's id."},"withdrawer":{"$ref":"#/components/schemas/Address","description":"The debited account; the master for a delegated withdrawal."},"to":{"$ref":"#/components/schemas/Address","description":"Recipient on the bridged chain."},"token":{"$ref":"#/components/schemas/Address","description":"Pod-side token."},"amount":{"$ref":"#/components/schemas/HexUint256","description":"Pod's 18 decimals, as signed. `claim` takes `proof.amount`."},"error":{"type":"string","enum":["insufficient_balance","not_included"],"description":"Why the withdrawal was refused. Omitted otherwise."},"timestamp_us":{"type":"integer","format":"int64","description":"The tick's batch deadline, microseconds. Also the `since` cursor."}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"},"BridgeClaimProof":{"type":"object","description":"Present exactly when `status` is `claimable`. Everything `claim(token, amount, to,\nproof, auxTxSuffix)` needs, except `token`: map the Pod-side `token` here to\n`l1_token` from `/bridge/config`.\n","required":["proof","committee_epoch","aux_tx_suffix"],"properties":{"proof":{"type":"array","items":{"type":"integer","minimum":0,"maximum":255},"description":"Certificate (`0x00` then one 65-byte signature per signer, by ascending signer address) or, for a withdrawal from before a bridge version bump, a Merkle proof."},"committee_epoch":{"type":"integer","format":"int64","description":"Currently always `0`."},"aux_tx_suffix":{"type":"array","items":{"type":"integer","minimum":0,"maximum":255},"description":"The withdrawal's id (its tx hash) as bytes."},"token":{"$ref":"#/components/schemas/Address","description":"Pod-side token. Omitted on legacy rows."},"amount":{"$ref":"#/components/schemas/HexUint256","description":"In the token's bridged-chain decimals; pass straight to `claim`. Omitted on legacy rows."},"to":{"$ref":"#/components/schemas/Address","description":"Recipient on the bridged chain. Omitted on legacy rows."},"claim_hash":{"$ref":"#/components/schemas/Bytes32","description":"The key `Bridge.processedRequests` uses; check it to see whether the claim already landed."}}}},"responses":{"BadRequest":{"description":"Malformed path or query parameter. Plain-text reason.","content":{"text/plain":{"schema":{"type":"string"}}}},"InternalError":{"description":"The ledger read failed. Empty body."}}}}
```


# Models

## The Address object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"}}}}
```

## The Bytes32 object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."}}}}
```

## The HexUint256 object

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

## The DecimalUint256 object

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

## The DecimalInt256 object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"DecimalInt256":{"type":"string","pattern":"^-?[0-9]+$","description":"Signed 256-bit integer, decimal string"}}}}
```

## The Timestamp object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"Timestamp":{"type":"integer","format":"int64","description":"Unix time in microseconds, as a JSON number"}}}}
```

## The TimestampString object

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

## The CandleResolution object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"CandleResolution":{"type":"string","enum":["1m","5m","15m","30m","1h","4h","1d","1w","1M"]}}}}
```

## The MarketType object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"MarketType":{"type":"string","enum":["spot","perpetual"]}}}}
```

## The OrderStatus object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"OrderStatus":{"type":"string","enum":["pending","active","filled","expired","canceled","margin_canceled","self_trade_canceled","post_only_refused","invalid"],"description":"- `pending`: submitted, not yet in the book\n- `active`: resting in the book\n- `filled`: completely filled\n- `expired`: TTL passed\n- `canceled`: canceled by the owner\n- `margin_canceled`: removed by the engine because the owner's margin was exhausted\n- `self_trade_canceled`: removed by the engine because it was about to fill against an order of the same owner\n- `post_only_refused`: a `post_only` order removed because it would have taken liquidity in the batch that admitted it\n- `invalid`: rejected at execution and never entered the book; see `invalid_reason`\n\nEverything except `pending` and `active` is terminal.\n"}}}}
```

## The OrderKind object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"OrderKind":{"type":"string","enum":["user_signed","liquidation","triggered","adl","adl_counterparty","backstop_transfer"],"description":"- `user_signed`: submitted by the account\n- `liquidation`: generated by the engine when the account fell below maintenance margin\n- `triggered`: the order a fired TP/SL trigger produced\n- `adl`: auto-deleveraging close of this account's position\n- `adl_counterparty`: this account's side covering an auto-deleveraging close\n- `backstop_transfer`: a backstop sweep of this account's position, shown as a terminal order\n"}}}}
```

## The OrderDirection object

```json
{"openapi":"3.0.0","info":{"title":"REST 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":"Spot orders use `buy`/`sell`. Perp orders use the position effect of their fills; `liquidation` when `kind` is `liquidation`."}}}}
```

## The TriggerType object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"TriggerType":{"type":"string","enum":["take_profit","stop_loss"]}}}}
```

## The TriggerGrouping object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"TriggerGrouping":{"type":"string","enum":["none","asset"],"description":"- `none`: standalone; removed only by cancel, TTL expiry or its own fire\n- `asset`: removed, with any resting order it produced, once the owner's position on the pair (perp) or base holding (spot) reaches zero\n"}}}}
```

## The MarketStatic object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"MarketStatic":{"type":"object","description":"Static market configuration. Numeric amounts are decimal strings.","properties":{"status":{"type":"string","enum":["pending","active","disabled","settled"],"description":"Lifecycle status."},"id":{"$ref":"#/components/schemas/Bytes32"},"name":{"type":"string","description":"`{base_symbol}/{quote_symbol}`"},"base_token_address":{"$ref":"#/components/schemas/Address"},"quote_token_address":{"$ref":"#/components/schemas/Address"},"base_token_symbol":{"type":"string"},"quote_token_symbol":{"type":"string"},"base_token_name":{"type":"string"},"quote_token_name":{"type":"string"},"market_type":{"type":"string","enum":["spot","perp"],"description":"Order rows spell this `perpetual`."},"auction_interval_us":{"type":"integer","format":"int64","description":"Batch interval, microseconds"},"maker_fee":{"type":"string","description":"Fee rate as a decimal fraction, six places (`\"0.000150\"` is 1.5 bps)."},"taker_fee":{"type":"string","description":"Fee rate as a decimal fraction, six places."},"tick_precision":{"$ref":"#/components/schemas/DecimalUint256"},"lot_size":{"$ref":"#/components/schemas/DecimalUint256"},"min_notional":{"type":"string","description":"Minimum quote notional per order, 1e18-scaled decimal string. `\"0\"` is no floor."},"max_leverage":{"type":"integer"},"initial_margin":{"type":"string","description":"Initial-margin rate, 1e18-scaled decimal string, unrounded (`max_leverage` is rounded)."},"funding_window_us":{"type":"integer","format":"int64","description":"Period `funding_rate` applies over, microseconds"},"live_at_us":{"type":"integer","format":"int64","description":"When a `pending` market goes live, microseconds. Omitted when not scheduled."},"disable_at_us":{"type":"integer","format":"int64","description":"Scheduled halt, microseconds. Omitted when none."},"settlement_price":{"type":"string","description":"Price open positions settle at, fixed when a perp market halts. 1e18-scaled decimal string. Omitted until then."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"DecimalUint256":{"type":"string","pattern":"^[0-9]+$","description":"Unsigned 256-bit integer, decimal string"}}}}
```

## The MarketStats object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"MarketStats":{"type":"object","description":"Live statistics for one market. Prices and amounts are 1e18-scaled decimal\nstrings. Optional fields are omitted until the data exists.\n","required":["orderbook_id","volume_24h"],"properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"last_clearing_price":{"type":"string","description":"Omitted until the market's first fill."},"volume_24h":{"type":"string","description":"Quote notional traded over 24 hours."},"high_24h":{"type":"string","description":"Omitted until the market has a closed candle."},"low_24h":{"type":"string","description":"Omitted until the market has a closed candle."},"price_change_24h":{"type":"integer","description":"24-hour price change in basis points."},"oracle_price":{"type":"string","description":"Perp only."},"internal":{"type":"boolean","description":"`true` when `oracle_price` is derived from the book because every oracle source was stale."},"mark_price":{"type":"string","description":"Perp only."},"funding_rate":{"type":"string","description":"Perp only. Signed."},"funding_index":{"type":"string","description":"Perp only. Signed, undivided funding accumulator."},"funding_settling_index":{"type":"string","description":"Perp only. The index positions settle against (`funding_settling_index × size − funding_basis` is a position's accrual). Absent until the market's first perp batch after the node started."},"funding_last_updated_us":{"type":"integer","format":"int64","description":"Perp only."},"open_interest":{"type":"string","description":"Perp only. USD notional."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."}}}}
```

## The Candle object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"Candle":{"type":"object","description":"One closed OHLCV bar. Prices and volumes are 1e18-scaled `0x` hex.","properties":{"timestamp":{"$ref":"#/components/schemas/Timestamp"},"open":{"$ref":"#/components/schemas/HexUint256"},"close":{"$ref":"#/components/schemas/HexUint256"},"high":{"$ref":"#/components/schemas/HexUint256"},"low":{"$ref":"#/components/schemas/HexUint256"},"volume":{"$ref":"#/components/schemas/HexUint256","description":"Base volume traded in the bucket."},"quote_volume":{"$ref":"#/components/schemas/HexUint256","description":"Quote notional traded in the bucket."}}},"Timestamp":{"type":"integer","format":"int64","description":"Unix time in microseconds, as a JSON number"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"}}}}
```

## The OrderbookSnapshot object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"OrderbookSnapshot":{"type":"object","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"buys":{"type":"object","additionalProperties":{"type":"object","properties":{"volume":{"$ref":"#/components/schemas/HexUint256"}}},"description":"Buy levels keyed by price (decimal string), price-ascending; the best bid is the last key."},"sells":{"type":"object","additionalProperties":{"type":"object","properties":{"volume":{"$ref":"#/components/schemas/HexUint256"}}},"description":"Sell levels keyed by price (decimal string), price-ascending; the best ask is the first key."},"buys_count":{"type":"integer","description":"Buy levels in the full book."},"sells_count":{"type":"integer","description":"Sell levels in the full book."},"grouping_precision":{"$ref":"#/components/schemas/HexUint256"},"timestamp":{"$ref":"#/components/schemas/Timestamp"},"new_orders_count":{"type":"integer"},"clearing_price":{"$ref":"#/components/schemas/HexUint256","description":"The orderbook's current mark, carried forward on ticks without fills."},"oracle_price":{"type":"string","nullable":true,"description":"Perp only, `0x` hex. `null` for spot."},"funding_rate":{"type":"string","nullable":true,"description":"Perp only, signed decimal string. `null` for spot."},"funding_index":{"type":"string","nullable":true,"description":"Perp only, signed decimal string. `null` for spot."},"funding_last_updated":{"type":"integer","format":"int64","nullable":true,"description":"Perp only, microseconds. `null` for spot."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"},"Timestamp":{"type":"integer","format":"int64","description":"Unix time in microseconds, as a JSON number"}}}}
```

## The Solution object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"Solution":{"type":"object","description":"One orderbook's record for one tick. Unsigned values are 1e18-scaled `0x` hex,\nsigned values decimal strings. Perp-only fields are omitted on spot ticks and on\nrows recorded before the field existed.\n","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"timestamp":{"$ref":"#/components/schemas/Timestamp","description":"Batch deadline."},"clearing_price":{"$ref":"#/components/schemas/HexUint256","description":"Omitted for a market that has never traded."},"mark_price":{"$ref":"#/components/schemas/HexUint256","description":"`0x0` for spot."},"volume":{"$ref":"#/components/schemas/HexUint256"},"oracle_price":{"$ref":"#/components/schemas/HexUint256"},"funding_rate":{"$ref":"#/components/schemas/DecimalInt256"},"funding_index":{"$ref":"#/components/schemas/DecimalInt256"},"open_interest":{"$ref":"#/components/schemas/HexUint256"},"mark_best_bid":{"$ref":"#/components/schemas/HexUint256"},"mark_best_ask":{"$ref":"#/components/schemas/HexUint256"},"premium_ema":{"$ref":"#/components/schemas/DecimalInt256"},"book_median_ema":{"$ref":"#/components/schemas/HexUint256"},"impact_bid":{"$ref":"#/components/schemas/HexUint256"},"impact_ask":{"$ref":"#/components/schemas/HexUint256"}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"Timestamp":{"type":"integer","format":"int64","description":"Unix time in microseconds, as a JSON number"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"},"DecimalInt256":{"type":"string","pattern":"^-?[0-9]+$","description":"Signed 256-bit integer, decimal string"}}}}
```

## The PartialFill object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"PartialFill":{"type":"object","properties":{"base_amount":{"$ref":"#/components/schemas/HexUint256"},"quote_amount":{"$ref":"#/components/schemas/HexUint256"},"timestamp":{"$ref":"#/components/schemas/Timestamp"},"price":{"$ref":"#/components/schemas/HexUint256","description":"The batch's clearing price; the order's own price for ADL fills."}}},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"},"Timestamp":{"type":"integer","format":"int64","description":"Unix time in microseconds, as a JSON number"}}}}
```

## The Order object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"Order":{"type":"object","description":"An order with its fills. Unsigned amounts and prices are 1e18-scaled `0x` hex,\nsigned ones decimal strings. Perp-only fields are omitted on spot orders.\n","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"market_type":{"$ref":"#/components/schemas/MarketType"},"kind":{"$ref":"#/components/schemas/OrderKind"},"order_id":{"$ref":"#/components/schemas/Bytes32"},"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"Creating transaction. Zero for engine-generated orders."},"bidder":{"$ref":"#/components/schemas/Address"},"nonce":{"type":"integer","format":"int64"},"order_type":{"type":"string","enum":["limit","market"]},"status":{"$ref":"#/components/schemas/OrderStatus"},"side":{"type":"string","enum":["buy","sell"]},"price":{"$ref":"#/components/schemas/HexUint256"},"initial_size":{"$ref":"#/components/schemas/DecimalInt256","description":"Signed; positive buy/long, negative sell/short."},"filled_base_amount":{"$ref":"#/components/schemas/HexUint256"},"filled_quote_amount":{"$ref":"#/components/schemas/HexUint256"},"fee":{"$ref":"#/components/schemas/HexUint256"},"deadline":{"$ref":"#/components/schemas/TimestampString","description":"The batch the order targets, microseconds, as a string."},"end":{"$ref":"#/components/schemas/Timestamp","description":"TTL expiry, microseconds. Orders that never expire carry `18446744073709551615`, which exceeds a JavaScript safe integer."},"included_batch":{"$ref":"#/components/schemas/Timestamp","description":"Deadline of the batch that first included the order. `0` for engine-generated orders and older rows."},"invalid_reason":{"type":"string","description":"Why the engine rejected the order. Only when `status` is `invalid`."},"effective_price":{"$ref":"#/components/schemas/HexUint256","description":"`filled_quote / filled_base` so far."},"fills":{"type":"array","items":{"$ref":"#/components/schemas/PartialFill"},"description":"Always present, oldest first."},"reduce_only":{"type":"boolean","description":"Perp only."},"ioc":{"type":"boolean","description":"Perp only."},"post_only":{"type":"boolean","description":"Omitted when false."},"direction":{"$ref":"#/components/schemas/OrderDirection"},"realized_pnl":{"$ref":"#/components/schemas/DecimalInt256","description":"Perp only, present once a fill closed exposure. Price drift minus funding across the slices it closed."},"grouping":{"$ref":"#/components/schemas/TriggerGrouping","description":"Inherited from the parent trigger. Omitted when `none`."},"trigger_type":{"$ref":"#/components/schemas/TriggerType","description":"Set only on orders a fired trigger produced (`kind` `triggered`)."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"MarketType":{"type":"string","enum":["spot","perpetual"]},"OrderKind":{"type":"string","enum":["user_signed","liquidation","triggered","adl","adl_counterparty","backstop_transfer"],"description":"- `user_signed`: submitted by the account\n- `liquidation`: generated by the engine when the account fell below maintenance margin\n- `triggered`: the order a fired TP/SL trigger produced\n- `adl`: auto-deleveraging close of this account's position\n- `adl_counterparty`: this account's side covering an auto-deleveraging close\n- `backstop_transfer`: a backstop sweep of this account's position, shown as a terminal order\n"},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"OrderStatus":{"type":"string","enum":["pending","active","filled","expired","canceled","margin_canceled","self_trade_canceled","post_only_refused","invalid"],"description":"- `pending`: submitted, not yet in the book\n- `active`: resting in the book\n- `filled`: completely filled\n- `expired`: TTL passed\n- `canceled`: canceled by the owner\n- `margin_canceled`: removed by the engine because the owner's margin was exhausted\n- `self_trade_canceled`: removed by the engine because it was about to fill against an order of the same owner\n- `post_only_refused`: a `post_only` order removed because it would have taken liquidity in the batch that admitted it\n- `invalid`: rejected at execution and never entered the book; see `invalid_reason`\n\nEverything except `pending` and `active` is terminal.\n"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"},"DecimalInt256":{"type":"string","pattern":"^-?[0-9]+$","description":"Signed 256-bit integer, decimal string"},"TimestampString":{"type":"string","pattern":"^[0-9]+$","description":"Unix time in microseconds, as a decimal string"},"Timestamp":{"type":"integer","format":"int64","description":"Unix time in microseconds, as a JSON number"},"PartialFill":{"type":"object","properties":{"base_amount":{"$ref":"#/components/schemas/HexUint256"},"quote_amount":{"$ref":"#/components/schemas/HexUint256"},"timestamp":{"$ref":"#/components/schemas/Timestamp"},"price":{"$ref":"#/components/schemas/HexUint256","description":"The batch's clearing price; the order's own price for ADL fills."}}},"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":"Spot orders use `buy`/`sell`. Perp orders use the position effect of their fills; `liquidation` when `kind` is `liquidation`."},"TriggerGrouping":{"type":"string","enum":["none","asset"],"description":"- `none`: standalone; removed only by cancel, TTL expiry or its own fire\n- `asset`: removed, with any resting order it produced, once the owner's position on the pair (perp) or base holding (spot) reaches zero\n"},"TriggerType":{"type":"string","enum":["take_profit","stop_loss"]}}}}
```

## The Fill object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"Fill":{"type":"object","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_token":{"$ref":"#/components/schemas/Address"},"quote_token":{"$ref":"#/components/schemas/Address"},"order_id":{"$ref":"#/components/schemas/Bytes32"},"order_type":{"type":"string","enum":["limit","market"]},"initial_size":{"$ref":"#/components/schemas/DecimalInt256"},"fee":{"$ref":"#/components/schemas/HexUint256"},"base_amount":{"$ref":"#/components/schemas/HexUint256"},"quote_amount":{"$ref":"#/components/schemas/HexUint256"},"timestamp":{"$ref":"#/components/schemas/Timestamp"},"price":{"$ref":"#/components/schemas/HexUint256"}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"DecimalInt256":{"type":"string","pattern":"^-?[0-9]+$","description":"Signed 256-bit integer, decimal string"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"},"Timestamp":{"type":"integer","format":"int64","description":"Unix time in microseconds, as a JSON number"}}}}
```

## The PerpPosition object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"PerpPosition":{"type":"object","description":"One open perp position. 1e18-scaled; unsigned `0x` hex, signed decimal strings.","properties":{"kind":{"type":"string","enum":["perp"]},"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"side":{"type":"string","enum":["long","short"]},"size":{"$ref":"#/components/schemas/DecimalInt256","description":"Positive long, negative short."},"notional":{"$ref":"#/components/schemas/HexUint256"},"entry_price":{"$ref":"#/components/schemas/HexUint256","description":"Rounded against the holder; `unrealized_pnl` is exact."},"mark_price":{"$ref":"#/components/schemas/HexUint256"},"margin":{"$ref":"#/components/schemas/HexUint256"},"leverage":{"$ref":"#/components/schemas/HexUint256"},"funding_accrued":{"$ref":"#/components/schemas/DecimalInt256","description":"Funding owed on the position, quote wei. Positive is owed by the holder."},"funding_basis":{"$ref":"#/components/schemas/DecimalInt256"},"cost_basis":{"$ref":"#/components/schemas/DecimalInt256"},"entry_funding":{"$ref":"#/components/schemas/DecimalInt256"},"liquidation_price":{"$ref":"#/components/schemas/HexUint256"},"unrealized_pnl":{"$ref":"#/components/schemas/DecimalInt256"},"realized_pnl":{"$ref":"#/components/schemas/DecimalInt256","description":"Always `\"0\"`; realized PnL is banked into cash and `total_realized_pnl`."},"stop_loss":{"type":"string","nullable":true,"description":"Always `null`."},"take_profit":{"type":"string","nullable":true,"description":"Always `null`."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"DecimalInt256":{"type":"string","pattern":"^-?[0-9]+$","description":"Signed 256-bit integer, decimal string"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"}}}}
```

## The SpotHolding object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"SpotHolding":{"type":"object","description":"One spot token holding. 1e18-scaled; unsigned `0x` hex, signed decimal strings.","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"balance":{"$ref":"#/components/schemas/HexUint256","description":"`free_balance + locked_balance`."},"free_balance":{"$ref":"#/components/schemas/HexUint256"},"locked_balance":{"$ref":"#/components/schemas/HexUint256","description":"Locked in open sell orders."},"cost_basis":{"$ref":"#/components/schemas/HexUint256"},"mark_price":{"$ref":"#/components/schemas/HexUint256"},"unrealized_pnl":{"$ref":"#/components/schemas/DecimalInt256"},"realized_pnl":{"$ref":"#/components/schemas/DecimalInt256","description":"Portfolio-wide lifetime spot realized PnL."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"},"DecimalInt256":{"type":"string","pattern":"^-?[0-9]+$","description":"Signed 256-bit integer, decimal string"}}}}
```

## The PositionsResponse object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"PositionsResponse":{"type":"object","properties":{"positions":{"type":"array","items":{"$ref":"#/components/schemas/PerpPosition"}},"total_unrealized_pnl":{"$ref":"#/components/schemas/DecimalInt256"},"total_realized_pnl":{"$ref":"#/components/schemas/DecimalInt256","description":"Lifetime, spot and perp."},"perps_equity":{"$ref":"#/components/schemas/DecimalInt256","description":"Cash adjusted for unsettled funding, plus perp unrealized PnL."},"account_value":{"$ref":"#/components/schemas/DecimalInt256","description":"`perps_equity` plus the mark value of spot holdings and quote escrowed in resting spot buys."},"cash":{"$ref":"#/components/schemas/DecimalInt256"},"withdrawable_cash":{"$ref":"#/components/schemas/HexUint256","description":"What a withdrawal or transfer can take now: `max(0, equity − max(initial_margin, transfer_margin_ratio × notional))`, where `notional` is `Σ |size| × mark` and `transfer_margin_ratio` is a network parameter (10% by default). Equity counts unrealized PnL."},"net_deposits":{"$ref":"#/components/schemas/DecimalInt256","description":"Native collateral deposited minus withdrawn. Lifetime PnL is `account_value − net_deposits`."}}},"PerpPosition":{"type":"object","description":"One open perp position. 1e18-scaled; unsigned `0x` hex, signed decimal strings.","properties":{"kind":{"type":"string","enum":["perp"]},"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"side":{"type":"string","enum":["long","short"]},"size":{"$ref":"#/components/schemas/DecimalInt256","description":"Positive long, negative short."},"notional":{"$ref":"#/components/schemas/HexUint256"},"entry_price":{"$ref":"#/components/schemas/HexUint256","description":"Rounded against the holder; `unrealized_pnl` is exact."},"mark_price":{"$ref":"#/components/schemas/HexUint256"},"margin":{"$ref":"#/components/schemas/HexUint256"},"leverage":{"$ref":"#/components/schemas/HexUint256"},"funding_accrued":{"$ref":"#/components/schemas/DecimalInt256","description":"Funding owed on the position, quote wei. Positive is owed by the holder."},"funding_basis":{"$ref":"#/components/schemas/DecimalInt256"},"cost_basis":{"$ref":"#/components/schemas/DecimalInt256"},"entry_funding":{"$ref":"#/components/schemas/DecimalInt256"},"liquidation_price":{"$ref":"#/components/schemas/HexUint256"},"unrealized_pnl":{"$ref":"#/components/schemas/DecimalInt256"},"realized_pnl":{"$ref":"#/components/schemas/DecimalInt256","description":"Always `\"0\"`; realized PnL is banked into cash and `total_realized_pnl`."},"stop_loss":{"type":"string","nullable":true,"description":"Always `null`."},"take_profit":{"type":"string","nullable":true,"description":"Always `null`."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"DecimalInt256":{"type":"string","pattern":"^-?[0-9]+$","description":"Signed 256-bit integer, decimal string"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"}}}}
```

## The BalancesResponse object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"BalancesResponse":{"type":"object","properties":{"balances":{"type":"array","items":{"$ref":"#/components/schemas/SpotHolding"}},"cash":{"$ref":"#/components/schemas/DecimalInt256"},"withdrawable_cash":{"$ref":"#/components/schemas/HexUint256"},"net_deposits":{"$ref":"#/components/schemas/DecimalInt256"}}},"SpotHolding":{"type":"object","description":"One spot token holding. 1e18-scaled; unsigned `0x` hex, signed decimal strings.","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"base_symbol":{"type":"string"},"quote_symbol":{"type":"string"},"balance":{"$ref":"#/components/schemas/HexUint256","description":"`free_balance + locked_balance`."},"free_balance":{"$ref":"#/components/schemas/HexUint256"},"locked_balance":{"$ref":"#/components/schemas/HexUint256","description":"Locked in open sell orders."},"cost_basis":{"$ref":"#/components/schemas/HexUint256"},"mark_price":{"$ref":"#/components/schemas/HexUint256"},"unrealized_pnl":{"$ref":"#/components/schemas/DecimalInt256"},"realized_pnl":{"$ref":"#/components/schemas/DecimalInt256","description":"Portfolio-wide lifetime spot realized PnL."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"},"DecimalInt256":{"type":"string","pattern":"^-?[0-9]+$","description":"Signed 256-bit integer, decimal string"}}}}
```

## The Trigger object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"Trigger":{"type":"object","description":"An armed TP/SL trigger.","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"order_id":{"$ref":"#/components/schemas/Bytes32"},"tx_hash":{"$ref":"#/components/schemas/Bytes32"},"bidder":{"$ref":"#/components/schemas/Address"},"nonce":{"type":"integer","format":"int64"},"size":{"$ref":"#/components/schemas/DecimalInt256","description":"Signed. `\"0\"` (only with `grouping` `asset`) sizes from the owner's exposure when the trigger fires."},"limit_price":{"$ref":"#/components/schemas/HexUint256"},"trigger_price":{"$ref":"#/components/schemas/HexUint256"},"trigger_type":{"$ref":"#/components/schemas/TriggerType"},"grouping":{"$ref":"#/components/schemas/TriggerGrouping"},"reduce_only":{"type":"boolean"},"ioc":{"type":"boolean"},"deadline":{"$ref":"#/components/schemas/TimestampString"},"end":{"type":"integer","description":"TTL expiry, microseconds, as a JSON number."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"DecimalInt256":{"type":"string","pattern":"^-?[0-9]+$","description":"Signed 256-bit integer, decimal string"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"},"TriggerType":{"type":"string","enum":["take_profit","stop_loss"]},"TriggerGrouping":{"type":"string","enum":["none","asset"],"description":"- `none`: standalone; removed only by cancel, TTL expiry or its own fire\n- `asset`: removed, with any resting order it produced, once the owner's position on the pair (perp) or base holding (spot) reaches zero\n"},"TimestampString":{"type":"string","pattern":"^[0-9]+$","description":"Unix time in microseconds, as a decimal string"}}}}
```

## The BackstopTransfer object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"BackstopTransfer":{"type":"object","description":"One backstop sweep. Amounts are 1e18-scaled decimal strings.","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32","description":"The swept position's market. Omitted on the cash-sweep row."},"size":{"type":"string","description":"Signed position size moved."},"cash":{"type":"string","description":"Signed."},"mark_price":{"type":"string"},"equity":{"type":"string","description":"Signed account equity when the sweep triggered."},"realized_pnl":{"type":"string","description":"Signed. `\"0\"` on the cash-sweep row and older rows."},"timestamp_us":{"$ref":"#/components/schemas/Timestamp"}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"Timestamp":{"type":"integer","format":"int64","description":"Unix time in microseconds, as a JSON number"}}}}
```

## The ActivityFrame object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"ActivityFrame":{"type":"object","description":"One account's activity: batch deadline (microseconds, as a decimal-string key) to that\nbatch's entries, in the order given on the route. The `pod_activity` websocket channel\nsends the same shape with one key per tick.\n","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/ActivityEntry"}}},"ActivityEntry":{"description":"One activity entry, discriminated by `k`. Amounts and prices are 1e18-scaled decimal\nstrings. Optional fields are omitted rather than `null`; boolean flags are omitted when\nfalse. Ignore kinds and fields you do not recognise.\n","oneOf":[{"$ref":"#/components/schemas/ActivityOrder"},{"$ref":"#/components/schemas/ActivityFill"},{"$ref":"#/components/schemas/ActivityModify"},{"$ref":"#/components/schemas/ActivityTermination"},{"$ref":"#/components/schemas/ActivityBackstop"},{"$ref":"#/components/schemas/ActivityBridgeTransfer"},{"$ref":"#/components/schemas/ActivityTransfer"},{"$ref":"#/components/schemas/ActivityModifyReject"},{"$ref":"#/components/schemas/ActivityCancelReject"}],"discriminator":{"propertyName":"k","mapping":{"order":"#/components/schemas/ActivityOrder","fill":"#/components/schemas/ActivityFill","modify":"#/components/schemas/ActivityModify","termination":"#/components/schemas/ActivityTermination","backstop":"#/components/schemas/ActivityBackstop","bridge_transfer":"#/components/schemas/ActivityBridgeTransfer","transfer":"#/components/schemas/ActivityTransfer","modify_reject":"#/components/schemas/ActivityModifyReject","cancel_reject":"#/components/schemas/ActivityCancelReject"}}},"ActivityOrder":{"description":"The order as `/clob/orders/{account}` serves it, at the batch that admitted it, in its\ncurrent state. On the `pod_activity` channel it is the admission state instead:\n`active`, or `invalid` with `invalid_reason`, zero totals and `fills: []`. ADL closes\nappear as orders with `kind` `adl` or `adl_counterparty`; backstop sweeps appear only\nas `backstop` entries.\n","allOf":[{"type":"object","required":["k"],"properties":{"k":{"type":"string","enum":["order"]}}},{"$ref":"#/components/schemas/Order"}]},"Order":{"type":"object","description":"An order with its fills. Unsigned amounts and prices are 1e18-scaled `0x` hex,\nsigned ones decimal strings. Perp-only fields are omitted on spot orders.\n","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"market_type":{"$ref":"#/components/schemas/MarketType"},"kind":{"$ref":"#/components/schemas/OrderKind"},"order_id":{"$ref":"#/components/schemas/Bytes32"},"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"Creating transaction. Zero for engine-generated orders."},"bidder":{"$ref":"#/components/schemas/Address"},"nonce":{"type":"integer","format":"int64"},"order_type":{"type":"string","enum":["limit","market"]},"status":{"$ref":"#/components/schemas/OrderStatus"},"side":{"type":"string","enum":["buy","sell"]},"price":{"$ref":"#/components/schemas/HexUint256"},"initial_size":{"$ref":"#/components/schemas/DecimalInt256","description":"Signed; positive buy/long, negative sell/short."},"filled_base_amount":{"$ref":"#/components/schemas/HexUint256"},"filled_quote_amount":{"$ref":"#/components/schemas/HexUint256"},"fee":{"$ref":"#/components/schemas/HexUint256"},"deadline":{"$ref":"#/components/schemas/TimestampString","description":"The batch the order targets, microseconds, as a string."},"end":{"$ref":"#/components/schemas/Timestamp","description":"TTL expiry, microseconds. Orders that never expire carry `18446744073709551615`, which exceeds a JavaScript safe integer."},"included_batch":{"$ref":"#/components/schemas/Timestamp","description":"Deadline of the batch that first included the order. `0` for engine-generated orders and older rows."},"invalid_reason":{"type":"string","description":"Why the engine rejected the order. Only when `status` is `invalid`."},"effective_price":{"$ref":"#/components/schemas/HexUint256","description":"`filled_quote / filled_base` so far."},"fills":{"type":"array","items":{"$ref":"#/components/schemas/PartialFill"},"description":"Always present, oldest first."},"reduce_only":{"type":"boolean","description":"Perp only."},"ioc":{"type":"boolean","description":"Perp only."},"post_only":{"type":"boolean","description":"Omitted when false."},"direction":{"$ref":"#/components/schemas/OrderDirection"},"realized_pnl":{"$ref":"#/components/schemas/DecimalInt256","description":"Perp only, present once a fill closed exposure. Price drift minus funding across the slices it closed."},"grouping":{"$ref":"#/components/schemas/TriggerGrouping","description":"Inherited from the parent trigger. Omitted when `none`."},"trigger_type":{"$ref":"#/components/schemas/TriggerType","description":"Set only on orders a fired trigger produced (`kind` `triggered`)."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"MarketType":{"type":"string","enum":["spot","perpetual"]},"OrderKind":{"type":"string","enum":["user_signed","liquidation","triggered","adl","adl_counterparty","backstop_transfer"],"description":"- `user_signed`: submitted by the account\n- `liquidation`: generated by the engine when the account fell below maintenance margin\n- `triggered`: the order a fired TP/SL trigger produced\n- `adl`: auto-deleveraging close of this account's position\n- `adl_counterparty`: this account's side covering an auto-deleveraging close\n- `backstop_transfer`: a backstop sweep of this account's position, shown as a terminal order\n"},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"OrderStatus":{"type":"string","enum":["pending","active","filled","expired","canceled","margin_canceled","self_trade_canceled","post_only_refused","invalid"],"description":"- `pending`: submitted, not yet in the book\n- `active`: resting in the book\n- `filled`: completely filled\n- `expired`: TTL passed\n- `canceled`: canceled by the owner\n- `margin_canceled`: removed by the engine because the owner's margin was exhausted\n- `self_trade_canceled`: removed by the engine because it was about to fill against an order of the same owner\n- `post_only_refused`: a `post_only` order removed because it would have taken liquidity in the batch that admitted it\n- `invalid`: rejected at execution and never entered the book; see `invalid_reason`\n\nEverything except `pending` and `active` is terminal.\n"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"},"DecimalInt256":{"type":"string","pattern":"^-?[0-9]+$","description":"Signed 256-bit integer, decimal string"},"TimestampString":{"type":"string","pattern":"^[0-9]+$","description":"Unix time in microseconds, as a decimal string"},"Timestamp":{"type":"integer","format":"int64","description":"Unix time in microseconds, as a JSON number"},"PartialFill":{"type":"object","properties":{"base_amount":{"$ref":"#/components/schemas/HexUint256"},"quote_amount":{"$ref":"#/components/schemas/HexUint256"},"timestamp":{"$ref":"#/components/schemas/Timestamp"},"price":{"$ref":"#/components/schemas/HexUint256","description":"The batch's clearing price; the order's own price for ADL fills."}}},"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":"Spot orders use `buy`/`sell`. Perp orders use the position effect of their fills; `liquidation` when `kind` is `liquidation`."},"TriggerGrouping":{"type":"string","enum":["none","asset"],"description":"- `none`: standalone; removed only by cancel, TTL expiry or its own fire\n- `asset`: removed, with any resting order it produced, once the owner's position on the pair (perp) or base holding (spot) reaches zero\n"},"TriggerType":{"type":"string","enum":["take_profit","stop_loss"]},"ActivityFill":{"type":"object","description":"One fill of an order. `tb`, `tq`, `tf`, `f` and `st` are omitted on rows indexed before they\nwere recorded.\n","required":["k","id","book","b","q"],"properties":{"k":{"type":"string","enum":["fill"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"Order id."},"book":{"$ref":"#/components/schemas/Bytes32"},"b":{"$ref":"#/components/schemas/DecimalUint256","description":"Base filled by this fill."},"q":{"$ref":"#/components/schemas/DecimalUint256","description":"Quote filled by this fill."},"tb":{"$ref":"#/components/schemas/DecimalUint256","description":"Order's total base filled after this fill."},"tq":{"$ref":"#/components/schemas/DecimalUint256","description":"Order's total quote filled after this fill."},"tf":{"$ref":"#/components/schemas/DecimalUint256","description":"Order's total fee after this fill."},"f":{"$ref":"#/components/schemas/DecimalUint256","description":"Fee charged by this fill."},"st":{"type":"string","enum":["filled","canceled","margin_canceled","self_trade_canceled","expired","post_only_refused"],"description":"Terminal status, present only on the fill that closed the order."},"pa":{"$ref":"#/components/schemas/DecimalInt256","description":"The position after this fill on a perp book. Omitted when no position moved."}}},"DecimalUint256":{"type":"string","pattern":"^[0-9]+$","description":"Unsigned 256-bit integer, decimal string"},"ActivityModify":{"type":"object","description":"A resting order's price and/or size changed in place. Sizes are unsigned.","required":["k","id","book","px","sz","old_px","old_sz"],"properties":{"k":{"type":"string","enum":["modify"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"Order id."},"book":{"$ref":"#/components/schemas/Bytes32"},"px":{"$ref":"#/components/schemas/DecimalUint256"},"sz":{"$ref":"#/components/schemas/DecimalUint256"},"old_px":{"$ref":"#/components/schemas/DecimalUint256"},"old_sz":{"$ref":"#/components/schemas/DecimalUint256"}}},"ActivityTermination":{"type":"object","description":"An order left the book other than by filling.","required":["k","id","book","st"],"properties":{"k":{"type":"string","enum":["termination"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"Order id."},"book":{"$ref":"#/components/schemas/Bytes32"},"st":{"type":"string","enum":["canceled","margin_canceled","self_trade_canceled","expired","post_only_refused"]}}},"ActivityBackstop":{"type":"object","description":"A perp position swept to the backstop (`book` set), or the terminal cash sweep (`book` omitted).","required":["k","sz","cash","mark","eq","pnl"],"properties":{"k":{"type":"string","enum":["backstop"]},"book":{"$ref":"#/components/schemas/Bytes32"},"sz":{"$ref":"#/components/schemas/DecimalInt256","description":"Position size moved."},"cash":{"$ref":"#/components/schemas/DecimalInt256"},"mark":{"$ref":"#/components/schemas/DecimalUint256","description":"Mark price at the sweep."},"eq":{"$ref":"#/components/schemas/DecimalInt256","description":"Account equity at the sweep."},"pnl":{"$ref":"#/components/schemas/DecimalInt256","description":"Realized PnL; `\"0\"` on the cash sweep."}}},"ActivityBridgeTransfer":{"type":"object","description":"A bridge deposit (positive `amt`) or withdrawal (negative). `err` set means it was\nrefused and nothing moved.\n","required":["k","tx","idx","tok","amt"],"properties":{"k":{"type":"string","enum":["bridge_transfer"]},"tx":{"$ref":"#/components/schemas/Bytes32","description":"The bridge transaction."},"idx":{"type":"integer","description":"Position among the tick's deposits; `0` for a withdrawal."},"tok":{"$ref":"#/components/schemas/Address"},"amt":{"$ref":"#/components/schemas/DecimalInt256"},"err":{"type":"string"}}},"ActivityTransfer":{"type":"object","description":"An account-to-account transfer, signed from the account's side: debit negative, credit\npositive. A self-transfer is two entries, the debit first. A refused transfer is reported\nto the sender only, with `err`.\n","required":["k","id","cp","tok","amt"],"properties":{"k":{"type":"string","enum":["transfer"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"Transfer id."},"cp":{"$ref":"#/components/schemas/Address","description":"The other side of the transfer, the receiver when `amt` is negative and the sender otherwise; the account itself on a self-transfer."},"tok":{"$ref":"#/components/schemas/Address"},"amt":{"$ref":"#/components/schemas/DecimalInt256"},"err":{"type":"string"}}},"ActivityModifyReject":{"type":"object","description":"An amendment the engine refused; the order is untouched. `px` and `sz` are what was asked for, `sz` unsigned.","required":["k","id","book","px","sz","why"],"properties":{"k":{"type":"string","enum":["modify_reject"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"Order id."},"book":{"$ref":"#/components/schemas/Bytes32"},"px":{"$ref":"#/components/schemas/DecimalUint256"},"sz":{"$ref":"#/components/schemas/DecimalUint256"},"why":{"type":"string","description":"The engine's reason."}}},"ActivityCancelReject":{"type":"object","description":"A cancel the engine refused; the order still rests.","required":["k","id","book","why"],"properties":{"k":{"type":"string","enum":["cancel_reject"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"Order id."},"book":{"$ref":"#/components/schemas/Bytes32"},"why":{"type":"string","description":"The engine's reason."}}}}}}
```

## The ActivityEntry object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"ActivityEntry":{"description":"One activity entry, discriminated by `k`. Amounts and prices are 1e18-scaled decimal\nstrings. Optional fields are omitted rather than `null`; boolean flags are omitted when\nfalse. Ignore kinds and fields you do not recognise.\n","oneOf":[{"$ref":"#/components/schemas/ActivityOrder"},{"$ref":"#/components/schemas/ActivityFill"},{"$ref":"#/components/schemas/ActivityModify"},{"$ref":"#/components/schemas/ActivityTermination"},{"$ref":"#/components/schemas/ActivityBackstop"},{"$ref":"#/components/schemas/ActivityBridgeTransfer"},{"$ref":"#/components/schemas/ActivityTransfer"},{"$ref":"#/components/schemas/ActivityModifyReject"},{"$ref":"#/components/schemas/ActivityCancelReject"}],"discriminator":{"propertyName":"k","mapping":{"order":"#/components/schemas/ActivityOrder","fill":"#/components/schemas/ActivityFill","modify":"#/components/schemas/ActivityModify","termination":"#/components/schemas/ActivityTermination","backstop":"#/components/schemas/ActivityBackstop","bridge_transfer":"#/components/schemas/ActivityBridgeTransfer","transfer":"#/components/schemas/ActivityTransfer","modify_reject":"#/components/schemas/ActivityModifyReject","cancel_reject":"#/components/schemas/ActivityCancelReject"}}},"ActivityOrder":{"description":"The order as `/clob/orders/{account}` serves it, at the batch that admitted it, in its\ncurrent state. On the `pod_activity` channel it is the admission state instead:\n`active`, or `invalid` with `invalid_reason`, zero totals and `fills: []`. ADL closes\nappear as orders with `kind` `adl` or `adl_counterparty`; backstop sweeps appear only\nas `backstop` entries.\n","allOf":[{"type":"object","required":["k"],"properties":{"k":{"type":"string","enum":["order"]}}},{"$ref":"#/components/schemas/Order"}]},"Order":{"type":"object","description":"An order with its fills. Unsigned amounts and prices are 1e18-scaled `0x` hex,\nsigned ones decimal strings. Perp-only fields are omitted on spot orders.\n","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"market_type":{"$ref":"#/components/schemas/MarketType"},"kind":{"$ref":"#/components/schemas/OrderKind"},"order_id":{"$ref":"#/components/schemas/Bytes32"},"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"Creating transaction. Zero for engine-generated orders."},"bidder":{"$ref":"#/components/schemas/Address"},"nonce":{"type":"integer","format":"int64"},"order_type":{"type":"string","enum":["limit","market"]},"status":{"$ref":"#/components/schemas/OrderStatus"},"side":{"type":"string","enum":["buy","sell"]},"price":{"$ref":"#/components/schemas/HexUint256"},"initial_size":{"$ref":"#/components/schemas/DecimalInt256","description":"Signed; positive buy/long, negative sell/short."},"filled_base_amount":{"$ref":"#/components/schemas/HexUint256"},"filled_quote_amount":{"$ref":"#/components/schemas/HexUint256"},"fee":{"$ref":"#/components/schemas/HexUint256"},"deadline":{"$ref":"#/components/schemas/TimestampString","description":"The batch the order targets, microseconds, as a string."},"end":{"$ref":"#/components/schemas/Timestamp","description":"TTL expiry, microseconds. Orders that never expire carry `18446744073709551615`, which exceeds a JavaScript safe integer."},"included_batch":{"$ref":"#/components/schemas/Timestamp","description":"Deadline of the batch that first included the order. `0` for engine-generated orders and older rows."},"invalid_reason":{"type":"string","description":"Why the engine rejected the order. Only when `status` is `invalid`."},"effective_price":{"$ref":"#/components/schemas/HexUint256","description":"`filled_quote / filled_base` so far."},"fills":{"type":"array","items":{"$ref":"#/components/schemas/PartialFill"},"description":"Always present, oldest first."},"reduce_only":{"type":"boolean","description":"Perp only."},"ioc":{"type":"boolean","description":"Perp only."},"post_only":{"type":"boolean","description":"Omitted when false."},"direction":{"$ref":"#/components/schemas/OrderDirection"},"realized_pnl":{"$ref":"#/components/schemas/DecimalInt256","description":"Perp only, present once a fill closed exposure. Price drift minus funding across the slices it closed."},"grouping":{"$ref":"#/components/schemas/TriggerGrouping","description":"Inherited from the parent trigger. Omitted when `none`."},"trigger_type":{"$ref":"#/components/schemas/TriggerType","description":"Set only on orders a fired trigger produced (`kind` `triggered`)."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"MarketType":{"type":"string","enum":["spot","perpetual"]},"OrderKind":{"type":"string","enum":["user_signed","liquidation","triggered","adl","adl_counterparty","backstop_transfer"],"description":"- `user_signed`: submitted by the account\n- `liquidation`: generated by the engine when the account fell below maintenance margin\n- `triggered`: the order a fired TP/SL trigger produced\n- `adl`: auto-deleveraging close of this account's position\n- `adl_counterparty`: this account's side covering an auto-deleveraging close\n- `backstop_transfer`: a backstop sweep of this account's position, shown as a terminal order\n"},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"OrderStatus":{"type":"string","enum":["pending","active","filled","expired","canceled","margin_canceled","self_trade_canceled","post_only_refused","invalid"],"description":"- `pending`: submitted, not yet in the book\n- `active`: resting in the book\n- `filled`: completely filled\n- `expired`: TTL passed\n- `canceled`: canceled by the owner\n- `margin_canceled`: removed by the engine because the owner's margin was exhausted\n- `self_trade_canceled`: removed by the engine because it was about to fill against an order of the same owner\n- `post_only_refused`: a `post_only` order removed because it would have taken liquidity in the batch that admitted it\n- `invalid`: rejected at execution and never entered the book; see `invalid_reason`\n\nEverything except `pending` and `active` is terminal.\n"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"},"DecimalInt256":{"type":"string","pattern":"^-?[0-9]+$","description":"Signed 256-bit integer, decimal string"},"TimestampString":{"type":"string","pattern":"^[0-9]+$","description":"Unix time in microseconds, as a decimal string"},"Timestamp":{"type":"integer","format":"int64","description":"Unix time in microseconds, as a JSON number"},"PartialFill":{"type":"object","properties":{"base_amount":{"$ref":"#/components/schemas/HexUint256"},"quote_amount":{"$ref":"#/components/schemas/HexUint256"},"timestamp":{"$ref":"#/components/schemas/Timestamp"},"price":{"$ref":"#/components/schemas/HexUint256","description":"The batch's clearing price; the order's own price for ADL fills."}}},"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":"Spot orders use `buy`/`sell`. Perp orders use the position effect of their fills; `liquidation` when `kind` is `liquidation`."},"TriggerGrouping":{"type":"string","enum":["none","asset"],"description":"- `none`: standalone; removed only by cancel, TTL expiry or its own fire\n- `asset`: removed, with any resting order it produced, once the owner's position on the pair (perp) or base holding (spot) reaches zero\n"},"TriggerType":{"type":"string","enum":["take_profit","stop_loss"]},"ActivityFill":{"type":"object","description":"One fill of an order. `tb`, `tq`, `tf`, `f` and `st` are omitted on rows indexed before they\nwere recorded.\n","required":["k","id","book","b","q"],"properties":{"k":{"type":"string","enum":["fill"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"Order id."},"book":{"$ref":"#/components/schemas/Bytes32"},"b":{"$ref":"#/components/schemas/DecimalUint256","description":"Base filled by this fill."},"q":{"$ref":"#/components/schemas/DecimalUint256","description":"Quote filled by this fill."},"tb":{"$ref":"#/components/schemas/DecimalUint256","description":"Order's total base filled after this fill."},"tq":{"$ref":"#/components/schemas/DecimalUint256","description":"Order's total quote filled after this fill."},"tf":{"$ref":"#/components/schemas/DecimalUint256","description":"Order's total fee after this fill."},"f":{"$ref":"#/components/schemas/DecimalUint256","description":"Fee charged by this fill."},"st":{"type":"string","enum":["filled","canceled","margin_canceled","self_trade_canceled","expired","post_only_refused"],"description":"Terminal status, present only on the fill that closed the order."},"pa":{"$ref":"#/components/schemas/DecimalInt256","description":"The position after this fill on a perp book. Omitted when no position moved."}}},"DecimalUint256":{"type":"string","pattern":"^[0-9]+$","description":"Unsigned 256-bit integer, decimal string"},"ActivityModify":{"type":"object","description":"A resting order's price and/or size changed in place. Sizes are unsigned.","required":["k","id","book","px","sz","old_px","old_sz"],"properties":{"k":{"type":"string","enum":["modify"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"Order id."},"book":{"$ref":"#/components/schemas/Bytes32"},"px":{"$ref":"#/components/schemas/DecimalUint256"},"sz":{"$ref":"#/components/schemas/DecimalUint256"},"old_px":{"$ref":"#/components/schemas/DecimalUint256"},"old_sz":{"$ref":"#/components/schemas/DecimalUint256"}}},"ActivityTermination":{"type":"object","description":"An order left the book other than by filling.","required":["k","id","book","st"],"properties":{"k":{"type":"string","enum":["termination"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"Order id."},"book":{"$ref":"#/components/schemas/Bytes32"},"st":{"type":"string","enum":["canceled","margin_canceled","self_trade_canceled","expired","post_only_refused"]}}},"ActivityBackstop":{"type":"object","description":"A perp position swept to the backstop (`book` set), or the terminal cash sweep (`book` omitted).","required":["k","sz","cash","mark","eq","pnl"],"properties":{"k":{"type":"string","enum":["backstop"]},"book":{"$ref":"#/components/schemas/Bytes32"},"sz":{"$ref":"#/components/schemas/DecimalInt256","description":"Position size moved."},"cash":{"$ref":"#/components/schemas/DecimalInt256"},"mark":{"$ref":"#/components/schemas/DecimalUint256","description":"Mark price at the sweep."},"eq":{"$ref":"#/components/schemas/DecimalInt256","description":"Account equity at the sweep."},"pnl":{"$ref":"#/components/schemas/DecimalInt256","description":"Realized PnL; `\"0\"` on the cash sweep."}}},"ActivityBridgeTransfer":{"type":"object","description":"A bridge deposit (positive `amt`) or withdrawal (negative). `err` set means it was\nrefused and nothing moved.\n","required":["k","tx","idx","tok","amt"],"properties":{"k":{"type":"string","enum":["bridge_transfer"]},"tx":{"$ref":"#/components/schemas/Bytes32","description":"The bridge transaction."},"idx":{"type":"integer","description":"Position among the tick's deposits; `0` for a withdrawal."},"tok":{"$ref":"#/components/schemas/Address"},"amt":{"$ref":"#/components/schemas/DecimalInt256"},"err":{"type":"string"}}},"ActivityTransfer":{"type":"object","description":"An account-to-account transfer, signed from the account's side: debit negative, credit\npositive. A self-transfer is two entries, the debit first. A refused transfer is reported\nto the sender only, with `err`.\n","required":["k","id","cp","tok","amt"],"properties":{"k":{"type":"string","enum":["transfer"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"Transfer id."},"cp":{"$ref":"#/components/schemas/Address","description":"The other side of the transfer, the receiver when `amt` is negative and the sender otherwise; the account itself on a self-transfer."},"tok":{"$ref":"#/components/schemas/Address"},"amt":{"$ref":"#/components/schemas/DecimalInt256"},"err":{"type":"string"}}},"ActivityModifyReject":{"type":"object","description":"An amendment the engine refused; the order is untouched. `px` and `sz` are what was asked for, `sz` unsigned.","required":["k","id","book","px","sz","why"],"properties":{"k":{"type":"string","enum":["modify_reject"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"Order id."},"book":{"$ref":"#/components/schemas/Bytes32"},"px":{"$ref":"#/components/schemas/DecimalUint256"},"sz":{"$ref":"#/components/schemas/DecimalUint256"},"why":{"type":"string","description":"The engine's reason."}}},"ActivityCancelReject":{"type":"object","description":"A cancel the engine refused; the order still rests.","required":["k","id","book","why"],"properties":{"k":{"type":"string","enum":["cancel_reject"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"Order id."},"book":{"$ref":"#/components/schemas/Bytes32"},"why":{"type":"string","description":"The engine's reason."}}}}}}
```

## The ActivityOrder object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"ActivityOrder":{"description":"The order as `/clob/orders/{account}` serves it, at the batch that admitted it, in its\ncurrent state. On the `pod_activity` channel it is the admission state instead:\n`active`, or `invalid` with `invalid_reason`, zero totals and `fills: []`. ADL closes\nappear as orders with `kind` `adl` or `adl_counterparty`; backstop sweeps appear only\nas `backstop` entries.\n","allOf":[{"type":"object","required":["k"],"properties":{"k":{"type":"string","enum":["order"]}}},{"$ref":"#/components/schemas/Order"}]},"Order":{"type":"object","description":"An order with its fills. Unsigned amounts and prices are 1e18-scaled `0x` hex,\nsigned ones decimal strings. Perp-only fields are omitted on spot orders.\n","properties":{"orderbook_id":{"$ref":"#/components/schemas/Bytes32"},"market_type":{"$ref":"#/components/schemas/MarketType"},"kind":{"$ref":"#/components/schemas/OrderKind"},"order_id":{"$ref":"#/components/schemas/Bytes32"},"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"Creating transaction. Zero for engine-generated orders."},"bidder":{"$ref":"#/components/schemas/Address"},"nonce":{"type":"integer","format":"int64"},"order_type":{"type":"string","enum":["limit","market"]},"status":{"$ref":"#/components/schemas/OrderStatus"},"side":{"type":"string","enum":["buy","sell"]},"price":{"$ref":"#/components/schemas/HexUint256"},"initial_size":{"$ref":"#/components/schemas/DecimalInt256","description":"Signed; positive buy/long, negative sell/short."},"filled_base_amount":{"$ref":"#/components/schemas/HexUint256"},"filled_quote_amount":{"$ref":"#/components/schemas/HexUint256"},"fee":{"$ref":"#/components/schemas/HexUint256"},"deadline":{"$ref":"#/components/schemas/TimestampString","description":"The batch the order targets, microseconds, as a string."},"end":{"$ref":"#/components/schemas/Timestamp","description":"TTL expiry, microseconds. Orders that never expire carry `18446744073709551615`, which exceeds a JavaScript safe integer."},"included_batch":{"$ref":"#/components/schemas/Timestamp","description":"Deadline of the batch that first included the order. `0` for engine-generated orders and older rows."},"invalid_reason":{"type":"string","description":"Why the engine rejected the order. Only when `status` is `invalid`."},"effective_price":{"$ref":"#/components/schemas/HexUint256","description":"`filled_quote / filled_base` so far."},"fills":{"type":"array","items":{"$ref":"#/components/schemas/PartialFill"},"description":"Always present, oldest first."},"reduce_only":{"type":"boolean","description":"Perp only."},"ioc":{"type":"boolean","description":"Perp only."},"post_only":{"type":"boolean","description":"Omitted when false."},"direction":{"$ref":"#/components/schemas/OrderDirection"},"realized_pnl":{"$ref":"#/components/schemas/DecimalInt256","description":"Perp only, present once a fill closed exposure. Price drift minus funding across the slices it closed."},"grouping":{"$ref":"#/components/schemas/TriggerGrouping","description":"Inherited from the parent trigger. Omitted when `none`."},"trigger_type":{"$ref":"#/components/schemas/TriggerType","description":"Set only on orders a fired trigger produced (`kind` `triggered`)."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"MarketType":{"type":"string","enum":["spot","perpetual"]},"OrderKind":{"type":"string","enum":["user_signed","liquidation","triggered","adl","adl_counterparty","backstop_transfer"],"description":"- `user_signed`: submitted by the account\n- `liquidation`: generated by the engine when the account fell below maintenance margin\n- `triggered`: the order a fired TP/SL trigger produced\n- `adl`: auto-deleveraging close of this account's position\n- `adl_counterparty`: this account's side covering an auto-deleveraging close\n- `backstop_transfer`: a backstop sweep of this account's position, shown as a terminal order\n"},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"OrderStatus":{"type":"string","enum":["pending","active","filled","expired","canceled","margin_canceled","self_trade_canceled","post_only_refused","invalid"],"description":"- `pending`: submitted, not yet in the book\n- `active`: resting in the book\n- `filled`: completely filled\n- `expired`: TTL passed\n- `canceled`: canceled by the owner\n- `margin_canceled`: removed by the engine because the owner's margin was exhausted\n- `self_trade_canceled`: removed by the engine because it was about to fill against an order of the same owner\n- `post_only_refused`: a `post_only` order removed because it would have taken liquidity in the batch that admitted it\n- `invalid`: rejected at execution and never entered the book; see `invalid_reason`\n\nEverything except `pending` and `active` is terminal.\n"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"},"DecimalInt256":{"type":"string","pattern":"^-?[0-9]+$","description":"Signed 256-bit integer, decimal string"},"TimestampString":{"type":"string","pattern":"^[0-9]+$","description":"Unix time in microseconds, as a decimal string"},"Timestamp":{"type":"integer","format":"int64","description":"Unix time in microseconds, as a JSON number"},"PartialFill":{"type":"object","properties":{"base_amount":{"$ref":"#/components/schemas/HexUint256"},"quote_amount":{"$ref":"#/components/schemas/HexUint256"},"timestamp":{"$ref":"#/components/schemas/Timestamp"},"price":{"$ref":"#/components/schemas/HexUint256","description":"The batch's clearing price; the order's own price for ADL fills."}}},"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":"Spot orders use `buy`/`sell`. Perp orders use the position effect of their fills; `liquidation` when `kind` is `liquidation`."},"TriggerGrouping":{"type":"string","enum":["none","asset"],"description":"- `none`: standalone; removed only by cancel, TTL expiry or its own fire\n- `asset`: removed, with any resting order it produced, once the owner's position on the pair (perp) or base holding (spot) reaches zero\n"},"TriggerType":{"type":"string","enum":["take_profit","stop_loss"]}}}}
```

## The ActivityFill object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"ActivityFill":{"type":"object","description":"One fill of an order. `tb`, `tq`, `tf`, `f` and `st` are omitted on rows indexed before they\nwere recorded.\n","required":["k","id","book","b","q"],"properties":{"k":{"type":"string","enum":["fill"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"Order id."},"book":{"$ref":"#/components/schemas/Bytes32"},"b":{"$ref":"#/components/schemas/DecimalUint256","description":"Base filled by this fill."},"q":{"$ref":"#/components/schemas/DecimalUint256","description":"Quote filled by this fill."},"tb":{"$ref":"#/components/schemas/DecimalUint256","description":"Order's total base filled after this fill."},"tq":{"$ref":"#/components/schemas/DecimalUint256","description":"Order's total quote filled after this fill."},"tf":{"$ref":"#/components/schemas/DecimalUint256","description":"Order's total fee after this fill."},"f":{"$ref":"#/components/schemas/DecimalUint256","description":"Fee charged by this fill."},"st":{"type":"string","enum":["filled","canceled","margin_canceled","self_trade_canceled","expired","post_only_refused"],"description":"Terminal status, present only on the fill that closed the order."},"pa":{"$ref":"#/components/schemas/DecimalInt256","description":"The position after this fill on a perp book. Omitted when no position moved."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"DecimalUint256":{"type":"string","pattern":"^[0-9]+$","description":"Unsigned 256-bit integer, decimal string"},"DecimalInt256":{"type":"string","pattern":"^-?[0-9]+$","description":"Signed 256-bit integer, decimal string"}}}}
```

## The ActivityModify object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"ActivityModify":{"type":"object","description":"A resting order's price and/or size changed in place. Sizes are unsigned.","required":["k","id","book","px","sz","old_px","old_sz"],"properties":{"k":{"type":"string","enum":["modify"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"Order id."},"book":{"$ref":"#/components/schemas/Bytes32"},"px":{"$ref":"#/components/schemas/DecimalUint256"},"sz":{"$ref":"#/components/schemas/DecimalUint256"},"old_px":{"$ref":"#/components/schemas/DecimalUint256"},"old_sz":{"$ref":"#/components/schemas/DecimalUint256"}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"DecimalUint256":{"type":"string","pattern":"^[0-9]+$","description":"Unsigned 256-bit integer, decimal string"}}}}
```

## The ActivityTermination object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"ActivityTermination":{"type":"object","description":"An order left the book other than by filling.","required":["k","id","book","st"],"properties":{"k":{"type":"string","enum":["termination"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"Order id."},"book":{"$ref":"#/components/schemas/Bytes32"},"st":{"type":"string","enum":["canceled","margin_canceled","self_trade_canceled","expired","post_only_refused"]}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."}}}}
```

## The ActivityBackstop object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"ActivityBackstop":{"type":"object","description":"A perp position swept to the backstop (`book` set), or the terminal cash sweep (`book` omitted).","required":["k","sz","cash","mark","eq","pnl"],"properties":{"k":{"type":"string","enum":["backstop"]},"book":{"$ref":"#/components/schemas/Bytes32"},"sz":{"$ref":"#/components/schemas/DecimalInt256","description":"Position size moved."},"cash":{"$ref":"#/components/schemas/DecimalInt256"},"mark":{"$ref":"#/components/schemas/DecimalUint256","description":"Mark price at the sweep."},"eq":{"$ref":"#/components/schemas/DecimalInt256","description":"Account equity at the sweep."},"pnl":{"$ref":"#/components/schemas/DecimalInt256","description":"Realized PnL; `\"0\"` on the cash sweep."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"DecimalInt256":{"type":"string","pattern":"^-?[0-9]+$","description":"Signed 256-bit integer, decimal string"},"DecimalUint256":{"type":"string","pattern":"^[0-9]+$","description":"Unsigned 256-bit integer, decimal string"}}}}
```

## The ActivityBridgeTransfer object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"ActivityBridgeTransfer":{"type":"object","description":"A bridge deposit (positive `amt`) or withdrawal (negative). `err` set means it was\nrefused and nothing moved.\n","required":["k","tx","idx","tok","amt"],"properties":{"k":{"type":"string","enum":["bridge_transfer"]},"tx":{"$ref":"#/components/schemas/Bytes32","description":"The bridge transaction."},"idx":{"type":"integer","description":"Position among the tick's deposits; `0` for a withdrawal."},"tok":{"$ref":"#/components/schemas/Address"},"amt":{"$ref":"#/components/schemas/DecimalInt256"},"err":{"type":"string"}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"DecimalInt256":{"type":"string","pattern":"^-?[0-9]+$","description":"Signed 256-bit integer, decimal string"}}}}
```

## The ActivityTransfer object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"ActivityTransfer":{"type":"object","description":"An account-to-account transfer, signed from the account's side: debit negative, credit\npositive. A self-transfer is two entries, the debit first. A refused transfer is reported\nto the sender only, with `err`.\n","required":["k","id","cp","tok","amt"],"properties":{"k":{"type":"string","enum":["transfer"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"Transfer id."},"cp":{"$ref":"#/components/schemas/Address","description":"The other side of the transfer, the receiver when `amt` is negative and the sender otherwise; the account itself on a self-transfer."},"tok":{"$ref":"#/components/schemas/Address"},"amt":{"$ref":"#/components/schemas/DecimalInt256"},"err":{"type":"string"}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"DecimalInt256":{"type":"string","pattern":"^-?[0-9]+$","description":"Signed 256-bit integer, decimal string"}}}}
```

## The ActivityModifyReject object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"ActivityModifyReject":{"type":"object","description":"An amendment the engine refused; the order is untouched. `px` and `sz` are what was asked for, `sz` unsigned.","required":["k","id","book","px","sz","why"],"properties":{"k":{"type":"string","enum":["modify_reject"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"Order id."},"book":{"$ref":"#/components/schemas/Bytes32"},"px":{"$ref":"#/components/schemas/DecimalUint256"},"sz":{"$ref":"#/components/schemas/DecimalUint256"},"why":{"type":"string","description":"The engine's reason."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"DecimalUint256":{"type":"string","pattern":"^[0-9]+$","description":"Unsigned 256-bit integer, decimal string"}}}}
```

## The ActivityCancelReject object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"ActivityCancelReject":{"type":"object","description":"A cancel the engine refused; the order still rests.","required":["k","id","book","why"],"properties":{"k":{"type":"string","enum":["cancel_reject"]},"id":{"$ref":"#/components/schemas/Bytes32","description":"Order id."},"book":{"$ref":"#/components/schemas/Bytes32"},"why":{"type":"string","description":"The engine's reason."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."}}}}
```

## The ExplorerTransaction object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"ExplorerTransaction":{"type":"object","description":"Receipt fields merged with Ethereum JSON transaction fields (receipt wins on\noverlap; the receipt's `transactionHash` is dropped for the transaction's `hash`),\nplus `attestations`, `committee_epoch` and `decoded`. Block fields are absent or\n`null` while the transaction is served from the recent cache.\n","additionalProperties":true,"properties":{"hash":{"$ref":"#/components/schemas/Bytes32"},"from":{"$ref":"#/components/schemas/Address"},"to":{"$ref":"#/components/schemas/Address"},"nonce":{"type":"string","description":"`0x` hex"},"input":{"type":"string","description":"`0x` hex calldata"},"status":{"type":"string","description":"`0x1` success, `0x0` failure"},"blockNumber":{"type":"string","nullable":true},"blockHash":{"type":"string","nullable":true},"transactionIndex":{"type":"string","nullable":true},"logs":{"type":"array","items":{"type":"object"}},"attestations":{"type":"array","items":{"type":"object","properties":{"validator_address":{"$ref":"#/components/schemas/Address"},"sequence_number":{"type":"integer","format":"int64"},"batch_index":{"type":"integer"},"timestamp":{"$ref":"#/components/schemas/Timestamp"},"signature":{"type":"string"}}}},"committee_epoch":{"type":"integer","format":"int64"},"decoded":{"$ref":"#/components/schemas/DecodedCalldata"}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"Timestamp":{"type":"integer","format":"int64","description":"Unix time in microseconds, as a JSON number"},"DecodedCalldata":{"type":"object","description":"Calldata decoded against Pod's precompiles. For an unrecognized target or\nselector, `contract` is `null` and only `selector` and `raw` are set.\n","properties":{"contract":{"type":"string","nullable":true},"address":{"$ref":"#/components/schemas/Address"},"symbol":{"type":"string"},"function":{"type":"string"},"args":{"type":"object","additionalProperties":true},"order_id":{"$ref":"#/components/schemas/Bytes32","description":"Resting order id the call creates (`submitOrder`, `submitTrigger`)."},"sequence":{"type":"integer","description":"Position inside the parent `submitBatch`."},"intents":{"type":"array","description":"Decoded sub-intents of a `submitBatch`.","items":{"type":"object"}},"selector":{"type":"string","description":"4-byte selector, `0x` hex."},"raw":{"type":"string","description":"Raw calldata, `0x` hex."}}}}}}
```

## The DecodedCalldata object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"DecodedCalldata":{"type":"object","description":"Calldata decoded against Pod's precompiles. For an unrecognized target or\nselector, `contract` is `null` and only `selector` and `raw` are set.\n","properties":{"contract":{"type":"string","nullable":true},"address":{"$ref":"#/components/schemas/Address"},"symbol":{"type":"string"},"function":{"type":"string"},"args":{"type":"object","additionalProperties":true},"order_id":{"$ref":"#/components/schemas/Bytes32","description":"Resting order id the call creates (`submitOrder`, `submitTrigger`)."},"sequence":{"type":"integer","description":"Position inside the parent `submitBatch`."},"intents":{"type":"array","description":"Decoded sub-intents of a `submitBatch`.","items":{"type":"object"}},"selector":{"type":"string","description":"4-byte selector, `0x` hex."},"raw":{"type":"string","description":"Raw calldata, `0x` hex."}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."}}}}
```

## The BridgeConfig object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"BridgeConfig":{"type":"object","properties":{"claim_chain_id":{"type":"integer","format":"int64","description":"The one chain withdrawals are claimable on. `0` when no bridge is configured."},"source_contract":{"$ref":"#/components/schemas/Address","description":"Bridge contract on that chain. Zero address when no bridge is configured."},"version":{"type":"integer","format":"int64","description":"Bridge version; feeds the claim-hash domain separator."},"tokens":{"type":"array","description":"Every bridged token, ordered by `pod_token`. The only source of the Pod-token to bridged-chain-token mapping. Empty when no bridge is configured.","items":{"type":"object","properties":{"pod_token":{"$ref":"#/components/schemas/Address"},"l1_token":{"$ref":"#/components/schemas/Address"},"decimals":{"type":"integer","description":"Decimals on the bridged chain. A withdrawal amount must be a multiple of `10^(18 - decimals)` wei."},"min":{"$ref":"#/components/schemas/HexUint256","description":"Minimum withdrawal, bridged-chain decimals."},"max":{"$ref":"#/components/schemas/HexUint256","description":"Maximum withdrawal, bridged-chain decimals."}}}}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"}}}}
```

## The Withdrawal object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"Withdrawal":{"type":"object","description":"One withdrawal outcome, as `pod_withdrawals` delivers it.","required":["tx_hash","withdrawer","to","token","amount","timestamp_us"],"properties":{"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"The withdraw transaction's hash, the withdrawal's id."},"withdrawer":{"$ref":"#/components/schemas/Address","description":"The debited account; the master for a delegated withdrawal."},"to":{"$ref":"#/components/schemas/Address","description":"Recipient on the bridged chain."},"token":{"$ref":"#/components/schemas/Address","description":"Pod-side token."},"amount":{"$ref":"#/components/schemas/HexUint256","description":"Pod's 18 decimals, as signed. `claim` takes `proof.amount`."},"error":{"type":"string","enum":["insufficient_balance","not_included"],"description":"Why the withdrawal was refused. Omitted otherwise."},"timestamp_us":{"type":"integer","format":"int64","description":"The tick's batch deadline, microseconds. Also the `since` cursor."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"}}}}
```

## The WithdrawalDetail object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"WithdrawalDetail":{"type":"object","required":["withdrawal","status"],"properties":{"withdrawal":{"$ref":"#/components/schemas/Withdrawal"},"status":{"type":"string","enum":["claimable","pending","refused"],"description":"May gain values. Treat an unfamiliar one as `pending`."},"proof":{"$ref":"#/components/schemas/BridgeClaimProof"}}},"Withdrawal":{"type":"object","description":"One withdrawal outcome, as `pod_withdrawals` delivers it.","required":["tx_hash","withdrawer","to","token","amount","timestamp_us"],"properties":{"tx_hash":{"$ref":"#/components/schemas/Bytes32","description":"The withdraw transaction's hash, the withdrawal's id."},"withdrawer":{"$ref":"#/components/schemas/Address","description":"The debited account; the master for a delegated withdrawal."},"to":{"$ref":"#/components/schemas/Address","description":"Recipient on the bridged chain."},"token":{"$ref":"#/components/schemas/Address","description":"Pod-side token."},"amount":{"$ref":"#/components/schemas/HexUint256","description":"Pod's 18 decimals, as signed. `claim` takes `proof.amount`."},"error":{"type":"string","enum":["insufficient_balance","not_included"],"description":"Why the withdrawal was refused. Omitted otherwise."},"timestamp_us":{"type":"integer","format":"int64","description":"The tick's batch deadline, microseconds. Also the `since` cursor."}}},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"},"BridgeClaimProof":{"type":"object","description":"Present exactly when `status` is `claimable`. Everything `claim(token, amount, to,\nproof, auxTxSuffix)` needs, except `token`: map the Pod-side `token` here to\n`l1_token` from `/bridge/config`.\n","required":["proof","committee_epoch","aux_tx_suffix"],"properties":{"proof":{"type":"array","items":{"type":"integer","minimum":0,"maximum":255},"description":"Certificate (`0x00` then one 65-byte signature per signer, by ascending signer address) or, for a withdrawal from before a bridge version bump, a Merkle proof."},"committee_epoch":{"type":"integer","format":"int64","description":"Currently always `0`."},"aux_tx_suffix":{"type":"array","items":{"type":"integer","minimum":0,"maximum":255},"description":"The withdrawal's id (its tx hash) as bytes."},"token":{"$ref":"#/components/schemas/Address","description":"Pod-side token. Omitted on legacy rows."},"amount":{"$ref":"#/components/schemas/HexUint256","description":"In the token's bridged-chain decimals; pass straight to `claim`. Omitted on legacy rows."},"to":{"$ref":"#/components/schemas/Address","description":"Recipient on the bridged chain. Omitted on legacy rows."},"claim_hash":{"$ref":"#/components/schemas/Bytes32","description":"The key `Bridge.processedRequests` uses; check it to see whether the claim already landed."}}}}}}
```

## The BridgeClaimProof object

```json
{"openapi":"3.0.0","info":{"title":"REST API","version":"1.0.0"},"components":{"schemas":{"BridgeClaimProof":{"type":"object","description":"Present exactly when `status` is `claimable`. Everything `claim(token, amount, to,\nproof, auxTxSuffix)` needs, except `token`: map the Pod-side `token` here to\n`l1_token` from `/bridge/config`.\n","required":["proof","committee_epoch","aux_tx_suffix"],"properties":{"proof":{"type":"array","items":{"type":"integer","minimum":0,"maximum":255},"description":"Certificate (`0x00` then one 65-byte signature per signer, by ascending signer address) or, for a withdrawal from before a bridge version bump, a Merkle proof."},"committee_epoch":{"type":"integer","format":"int64","description":"Currently always `0`."},"aux_tx_suffix":{"type":"array","items":{"type":"integer","minimum":0,"maximum":255},"description":"The withdrawal's id (its tx hash) as bytes."},"token":{"$ref":"#/components/schemas/Address","description":"Pod-side token. Omitted on legacy rows."},"amount":{"$ref":"#/components/schemas/HexUint256","description":"In the token's bridged-chain decimals; pass straight to `claim`. Omitted on legacy rows."},"to":{"$ref":"#/components/schemas/Address","description":"Recipient on the bridged chain. Omitted on legacy rows."},"claim_hash":{"$ref":"#/components/schemas/Bytes32","description":"The key `Bridge.processedRequests` uses; check it to see whether the claim already landed."}}},"Address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"20-byte address, `0x` hex"},"HexUint256":{"type":"string","pattern":"^0x[a-fA-F0-9]+$","description":"Unsigned 256-bit integer, `0x` hex"},"Bytes32":{"type":"string","pattern":"^0x[a-fA-F0-9]{64}$","description":"32-byte value, `0x` hex. Orderbook ids, order ids and hashes."}}}}
```


# 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.                                                                                                 |
| `997`               | `Empty transaction required to make progress` | From `pod_sendRawTransaction`: the account's head nonce will not finalize on its own. `data` carries the nonce to unblock.                                                  |
| `-32002`            | `Chain has no block yet`                      | `eth_blockNumber` before the first block exists.                                                                                                                            |
| `-32025`            | `not available in your region`                | `eth_sendRawTransaction` / `pod_sendRawTransaction` from a geo-restricted source.                                                                                           |
| `-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, 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.            |

### `997` — empty transaction required

Returned by `pod_sendRawTransaction` when the account's head nonce has no certificate and will not finalize on its own. Submit a deadline-free empty self-transfer (`to` = your own address, value 0, no calldata) at `data.nonce`; once that finalizes (or the head becomes recoverable), resubmit.

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": 997,
    "message": "Empty transaction required to make progress",
    "data": {
      "nonce": 12,
      "errors": ["Account has pending transaction"]
    }
  }
}
```

| `data` field | Type      | Description                                                       |
| ------------ | --------- | ----------------------------------------------------------------- |
| `nonce`      | number    | The head nonce to submit the empty self-transfer at.              |
| `errors`     | string\[] | Any validator rejections observed while waiting for attestations. |

## 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.

On the delta channels (`pod_orderbook`, `pod_orders`, `pod_orders_v2`, `pod_candles`, `pod_withdrawals`, `pod_transfers`, `pod_activity`), `eth_subscribe` rejects a `since` older than the node's replay buffer, or any `since` while the buffer is empty, with `-32602` `since too old; backfill via REST then resubscribe`. Backfill the gap over [REST](/guides-references/references/rest), then resubscribe with a recent `since`.

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.         |
| `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), or a subscription `since` older than the replay buffer. |
| `-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` | Token bridging in and out of Pod — the only way value crosses the boundary |
| [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 an account's token balance 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,
    uint8 flags
  )`
];
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,
  0,        // flags: 0x01 REDUCE_ONLY (perp only) | 0x02 IOC | 0x04 POST_ONLY
);
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": "flags", "type": "uint8"}],
    "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
    0,                                           # flags: 0x01 REDUCE_ONLY | 0x02 IOC | 0x04 POST_ONLY
).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,
            uint8 flags
        ) 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
        0,                                        // flags: 0x01 REDUCE_ONLY | 0x02 IOC | 0x04 POST_ONLY
    ).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**, **moving funds between accounts**, **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 — `transfer` as much as orders, cancels, updates and triggers. All of them pass through the same validator check, so an unaligned transfer 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 %}

### Order flags

`submitOrder` carries an order's boolean properties in a single `uint8 flags` bitfield rather than one `bool` argument per property. OR together the bits you want; `0` is a plain resting limit order.

| Bit | Value  | Flag          | Meaning                                                                                                                          |
| --- | ------ | ------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| 0   | `0x01` | `REDUCE_ONLY` | The order may only reduce the submitter's existing position. Perp markets only.                                                  |
| 1   | `0x02` | `IOC`         | Immediate-or-cancel: whatever does not match in the order's batch is cancelled at the end of it instead of resting on the book.  |
| 2   | `0x04` | `POST_ONLY`   | Add-liquidity-only: the order rests, but may not trade in the batch that admitted it. See [Post-only orders](#post-only-orders). |

Combinations are checked when the intent is validated:

* `IOC | POST_ONLY` is **rejected** (`post-only order cannot be immediate-or-cancel`) — IOC demands a fill in the admitting batch, post-only forbids one.
* `POST_ONLY` on a `Market` order is **rejected** (`post-only is not valid for a market order`) — a market order has no resting price, so it has nothing to post at.
* `REDUCE_ONLY | POST_ONLY` is fine, as is any other combination.
* Market orders must set `IOC` (`market orders must be immediate-or-cancel`).

{% hint style="warning" %}
**Bits 3–7 must be zero.** Calldata carrying a flag bit the network does not recognise is rejected, not masked off — so an intent is never executed with a property silently dropped from it. Future order properties arrive as new bits here rather than as another overload.
{% endhint %}

{% hint style="info" %}
**`submitOrder` is overloaded, and only the `flags` form is current.** Encode against the exact signature — the selector differs per overload:

| Signature                                                             | Selector     | Status                                                                                                                          |
| --------------------------------------------------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------- |
| `submitOrder(bytes32,int256,uint256,uint8,uint128,uint128,uint8)`     | `0x1e416275` | **Current.** The `flags` form; the only one that can request post-only.                                                         |
| `submitOrder(bytes32,int256,uint256,uint8,uint128,uint128,bool,bool)` | `0x435f7e71` | Deprecated. The old `reduceOnly, ioc` pair, still accepted; equivalent to setting bit 0 from `reduceOnly` and bit 1 from `ioc`. |

The `flags` overload can only be decoded by nodes that ship it, so a client that must also work against a network running an older build can keep emitting the deprecated `bool, bool` form — it is accepted unchanged, and it simply cannot request post-only.

`submitTrigger` still takes `bool reduceOnly, bool ioc` and has no `flags` argument, so a trigger's synthetic order cannot be post-only.
{% endhint %}

### Post-only orders

A post-only order is guaranteed to **add** liquidity: it rests on the book and never takes from it on the way in. Set `POST_ONLY` (`0x04`) in `flags`.

Because pod matches in discrete batch auctions rather than on arrival, "would this order cross the book right now?" is the wrong question — every intent in a batch is matched together, so two orders that arrive in the same batch and match each other are *both* takers. The guarantee is therefore expressed against the batch:

> **A post-only order may not trade in the batch that admitted it.** From the next batch onwards it is an ordinary resting maker and matches normally.

What that means in practice:

* The order enters the book immediately and is reported `active`, like any other resting order.
* If it would have traded **in that first batch**, it is removed from the book instead. The removal is terminal and never partial — a refusal never leaves a post-only order half-filled — and it is reported with the terminal status `post_only_refused`, which is distinct from `canceled` so you can tell a refusal from a cancel you sent yourself.
* If it would **not** have traded in that batch, nothing happens to it: it rests, and can be matched from the next batch on.
* If another order at the same price with better queue priority absorbs the crossing liquidity first, your post-only order simply rests — it never had the opportunity to take, so there is nothing to refuse.
* Two post-only orders admitted in the same batch that cross only each other are **both** refused. Neither took resting liquidity, but each would have taken from the other.

**Amendments re-arm the guarantee.** An `update` that re-queues the order — a price change, or a size increase — makes it a newcomer again, so it may not trade for the rest of *that* batch and can be refused in it (for example, when you reprice it onto a crossing level). An update that only *decreases* the size keeps its queue priority and its original admission batch, so it goes on matching normally.

### Transfers between accounts

`transfer` moves `amount` of `token` from the signer's balance to another account's balance. Both sides are accounts on Pod, so the funds stay on the network and the recipient can trade them immediately.

The call is **global, not orderbook-bound**: it names no `orderbookId`, because the balance it moves is shared across every market. It works standalone and as a `submitBatch` sub-intent.

**What is checked before attestation.** The transaction is rejected outright — it never lands — when:

* `amount` is zero.
* `recipient` is the signer. It would burn a nonce and move nothing.
* `recipient` is the zero address. Burning has to be deliberate, not a typo.
* `recipient` is a system precompile.
* `deadline` is unaligned to the auction interval, or points at a batch that has already executed.

The sender's balance is deliberately **not** checked there: pending fills can raise it before the batch executes. It is checked against the withdrawable balance when the batch executes, and a transfer the balance does not cover is reported as a failed outcome rather than rejected as a transaction.

{% hint style="warning" %}
**`transfer` cannot be delegated.** It is refused as the inner call of a `delegated` wrapper, and refused again when it appears inside a `delegated(submitBatch([…]))`. Pinning the recipient to the master — what makes a delegated call safe elsewhere — would force a self-transfer here, which moves nothing, so the envelope is refused instead. Allowing it would make a leaked delegate key worth as much as a leaked master key for the whole spendable balance.
{% endhint %}

**Following a transfer.** Every transfer has an id derived exactly like an `order_id`, so you can compute it before you submit:

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

`sequence` is the intent's position inside a `submitBatch` envelope, `0` for a standalone `transfer`. A transfer has no receipt of its own — it settles inside the solver's `submitSolutions` transaction — so this channel is the only place its fate appears:

| Surface                                              | Use                                                                                                                                                                                                                                                        |
| ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `eth_subscribe("pod_transfers", { account, since })` | Live outcomes, one array per tick. `account` matches **either** side, so a recipient hears the credit as readily as a sender hears the debit. Each entry carries `transfer_id`, `from`, `to`, `token`, `amount` (18 decimals), `error` and `timestamp_us`. |

`error` is absent when the funds moved, and otherwise names why they did not:

* `insufficient_balance` — the sender's withdrawable balance did not cover it when the batch executed.
* `recipient_not_resident` — the recipient's account was not resident when the tick ran, so the credit had nowhere to land.
* `not_included` — the solver left the intent out of the solution its deadline pointed at.

All three mean **nothing moved on either side**. The nonce is spent either way, so retrying means a new transaction, which gets a new `transfer_id`.

### 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 on **this** precompile (`submitOrder`, `cancel`, `update`, `submitTrigger`, `transfer`, …) — 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 target) while its `order_id` keys on the delegate (the tx signer). Any deadline-bearing call can be wrapped — single intents or a whole `submitBatch` — but `submitSolutions`, the market-lifecycle calls (`createMarket`, `disableMarket`, `settleMarket`, `updateMarketOracle`), and nested `delegated` are rejected, and so is `transfer`, both directly and inside a wrapped `submitBatch` (see [Transfers between accounts](#transfers-between-accounts)). 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).

### Market lifecycle

Markets are created, halted, settled and re-pointed at their price feeds with four **admin-only** calls on this precompile. `createMarket` may be sent by any address on the network's market-admin allowlist and makes the signer the market's **owner**; the other three are accepted only from that owner. All four carry a `deadline` like every other intent, ride the solver's solutions, and are applied inside a batch, so every node moves the market through the same states at the same tick.

| Call                                                                | Effect                                                                                                                                                                                                                                                                                                                                                                          |
| ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `createMarket(params, deadline, liveAt)`                            | Mints a market from a self-describing `MarketParams`. The orderbook id is **assigned by the protocol** (a counter) and returned as `bytes32`; nothing lets the caller pick it. The market is born `pending` at `deadline` and goes `active` at the first batch at or after `liveAt` that has seen an oracle price (spot markets flip unconditionally).                          |
| `disableMarket(orderbookId, deadline, disableAt)`                   | Schedules a halt. `disableAt` must be tick-aligned and at least the network's minimum notice past `deadline`. Until it, the book trades normally so users can exit; from that tick the market is `disabled` and **every** intent on it is refused. Resting orders and positions stay where they are, and the oracle price of the halt tick is captured as the settlement price. |
| `settleMarket(orderbookId, deadline)`                               | Closes a `disabled` market: every resting order is refunded and every position closed at the captured settlement price. The market stays listed as `settled` for history. Disable to settle is one-way; a "revived" market is a new `createMarket`.                                                                                                                             |
| `updateMarketOracle(orderbookId, deadline, oracleSpec, midSources)` | Rebinds the feeds of an `active` or `pending` market without touching orders or positions. `oracleSpec` is the comma-separated `<source>/<asset>` list with the first entry primary; empty is legal only for spot. A perp created against a feed that never served a price stays `pending` until this call points it at one.                                                    |

`ob_getMarkets` reports every market with its lifecycle `status` (`pending`, `active`, `disabled`, `settled`) plus `live_at`, `disable_at` and `settlement_price` when they apply, so a client can hide a halted book or warn users during a notice window.

{% hint style="warning" %}
**Intents due after a scheduled halt are refused up front.** Once `disable_at` is set, any order, cancel or update on that book whose `deadline` lies past the halt is rejected at submission with `market disables at …: an intent with deadline … could never execute`. Bots that stamp long deadlines should shorten them, or drop the book, as soon as `disable_at` appears, and a `submitBatch` that spans several books fails as a whole when one sub-intent trips this rule.
{% endhint %}

The lifecycle calls cannot be wrapped in `delegated` or carried inside `submitBatch`, and they pay flat gas with no exemption.

### 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 ---

    // Bits of `submitOrder`'s `flags` argument. OR together the ones you want;
    // 0 is a plain resting limit order. Bits 3-7 are unassigned and MUST be
    // zero — a node rejects calldata carrying a flag bit it does not know
    // rather than ignoring it. New order properties become a new bit here.
    uint8 constant REDUCE_ONLY = 0x01; // perp markets only
    uint8 constant IOC         = 0x02;
    uint8 constant POST_ONLY   = 0x04;

    /**
     * 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 flags Bitfield of the order's properties — REDUCE_ONLY, IOC, POST_ONLY (see above).
     *        IOC | POST_ONLY is rejected, as is POST_ONLY on a Market order.
     */
    function submitOrder(
        bytes32 orderbookId,
        int256 size,
        uint256 price,
        OrderType orderType,
        uint128 deadline,
        uint128 ttl,
        uint8 flags
    ) public {}

    /**
     * @notice Deprecated: the pre-`flags` form of `submitOrder`, kept so calldata
     *         written against it still decodes. It cannot request POST_ONLY.
     *         Equivalent to the current form with bit 0 set from `reduceOnly`
     *         and bit 1 from `ioc`.
     */
    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 Moves tokens from the caller's balance to another account's
     *         balance. Both sides are accounts on Pod.
     * @dev Global rather than orderbook-bound: the balance it moves is shared
     *      across every market, so there is no `orderbookId`. Valid standalone
     *      and as a `submitBatch` sub-intent, but **never** under `delegated` —
     *      including inside a delegated `submitBatch`. Rejected before
     *      attestation when `amount` is zero, when `recipient` is the caller,
     *      the zero address or a system precompile, or when `deadline` is
     *      unaligned or already executed. The caller's balance is checked at
     *      execution instead, so an insufficient balance arrives as a
     *      `pod_transfers` outcome rather than as a rejected transaction. See
     *      "Transfers between accounts" above.
     * @param token The address of the token to move.
     * @param recipient The account to credit, on Pod.
     * @param amount The amount to move, in Pod's 18 decimals. Must be non-zero.
     * @param deadline The latest batch this intent may be included in, in microseconds. Must be a multiple of the market's `auction_interval`.
     */
    function transfer(
        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`, or
     *      `transfer`. 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 {}

    // --- Market lifecycle (admin-only; see "Market lifecycle" above) ---

    /**
     * @notice Full self-describing market definition for `createMarket`. The
     *         perp-only fields are ignored for `MarketType.Spot`.
     * @dev `oracleSpec` is the comma-separated `"<source>/<asset>"` list with the
     *      first entry primary; required for `Perp`, empty for `Spot`.
     *      `midSources` are external mid-price feeds and may be empty. Durations
     *      are microseconds; amounts and prices are 1e18-scaled.
     */
    struct MarketParams {
        address baseToken;
        address quoteToken;
        string baseSymbol;
        string quoteSymbol;
        string baseName;
        string quoteName;
        MarketType marketType;
        uint256 tickPrecision;
        uint256 lotSize;
        uint256 minNotional;
        uint256 maxPrice;
        uint256 maxPositionSize;
        string oracleSpec;
        string[] midSources;
        // -- perp-only --
        uint32 maxLeverage;
        int32 interestRate;
        uint32 maxFundingRate;
        uint32 maxPremium;
        uint32 markPriceClamp;
        uint64 fundingWindowMicros;
        uint64 emaWindowMicros;
        uint256 impactNotional;
    }

    /**
     * @notice Creates a market owned by the signer, who must be a market admin.
     * @dev The orderbook id is protocol-assigned and returned; it is never chosen
     *      by the caller. `deadline` is the inclusion batch (microseconds) that
     *      creates the market in `pending` status; `liveAt` (>= `deadline`,
     *      tick-aligned) is the batch from which it may go `active` — at the
     *      first executed batch at/after it that has seen an oracle price, or
     *      unconditionally for a spot market.
     */
    function createMarket(
        MarketParams calldata params,
        uint128 deadline,
        uint128 liveAt
    ) public returns (bytes32) {}

    /**
     * @notice Schedules a halt of `orderbookId`. Owner-only.
     * @dev `disableAt` must be tick-aligned and at least the network's minimum
     *      notice past `deadline`. The book trades normally until the halt; from
     *      that batch every intent on it is refused and the oracle price is
     *      captured as the settlement price.
     */
    function disableMarket(bytes32 orderbookId, uint128 deadline, uint128 disableAt) public {}

    /**
     * @notice Settles a `disabled` market: refunds every resting order and closes
     *         every position at the captured settlement price. Owner-only.
     */
    function settleMarket(bytes32 orderbookId, uint128 deadline) public {}

    /**
     * @notice Rebinds the oracle feeds of an `active` or `pending` market.
     *         Owner-only.
     * @dev `oracleSpec` is the comma-separated `"<source>/<asset>"` list, first
     *      entry primary; empty is legal only for a spot market, a perp must keep
     *      one. Orders, positions and the mark price are untouched.
     */
    function updateMarketOracle(
        bytes32 orderbookId,
        uint128 deadline,
        string calldata oracleSpec,
        string[] calldata midSources
    ) 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`, the market-lifecycle calls
     *        (`createMarket`, `disableMarket`, `settleMarket`,
     *        `updateMarketOracle`), and nested `delegated` are rejected; view
     *        functions cannot be wrapped.
     *      - `transfer` is rejected, both as `inner` and inside a wrapped
     *        `submitBatch`: a delegate must not be able to name the recipient.
     *      The inner intent is owned by `master` (balances, resting-order owner,
     *      cancel/update 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 {}
}
```


# Bridge

The **Bridge precompile** is how value crosses the boundary between Pod and the chain the network's bridge is configured for — the **bridged chain**. It owns both directions:

* **In** — a deposit made on the bridged chain's bridge contract is observed by validators and credited straight to the recipient's **balance**. There is no deposit call on Pod.
* **Out** — `withdraw` debits the caller's balance, burns it on Pod, and makes the same value claimable on the bridged chain.

The funds deposited to Pod via the bridge are directly usable by the orderbook.

{% hint style="info" %}
**Bridge precompile address:** `0x50d0000000000000000000000000000000000001`
{% endhint %}

For how the bridge works end-to-end, see [Native Bridge](https://github.com/podnetwork/pod-sdk/tree/main/doc/protocol/native-bridge.md). 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).

## Reading the bridge configuration

`withdraw` takes **no `chainId`**: exactly one chain is claimable, so there is nothing to name wrongly. That chain, the contract the claim is submitted to, and the per-token rules all come from `GET /v1/bridge/config` on any full node:

```json
{
  "claim_chain_id": 42161,
  "source_contract": "0x…",
  "version": 1,
  "tokens": [
    { "pod_token": "0x…", "l1_token": "0x…", "decimals": 6, "min": "0xf4240", "max": "0x…" }
  ]
}
```

`tokens` is the only source of the Pod-token → bridged-chain-token mapping, and `min`/`max` are in the token's **bridged-chain decimals**, compared against the converted amount rather than the 18-decimal one that is signed.

## Withdrawing

`withdraw` is a **solver-gated intent**, not an immediate transfer. It carries a `deadline` like an order, settles when that batch executes, and its result arrives as an outcome rather than as a receipt.

**What the parameters mean.**

| Parameter  | Meaning                                                                                                                                                                                                                                                                      |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `token`    | The **Pod-side** token address. Use `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE` for the native token. `l1_token` from `/v1/bridge/config` is the asset the claim actually pays out.                                                                                         |
| `to`       | An address on the **bridged chain**, not on Pod. Same 20 bytes, different chain — the address must be controlled by the intended recipient there, which matters most for a contract address.                                                                                 |
| `amount`   | Pod's 18 decimals, and it must be a **whole number of bridged-chain units**: `amount % 10^(18 - decimals) == 0`. Where a token is 6-decimal on the bridged chain, every withdrawal is a multiple of `1e12` wei. Nothing is rounded — an inexact amount is rejected outright. |
| `deadline` | The latest batch this intent may land in, in microseconds, aligned to the orderbook's `auction_interval` — the same rule every orderbook intent follows.                                                                                                                     |

{% hint style="warning" %}
**`tx.value` must be `0`, for the native token too.** The balance is debited internally; nothing rides along with the transaction. A withdraw carrying value is rejected.

Withdrawals are also **gas-exempt**, so an account whose entire balance arrived over the bridge can withdraw all of it without holding anything back for fees.
{% endhint %}

**A withdrawal is valid when** the token is bridged, `amount` converts to a whole number of bridged-chain units and falls inside that token's `[min, max]`, `tx.value` is zero, and `deadline` is aligned to the auction interval and has not already executed.

**It is rejected outright** — the transaction never lands — when any of those fails.

The balance is **not** part of that check. It is compared against the withdrawable balance when the batch executes, because pending fills can raise it in the meantime. A withdrawal the balance does not cover at that point is reported as a failed outcome rather than rejected as a transaction, and debits nothing.

**A withdrawal is always its own transaction.** It cannot be packed into an orderbook `submitBatch` and cannot be wrapped in `delegated`. Its identity is therefore the **withdraw transaction's hash**, which is what every outcome and lookup below is keyed by.

## Following a withdrawal

Outcomes are published once per batch:

| Surface                                                        | Use                                                                                                                     |
| -------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `eth_subscribe("pod_withdrawals", { account, since })`         | Live outcomes. Each carries `tx_hash`, `withdrawer`, `to`, `token`, `amount` (18 decimals), `error` and `timestamp_us`. |
| `GET /v1/bridge/withdrawals/{account}?since=&since_id=&limit=` | Backfill after a disconnect — identical shape, and `since` is the same cursor the subscription takes.                   |
| `GET /v1/bridge/withdrawals/by-id/{tx_hash}`                   | One withdrawal: its `status` (`claimable`, `pending` or `refused`) and, once assembled, the claim `proof`.              |
| `pod_getBridgeClaimProof(txHash)`                              | The claim proof on its own, by the same key.                                                                            |

`withdrawer` is the debited account, and it is what `account` filters on.

`error` names why a withdrawal was refused:

* `insufficient_balance` — the balance did not cover the amount when the batch executed.
* `not_included` — the solver left the intent out of the solution its deadline pointed at.

Both mean **nothing was debited**: the funds remain on the account, no claim exists and none ever will. The nonce is spent, so retrying means a new transaction with a new hash. This is the only place a failure reason appears, so a client watching only the bridged chain waits forever for an event that cannot come.

An absent `error` is the ordinary claimable case, but do not read it as a guarantee: a node whose bridge config does not cover the token records the row, signs nothing, and reports `refused` **without** a reason. Confirm against `status` and `proof` rather than treating absent-`error` as "on its way".

## Claiming

Once `n - f` validators have signed the withdrawal, `GET /v1/bridge/withdrawals/by-id/{tx_hash}` returns `status: "claimable"` and a `proof`. Two of its fields pass straight to the bridge contract's `claim` and one does not:

| Proof field              | Passing it to `claim`                                                                                                                                                                                          |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `amount`                 | Yes. Already in the token's **bridged-chain** decimals, not the 18-decimal value that was signed — take it from here rather than recomputing it.                                                               |
| `to`                     | Yes. Already a bridged-chain address.                                                                                                                                                                          |
| `token`                  | **No.** This is the **Pod-side** address, because a Pod RPC answers in Pod terms. `claim` names the bridged-chain asset, so map it through `l1_token` in `/v1/bridge/config`. Passing the Pod address reverts. |
| `proof`, `aux_tx_suffix` | Yes, but they serialize as **JSON arrays of byte values**, not `0x` strings. Convert before handing them to a web3 library's `bytes` parameter.                                                                |

`claim_hash` is also returned; the bridge contract keys `processedRequests` on it, so a caller can check whether a claim already landed before spending a transaction.

The bridge relayer submits that claim; the call is permissionless, so anyone can submit the same proof if the relayer is unavailable. `status: "pending"` means the certificate is still being assembled: ask again rather than treating it as a failure. See [Native Bridge](https://github.com/podnetwork/pod-sdk/tree/main/doc/protocol/native-bridge.md) for how the certificate is produced.

{% hint style="warning" %}
**Branch on `proof`, not on `status`.** The status vocabulary can grow, and a client holding burned funds must never let an unfamiliar value veto a valid certificate sitting in the same response. Claim whenever `proof` is present, treat `refused` as terminal, and treat anything else — `pending` included — as "ask again".
{% endhint %}

## Interface

```solidity
interface IPodBridge {
    /// @notice Emitted on Pod when a bridge-in deposit is applied. Mirrors the
    ///         bridged chain's `Bridge.Deposit` event so the two can be correlated;
    ///         the credit itself lands on the recipient's balance.
    event DepositApplied(
        uint256 indexed depositId,
        address indexed from,
        address indexed to,
        address token,
        uint256 amount,
        address callContract,
        uint256 reserveBalance,
        uint256 l1Block
    );

    /// @notice Withdraw from the caller's balance to the bridged chain.
    ///         The balance is debited when the batch executes and the same value
    ///         becomes claimable on the bridged chain; nothing is credited on Pod.
    /// @dev There is no `chainId` — exactly one chain is claimable, and the claim
    ///      hash commits to it. `tx.value` must be zero, for the native token too.
    ///      The withdrawal is identified by this transaction's own hash. Checked
    ///      before attestation against `GET /v1/bridge/config`; the balance is
    ///      checked at execution, so an insufficient balance arrives as a
    ///      `pod_withdrawals` outcome rather than as a rejected transaction.
    /// @param token Token address on Pod. Use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for the native token.
    /// @param to Recipient address on the bridged chain.
    /// @param amount Amount in Pod's 18 decimals; must be a whole number of bridged-chain units and within the token's `[min, max]`.
    /// @param deadline The latest batch this intent may be included in, in microseconds. Must be a multiple of the orderbook's `auction_interval`.
    function withdraw(
        address token,
        address to,
        uint256 amount,
        uint128 deadline
    ) external;

    /// @notice Applies bridge-in deposits observed on the bridged chain, crediting
    ///         each recipient's balance.
    /// @dev **Callable only by the configured bridge relayer** — users never send
    ///      this. Every field of every entry is checked by each validator against
    ///      its own view of the finalized bridged-chain `Bridge.Deposit` event before
    ///      it attests, and `depositId` is replay-protected. Listed here because
    ///      it is what puts funds on Pod, not because a client calls it.
    function processDeposits(
        uint128 deadline,
        DepositParams[] calldata deposits
    ) external;

    struct DepositParams {
        uint256 depositId;
        uint256 l1Block;
        address from;
        address to;
        address token;
        uint256 amount;
        address callContract;
        uint256 reserveBalance;
    }
}
```

{% hint style="info" %}
**`callContract` and `reserveBalance` no longer route anything.** They are carried through from the bridged-chain event and re-emitted on `DepositApplied` so the two sides still reconcile, but the deposit is credited whole to the recipient's balance either way. There is no longer a second balance to split it against.
{% endhint %}

## Decimal Scaling

All tokens on Pod carry 18 decimals, regardless of their decimals on the bridged chain (USDC is 6 there, 18 here). The bridge converts:

* **In** — the credited amount is scaled **up** to 18 decimals.
* **Out** — the `amount` passed to `withdraw` is already in Pod's 18 decimals; it is scaled **down** for the claim, which is why it must be a whole number of bridged-chain units.


# 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.


# 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**.

Trading Competition closed as of June 24, 2026. Follow [Pod Network](https://x.com/poddotnetwork) for the winners.

|                  |                                                       |
| ---------------- | ----------------------------------------------------- |
| **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 |


# Page


