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).
Why quotas exist
Section titled “Why quotas exist”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.
Limits resolve per owner
Section titled “Limits resolve per owner”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.
The five dimensions
Section titled “The five dimensions”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.
Active jobs
Section titled “Active jobs”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.
Total counts
Section titled “Total counts”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.
Storage
Section titled “Storage”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.
Weekly job budget
Section titled “Weekly job budget”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.
Where the dimensions apply
Section titled “Where the dimensions apply”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 type | Active jobs | Total count | Storage | Weekly budget |
|---|---|---|---|---|
| Grids | ✓ | ✓ | ✓ | ✓ |
| Exports | ✓ | ✓ | ✓ | ✓ |
| Inventories | ✓ | ✓ | ✓ | ✓ |
| Features | ✓ | ✓ | ✓ | ✓ |
| Point clouds | ✓ | ✓ | ✓ | ✓ |
| Domains | — | ✓ | — | — |
Retention (lifecycle)
Section titled “Retention (lifecycle)”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.
Tiers and overrides
Section titled “Tiers and overrides”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.
See your own limits and usage
Section titled “See your own limits and usage”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):
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:
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.
When you hit a limit
Section titled “When you hit a limit”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." }}reasonis always"QUOTA_EXCEEDED"for a quota rejection — the stable string a client should branch on, rather than parsing the humanmessage.quotanames 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.currentandlimitare integers in the quota’s own units — a count for count limits, bytes for storage limits (themessagealso states storage in GiB for readability).
How you resolve a 429 depends on which dimension it names:
- Active-job limit (
max_active_*) — the response includesRetry-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, …) — noRetry-After; waiting won’t help. Delete resources you no longer need to free slots. - Storage limit (
max_*_storage_bytes) — noRetry-After. Delete resources to free bytes. (Reclamation via retention will also free space over time as idle resources expire.) - Weekly budget (
max_weekly_*_dispatches) — noRetry-After, and deleting resources won’t help: spent budget is not refunded. The detail carries an extrawindow_reset_onfield — the exact UTC timestamp when your budget resets — and the response carries theRateLimitheaders withr=0and 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.
Where to go next
Section titled “Where to go next”- 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, andGET /users/me/usage, of which this page is the conceptual companion.