Skip to main content

RateLimiter

Struct RateLimiter 

Source
pub struct RateLimiter { /* private fields */ }
Expand description

Holds all rate limiters for one API surface.

Created via factory methods like RateLimiter::clob_default() which configure hardcoded limits matching Polymarket’s documented rate limits.

Implementations§

Source§

impl RateLimiter

Source

pub fn begin_cooldown(&self, delay: Duration)

Hold every request on this limiter for delay.

Extends an existing cooldown but never shortens one: several concurrent requests typically see the same 429 within a few milliseconds of each other, and taking the most recent value would let whichever response carried the smallest delay release all of them early.

Prefer HttpClient::note_rate_limited, which derives the delay from the response. Reach for this directly only when driving the limiter from a transport this crate does not own.

Source

pub async fn acquire(&self, path: &str, method: Option<&Method>)

Await the appropriate limiter(s) for this endpoint.

Waits out any cooldown a previous 429 imposed, then awaits the default (general) limiter, then additionally awaits the first matching endpoint-specific limiter (burst + sustained).

Source

pub fn clob_default() -> Self

CLOB API rate limits.

Transcribed from https://docs.polymarket.com/api-reference/rate-limits as fetched on 2026-07-25, and pinned by the documented_limits tests.

Two things about the published tables need interpreting:

  • The ledger group cap (900/10s across /trades, /orders, /notifications and /order) is genuinely shared, so those entries hold clones of one shared bucket rather than four of their own.
  • That group names /order and /orders, which also appear in the trading table at 5,000 and 2,000 per 10s. Both tables can only hold simultaneously if the group cap governs the ledger reads; a 900/10s cap on all methods would make the published trading burst unreachable. The group is therefore scoped to GET.

Ordering matters wherever one pattern is a path-segment prefix of another: /balance-allowance/update must precede /balance-allowance, and the specific /data/* routes must precede the /data catch-all.

Source

pub fn gamma_default() -> Self

Gamma API rate limits.

  • General: 4,000/10s
  • /events: 500/10s
  • /markets: 300/10s
  • /public-search: 350/10s
  • /comments: 200/10s
  • /tags: 200/10s
  • /status (health): 100/10s

Upstream also lists a 900/10s cap shared by /markets + /events. It is not modelled because it can never bind: the per-endpoint caps of 300 and 500 sum to 800, which is already below it.

The published table spells the health row /ok, but that path answers 404 on gamma-api.polymarket.com — /status is the route that answers 200, and the one Gamma::health().ping() requests. /ok is boilerplate repeated into every surface’s table; only the CLOB host serves it.

Source

pub fn data_default() -> Self

Data API rate limits.

  • General: 1,000/10s
  • /trades: 200/10s
  • /positions and /closed-positions: 150/10s
  • / (health): 100/10s
  • Data API v2: measured per route, since upstream publishes no figures; see docs/specs/data-v2/OBSERVED.md

The published table spells the health row /ok, but that path answers 404 on data-api.polymarket.com — / answers 200 {"data":"OK"}, and is the route this crate requests. /ok is boilerplate repeated into every surface’s table; only the CLOB host serves it.

Matching / is safe despite entries being prefix-matched: the segment-boundary rule means strip_prefix("/") on /positions leaves positions, which starts with neither / nor ?, so the entry matches only the bare root and the root with a query string.

This limiter is shared with the two sibling hosts, so it also carries their rules:

  • /user-pnl: 200/10s, published as the host-wide allowance for user-pnl-api.polymarket.com. Modelled per-path because it is the only route polyoxide calls there and matching has no host dimension.
  • lb-api.polymarket.com (/volume, /profit) has no published limit, so those fall to the general bucket.
Source

pub fn relay_default() -> Self

Relay API rate limits.

  • 25 requests per 1 minute (single limiter, no endpoint-specific limits)
Source

pub fn perps_default() -> Self

Perps API rate limits.

Upstream publishes no figure for the public /v1/info/* routes, only that a per-IP token bucket exists. Each count is the highest clean ramp stage measured by polyoxide-perps/examples/info_soak.rs on 2026-09-30 and recorded in docs/specs/perps/OBSERVED.md; quota() reserves a tenth. The four routes throttle at different rates (a 429 on one arrived while the others kept being served), so each has its own row. The 17 routes that were not soaked share a /v1/info catch-all at the lowest measured rate, so an unmeasured route cannot be driven harder than any measured one. The general bucket is a client-wide cap measured separately: the budget is partly shared across routes, so a mixed run capped at the most permissive route’s 50 per 10 s was throttled (11 of 487 requests over 120 s) while the same run capped at PERPS_GENERAL was clean. See the validation runs in OBSERVED.md.

With the general bucket at 30, bbo’s own row never binds and the klines and portfolio rows coincide with the general bucket; only the trades row and the catch-all restrict further. The rows are kept at their measured values so a later change to the general bucket does not silently loosen a route.

Row order matters: prefix matching takes the first match, so the catch-all must come last.

Trait Implementations§

Source§

impl Clone for RateLimiter

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for RateLimiter

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more