Skip to content

About usage quotas

You are viewing in-progress documentation for v2 (Beta). Switch to the stable version for the current production release.

A quota is a ceiling the API places on how much of a shared service one owner can consume at once. FastFuels is a hosted service backed by finite compute and storage, so every account has limits on how many jobs it can run concurrently, how many resources it can own, how many bytes those resources store, how many jobs it can start each week, and how long resources are kept. When a create request would push you past one of those ceilings, the API refuses it with a structured 429 QUOTA_EXCEEDED response instead of accepting work it cannot fairly serve.

This page is about the idea of quotas: which dimensions are limited, why each one exists, how your specific limits are decided, and how to see and interpret them. It is not the field-by-field reference for the 429 body — that lives in the OpenAPI schema (QuotaExceededDetail) — and it is not a step-by-step recipe. It assumes the resource and job model: that every resource is created under an owner, and that grids, inventories, features, point clouds, and exports run as asynchronous jobs that move pending → running → completed (or failed).

Three concerns motivate every limit below, and it helps to keep them in mind because they explain why a particular dimension is bounded the way it is:

  • Fair use. The API’s workers are a shared pool. Without a cap on concurrent jobs, one owner submitting hundreds of grids at once would starve everyone else. Limiting active work keeps the queue responsive for all.
  • Cost control. Building and storing a fine-resolution fuelbed costs real compute and disk. Bounding how much any one account can accumulate keeps the service’s cost predictable and sustainable.
  • Abuse prevention. Counts, storage, and retention limits, together with the ability to throttle a misbehaving account to zero, contain runaway or malicious usage before it degrades the platform.

Quotas are attached to an owner, not to an API key. An owner is the account a resource belongs to — a personal user or an application. If you mint several API keys, they all draw on the same quota bucket, because they all create resources under the same owner. This is why the answer to “what are my limits?” depends on who you are, not which key you used, and why the endpoints that report your limits (below) resolve “me” to the authenticated owner.

Quotas limit five independent things. The first four are checked at create time — the moment you POST a new resource — and evaluated in the order below; the first ceiling you are at is the one that rejects the request. The fifth, retention, is enforced continuously in the background.

The number of jobs of a given resource type that are in progress (pending or running) at the same time. This is the tightest, most dynamic limit, and it clears on its own: as your jobs finish, your active count falls and capacity frees up. Because waiting resolves it, a 429 on an active-job limit carries a Retry-After header telling you how long to back off before retrying. You can also clear headroom immediately by deleting a still-running job you no longer need.

Active-job limits apply to the resource types that do work — grids, exports, inventories, features, and point clouds. Completed and failed jobs never count against this limit; only in-flight ones do.

How many resources of each type you may own in total, regardless of their state. Unlike active jobs, a completed resource keeps counting — it occupies a slot until you delete it or it expires. Every resource type has a count limit, including domains, which have no jobs and no stored artifacts of their own. A 429 on a count limit does not carry Retry-After, because waiting won’t help: you resolve it by deleting resources you no longer need, or by requesting a higher limit.

The total bytes of stored artifacts summed across all resources of a type — the GeoTIFFs, netCDFs, and packaged exports the jobs produce. A resource that is small in count can still be large on disk, so storage is metered separately from counts. Like counts, a storage 429 has no Retry-After; you free space by deleting resources or request a higher limit. Storage limits apply to the artifact-producing types (grids, exports, inventories, features, point clouds); domains store nothing of their own.

How many jobs you may start per week, per resource type. Active jobs bound how much work runs at once; the weekly budget bounds how much you start over time. Processing costs compute whether or not you keep the result, so the budget counts every job the API runs on your behalf — creating a resource, modifying it in place, applying a treatment, duplicating it, or processing an upload — and deleting resources does not give budget back.

The budget resets at the start of each ISO week — Monday 00:00 UTC — rather than on a rolling clock, so your full allowance is always available at the start of a week. Like the active-job limit, it clears on its own; unlike the others, nothing you do mid-week can raise it back up. Every response to a request that started a job carries the standard RateLimit and RateLimit-Policy headers reporting how many jobs remain in your budget and how many seconds until it resets, so a client can watch its headroom without any extra calls.

Not every dimension applies to every resource type. The table below is the map — it is the shape of the model, not a promise about specific numbers (for those, see your live limits):

