Skip to main content
Both Minerva and AsyncMinerva self-throttle to whatever your plan allows. You don’t have to write a token bucket, a semaphore, or back-off logic.

How it works

On the first call (sync or async), the SDK GETs /v2/usage/limits to discover your per-second rate, burst, and daily quota. The response is cached in-process and used to build a shared token bucket:
{
  "rps_limit": 100,
  "burst_limit": 150,
  "daily_quota": null,
  "daily_quota_used": null,
  "reset_at_utc": null
}
(Any field set to null is treated as “no limit on this axis.”) Subsequent calls — including concurrent ones under one client — pass through the bucket. When the bucket is empty, the call waits the minimal time needed to acquire a token.

When it helps

Most when you fan out concurrent requests:
async with AsyncMinerva() as mc:
    # 100 concurrent enriches; the SDK self-throttles to your plan's rps_limit.
    results = await asyncio.gather(*[
        mc.api.enrich(batch) for batch in batches
    ])
…or use the built-in enrich_many / resolve_many which already share the same client + bucket.

Inspecting the active policy

async with AsyncMinerva() as mc:
    limits = await mc.ensure_limits()
    print(f"{limits.rps_limit=} {limits.burst_limit=} {limits.daily_quota=}")
Or for the sync client:
mc = Minerva()
limits = mc.ensure_limits()

Opting out

mc = Minerva(rate_limit=False)
async_mc = AsyncMinerva(rate_limit=False)
Useful when:
  • You’ve already built your own throttler at the application layer.
  • You’re running tests against a recorded response.
  • You want to deliberately push toward 429 to learn your ceiling.

Older servers / endpoint not deployed

If /v2/usage/limits returns 404 (or any error), the SDK silently falls back to “no throttle” and continues normally. Your calls won’t fail because the limits probe didn’t work.