Limits and quotas

jsonpad meters two things: how many requests you make in a calendar month, and how many bytes you have stored. Everything else on your plan is a guard rail against a runaway loop rather than something you should need to design around.

If you are writing a client or an agent that talks to jsonpad unattended, this is the page to read: the response headers below are what let it pace itself, and the degradation behaviour is what lets it keep working when it runs out. To check your limits and usage in a single request, call GET /tokens/self.

What counts as a request

Every API call authenticated with an API token counts as one request against your monthly allowance, regardless of method or response status.

Four things do not count:

  • Requests made by the jsonpad dashboard while you are signed in. Browsing your own data through the website is free.
  • Requests that fail with a 5xx status. If we break, you get the request back.
  • Requests made after your allowance and credits have run out, whether they are refused or served at the reduced rate. A request pack you buy later only pays for requests made after you buy it.
  • Requests refused by a rate limit. Backing off and retrying costs you nothing.

Realtime websocket messages are not metered either. Instead, each plan caps how many concurrent realtime connections a single account may hold open; a connection beyond that cap is refused at connection time, and is told how long to wait before trying again. See connection limits.

Outbound webhook deliveries are not metered either. Each plan caps how many webhooks an account can have (1 on Free, 5 on Indie, 20 on Pro and 50 on Scale).

A flow costs what the same API calls would: calling an endpoint flow, or an event flow running, is one request, and each item the flow reads or writes is one more. Runs you start in the dashboard, and test runs, are free. Each plan caps how many flows an account can have (2 on Free, 10 on Indie, 50 on Pro and 250 on Scale).

Response headers

Every metered response carries the headers below, alongside the per-minute headers described under rate limits. All of them can be read from JavaScript running in a browser as well as from a server.

  • x-quota-total25000The request allowance for the current month, excluding any overdraft and any prepaid credits.
  • x-quota-remaining18342How many requests are left before writes start being refused. This includes your plan's overdraft and any prepaid credits you hold, so it can be larger than x-quota-total.
  • x-quota-credits0How many prepaid requests you currently hold. These never expire and are only drawn down once the monthly allowance and overdraft are gone.
  • x-quota-reset2026-10-01T00:00:00.000ZAn ISO 8601 timestamp for when the allowance next resets.
  • x-quota-degradedtrueOnly present on a read served at the free tier's rate limit because your allowance and credits have run out. See below.

What happens when you run out

We email you once, when you cross 80% of your allowance. There is no second email at 90%.

At 100%, in order:

  1. On a paid plan you enter a 10% overdraft, and nothing changes. The free plan has no overdraft.
  2. Past the overdraft, any prepaid request credits you hold are drawn down. Again, nothing changes until they run out.
  3. Once those are gone, GET, HEAD and OPTIONS requests keep working, but at the free tier's rate limit. Every other method returns
    429 Too Many Requests
    with the error code QUOTA_EXCEEDED and a retry-after header.

In other words, your application degrades to read-only rather than going dark. Whatever you have already stored stays readable.

{
name: "QUOTA_EXCEEDED"
code: 10013
message: "Monthly request quota exceeded. Your allowance resets at 2026-10-01T00:00:00.000Z. Read requests st..."
}

Buying a prepaid request pack takes effect immediately and does not change your plan.

When the allowance resets

At 00:00 UTC on the first of each calendar month, not on your billing anniversary. Free accounts have no anniversary, and a fixed reset date means an upgrade never has to prorate your allowance.

Prepaid credits carry over. Unused monthly allowance does not.

Storage

Each plan has a total storage allowance covering the JSON data of every item in every one of your lists. Stored bytes are recalculated once a day rather than on every write, so the figure you see on your dashboard can be up to a day behind.

If you are over the allowance, reads keep working and writes return

403 Forbidden
with the error code STORAGE_LIMIT_EXCEEDED until you delete some data or move up a plan. Nothing is ever deleted for you.

Rate limits

Separately from the monthly allowance, each plan limits how fast you can make requests: a maximum number of requests per minute, and a minimum gap between consecutive requests. Exceeding either returns

429 Too Many Requests
with the error code RATE_LIMIT_EXCEEDED and a retry-after header telling you how many seconds to wait. A refused request does not count against your monthly allowance.

Every response to a request made with an API token, including a refused one, carries two headers describing the per-minute limit:

  • x-rate-limit-total60How many requests your plan allows per minute.
  • x-rate-limit-remaining42How many more requests you can make after this one before reaching that limit. The minute is a rolling window over the last 60 seconds.

Rate limits exist to stop one account degrading the service for everyone. They are not something you should have to plan around: if you are hitting them during normal operation, add a short delay between requests rather than retrying immediately.

Version history

Each plan retains a number of versions per item. Older versions remain in the event log — we never delete event history — but they can no longer be fetched back through the version query parameter, and requesting one returns

410 Gone
with the error code ITEM_VERSION_NOT_RETAINED.

Write rules

Write rules have to finish, quickly, on every write, so the language has no loops and no recursion and evaluation has a budget. These limits are the same on every plan, including free:

  • rule text64 KiBChecked when the rules are saved.
  • statements200allow and require statements in one rule set.
  • expressions5,000Across the whole rule set, counting each call to one of your own functions as the size of its body.
  • nesting depth64Brackets and unary operators, with a separate cap of 500 on the height of an expression — every operator in a chain like a && b && c is one level.
  • function parameters8Per declared function.
  • evaluation budget100,000 unitsPer write. Roughly one unit per expression evaluated, and more for work over large values: comparing, diffing, hashing and string handling all cost by size. Running out refuses the write with WRITE_RULE_DENIED. Ordinary rules use a tiny fraction of it, and the dashboard's playground shows you how much.
  • lookups10 itemsDifferent items one write's rules can read with lookup() and exists(). Reading the same item again doesn't count twice. A lookup past the limit is an error, so the statement making it isn't true. Each item read counts as a request.
  • value depth256How deeply nested a value can be when it's compared, diffed or hashed.
  • rule tests200 / 256 KiBStored per list, as a count and as a size.

Refused writes are counted in your list's stats, and the last 50 per list are kept so you can see what was refused and why.

What is not limited

Lists, items per list and indexes per list are uncapped on every plan, including free. In practice what you can store is bounded by the storage allowance rather than by a count.

Every feature is available on every plan too: JSON schema validation, version history, JSON Patch, JSON Pointer, JSON Path, realtime updates and identities. You never need to move up a plan to unlock a capability — only to get more volume.

The current numbers for each plan are on the pricing page.