Resource typeActive jobsTotal countStorageWeekly budget
Grids
Exports
Inventories
Features
Point clouds
Domains

Resources do not live forever. Each one has a time-to-live measured from its last modification; once a resource has been untouched for longer than its TTL, a background reclamation process deletes it and frees the storage and count it held. Retention is what keeps abandoned work from accumulating indefinitely, and it is why the count and storage dimensions tend to self-heal over time even if you never delete anything by hand.

The lifetime depends on the resource’s state and your tier:

  • Standard resources are retained for a fixed window (on the order of months) from their last modification.
  • Failed resources are kept on a much shorter clock — a failed job is reclaimed sooner, since it holds a slot without producing a usable artifact.
  • Application-tier resources never expire; they are kept until explicitly deleted.

Domains are the exception to reclamation: because a domain stores no artifact of its own, it is not swept on the TTL clock the way its child resources are.

Your limits are resolved in layers. A named tier sets a baseline, and per-owner overrides adjust individual limits on top of it. Two tiers cover almost everyone:

  • standard — the default every account starts on. Its limits suit interactive and moderate programmatic use.
  • application — for higher-throughput, programmatic workloads. It raises the concurrency, count, storage, and weekly-budget ceilings and, notably, lets resources persist indefinitely rather than expiring on the standard retention clock.

On top of whichever tier applies, an owner can carry overrides — individual limits raised (or otherwise adjusted) for that account specifically. This is the mechanism behind “we can give you a higher limit”: support raises the relevant field for your owner, and the new value takes effect the next time your limits resolve. Overrides win over the tier baseline, which wins over the built-in defaults.

Because tiers and overrides mean your effective numbers can differ from anyone else’s — and can change over time — you should never hard-code specific limit values into client code. Read them from the API instead.

Two endpoints report your live numbers. They are the canonical answer to “what are my limits, and how close am I?” — always prefer them over any number quoted in prose, including on this page.

GET /users/me returns your identity, your tier, and your fully-resolved limits (defaults + tier + overrides, already merged):

Terminal window
curl 'https://api-v2-prod-nyvjyh5ywa-uw.a.run.app/users/me' \
-H 'api-key: my-api-key'
// GET /users/me — illustrative shape; the numbers below are example
// standard-tier defaults and can change. Your account's live values —
// tier, overrides, everything — are whatever THIS call returns.
{
"id": "owner-abc123", // your owner id
"kind": "user", // "user" or "application"
"tier": "standard",
"quotas": {
// Active jobs — concurrent pending/running jobs per type
"max_active_grids": 25,
"max_active_exports": 10,
"max_active_inventories": 10,
"max_active_features": 10,
"max_active_pointclouds": 5,
// Total counts — how many of each type you may own
"max_domains": 50,
"max_grids": 1000,
"max_exports": 500,
"max_inventories": 500,
"max_features": 500,
"max_pointclouds": 50,
"max_api_keys": 50,
// Storage — summed artifact bytes per type
"max_grid_storage_bytes": 53687091200, // 50 GiB
"max_export_storage_bytes": 26843545600, // 25 GiB
"max_inventory_storage_bytes": 10737418240, // 10 GiB
"max_feature_storage_bytes": 1073741824, // 1 GiB
"max_pointcloud_storage_bytes": 53687091200,// 50 GiB
// Weekly budget — jobs started per ISO week, per type
"max_weekly_grid_dispatches": 500,
"max_weekly_export_dispatches": 250,
"max_weekly_inventory_dispatches": 250,
"max_weekly_feature_dispatches": 250,
"max_weekly_pointcloud_dispatches": 50,
// Retention — days; null means "never expires"
"resource_ttl_days": 180,
"failed_resource_ttl_days": 14
}
}

GET /users/me/usage returns the same limits paired with your current usage, so you can see how much headroom is left before any ceiling — plus a lifecycle block echoing your retention TTLs:

