Rate Limits

Terra applies rate limits on data-read endpoints (e.g /activity) to protect the platform from runaway loops and to keep response times consistent for everyone.

The limits operate per (user_id) — meaning each user you've connected has their own budget, separate from your other users.

The rules

There are two rules. A request must satisfy both to be accepted.

Rule
Limit
Window

Per-request window size

1,825 days (5 years)

per request

Cumulative requested days

6,000 days

rolling 1-hour bucket per (user_id)

The "requested days" cost of a single call is end_date − start_date. Calls without start_date/end_date count as 1 day. Requests at exactly 1,825 days are allowed; only > 1,825 is rejected.

circle-info

Why two rules? Most partners do small windows (≤ 30 days) and never come close to either limit. The per-request cap stops obviously-broken calls (e.g. requesting 20 years of data in one shot). The hourly cumulative cap stops loops that hammer the same user repeatedly with multi-year windows.

Detecting throttling

When a request is rejected, you'll receive an HTTP 429 Too Many Requests response with these headers:

Header
Meaning

X-Terra-RateLimit-Rule

Which rule fired: r1 (per-request) or r2 (cumulative)

Retry-After

For r2: seconds until the hourly bucket resets. For r1: not set (retrying the same request won't help).

Response body:

{
  "detail": "rate limit exceeded"
}

Successful responses include your remaining budget

Whenever a request is accepted and the cumulative rule (R2) was evaluated, we include three headers so you can pace yourself without guessing:

Header
Meaning

X-Terra-RateLimit-Limit

Your hourly limit in days (e.g. 6000)

X-Terra-RateLimit-Remaining

Days left in the current hour bucket

X-Terra-RateLimit-Reset-After

Seconds until the bucket resets

Example response:

If these headers are missing, no rate-limit budget was tracked for the request (e.g. an unauthenticated path) — you don't need to act on them.

Handling 429s

  • X-Terra-RateLimit-Rule: r1 — your start_date/end_date window is wider than 5 years. Split it into shorter windows and retry. Don't retry the same request; it will fail again.

  • X-Terra-RateLimit-Rule: r2 — your code has issued requests for this user totalling more than 6,000 days in the current hour. Wait Retry-After seconds, then resume. Smaller windows won't help until the bucket resets.

A simple back-off:

Best practices

  • Cache what you've already fetched. The cumulative cap is wall-clock time, not cache misses — replays count too.

  • Chunk backfills. A 5-year backfill at 30-day chunks is 60 calls; spread them across a few hours and you'll never see a 429.

  • Watch the X-Terra-RateLimit-Remaining header in production logs. Drops toward zero predict throttling before it happens.

  • One request per user at a time. Parallel calls for the same user share a budget; concurrency does not multiply your allowance.

circle-exclamation

FAQ

Does this apply to webhook deliveries? No. Rate limits only apply to inbound API requests on the data-read endpoints listed above.

Does the budget reset at the top of the hour or rolling from my first request? Fixed buckets aligned to UTC (e.g. 14:00–15:00 UTC). The Retry-After header tells you exactly when the current bucket resets.

Can I get a higher limit? Reach out to your account contact — limits can be raised per dev_id for legitimate use cases.

What counts as one "day" of cost? Whatever you pass as end_date − start_date. A request like ?start_date=2024-01-01&end_date=2024-01-31 costs 30 days, regardless of how much data the user actually has in that range.

Last updated

Was this helpful?