Terminal window
curl 'https://api-v2-prod-nyvjyh5ywa-uw.a.run.app/users/me/usage' \
-H 'api-key: my-api-key'
// GET /users/me/usage — illustrative shape. Each entry pairs current
// "usage" with the "limit" it counts against.
{
"grids": {
"active": { "usage": 3, "limit": 25 }, // in-flight jobs
"total": { "usage": 214, "limit": 1000 }, // resources owned
"storage": { "usage_bytes": 8123400000, "limit_bytes": 53687091200 }
},
"exports": { "active": { "usage": 0, "limit": 10 }, "total": { "usage": 5, "limit": 500 }, "storage": { "usage_bytes": 402653184, "limit_bytes": 26843545600 } },
"inventories": { "active": { "usage": 1, "limit": 10 }, "total": { "usage": 40, "limit": 500 }, "storage": { "usage_bytes": 1073741824, "limit_bytes": 10737418240 } },
"features": { "active": { "usage": 0, "limit": 10 }, "total": { "usage": 8, "limit": 500 }, "storage": { "usage_bytes": 160972, "limit_bytes": 1073741824 } },
"pointclouds": { "active": { "usage": 0, "limit": 5 }, "total": { "usage": 0, "limit": 50 }, "storage": { "usage_bytes": 0, "limit_bytes": 53687091200 } },
// Count-only types: no jobs, no storage of their own
"domains": { "total": { "usage": 12, "limit": 50 } },
"api_keys": { "total": { "usage": 2, "limit": 50 } },
"lifecycle": {
"resource_ttl_days": 180,
"failed_resource_ttl_days": 14,
"next_expiry_on": null
}
}

Reading the usage response is the practical way to answer questions like “can I kick off ten more grids right now?” (compare grids.active.usage to its limit) or “am I running low on inventory storage?” (compare inventories.storage.usage_bytes to limit_bytes). It is also the honest way to plan around a limit before a create fails, rather than discovering the ceiling by hitting it.

A create request that would exceed a quota is rejected with HTTP 429 and a structured JSON body. The body is diagnostic by design: it tells you exactly which ceiling you hit, where you stand against it, and what to do. The fields under detail are the QuotaExceededDetail model from the OpenAPI reference:

// HTTP 429 Too Many Requests
// Retry-After: 60 ← present only for active-job limits
{
"detail": {
"reason": "QUOTA_EXCEEDED", // machine-readable; switch on this
"quota": "max_active_grids", // the exact limit field you hit
"current": 25, // your usage for that quota
"limit": 25, // the ceiling you reached
"message": "You have 25 grid jobs in progress (limit 25). Wait for jobs to complete or delete unneeded grids, then retry. To request a higher limit, contact support.fastfuels@silvxlabs.com."
}
}
  • reason is always "QUOTA_EXCEEDED" for a quota rejection — the stable string a client should branch on, rather than parsing the human message.
  • quota names the exact limit field (e.g. max_active_grids, max_grids, max_grid_storage_bytes, max_weekly_grid_dispatches), so you can tell which kind of ceiling rejected you programmatically.
  • current and limit are integers in the quota’s own units — a count for count limits, bytes for storage limits (the message also states storage in GiB for readability).

How you resolve a 429 depends on which dimension it names:

  • Active-job limit (max_active_*) — the response includes Retry-After (seconds). Wait for in-flight jobs to finish, then retry; the limit clears itself as they complete. Deleting a running job you no longer need frees a slot immediately.
  • Count limit (max_domains, max_grids, …) — no Retry-After; waiting won’t help. Delete resources you no longer need to free slots.
  • Storage limit (max_*_storage_bytes) — no Retry-After. Delete resources to free bytes. (Reclamation via retention will also free space over time as idle resources expire.)
  • Weekly budget (max_weekly_*_dispatches) — no Retry-After, and deleting resources won’t help: spent budget is not refunded. The detail carries an extra window_reset_on field — the exact UTC timestamp when your budget resets — and the response carries the RateLimit headers with r=0 and the seconds remaining until that reset. Wait for the reset, or request a higher limit.

In every case, if your workload genuinely needs more than your current ceiling, the durable fix is a higher limit: contact support.fastfuels@silvxlabs.com (the address the message points to) to have your tier or a specific override raised.

  • Introduction to the FastFuels API — the resource model, API-key authentication, and the asynchronous job lifecycle that the active-job quota is built on.
  • Create a domain — the first resource you create under your owner, and the entry point where a quota can first apply.
  • The OpenAPI reference — the field-by-field schema for QuotaExceededDetail, GET /users/me, and GET /users/me/usage, of which this page is the conceptual companion.