Documentation Index
Fetch the complete documentation index at: https://docs.mareaalcalina.com/llms.txt
Use this file to discover all available pages before exploring further.
Rate limits
Marea uses per-key minute and day buckets with Stripe-compatible headers. Counts increment before the handler runs, so 4xx and 5xx responses still count against your quota — that’s deliberate, and it defends against spam-of-invalid-requests abuse.Headers on every response
Retry-After is in seconds. For minute-bucket overflow it’s seconds-until-the-next-minute (always ≤ 60). For day-bucket overflow it can be up to 86,400 seconds (a full day).
The headers report on the minute bucket only — there is no
X-RateLimit-Remaining-Day header. Use GET /v1/me’s rateLimit.remainingDay for the day-bucket counter.Default budgets
Read your live values fromGET /v1/me (the rateLimit object). Values stored on the API key doc at issuance time:
| Key prefix | Key type | rpm | rpd | Notes |
|---|---|---|---|---|
mk_user_* | User scope | 60 | 10,000 | Issued via POST /v1/users/:userId/keys. |
mk_dev_* | Developer scope | 60 | 50 (default) | The dev-key rpd is the bootstrap-per-day ceiling — see below. |
GET /v1/me. The response includes:
Header vs. body precision. The exact
remainingMinute value lives in the response headers (X-RateLimit-Remaining). The /v1/me body’s remainingMinute is approximate — it’s the value at response-assembly time, not at your next request. For backoff logic, trust the headers.429 response shape
message field tells you which bucket overflowed:
messagecontainsrpm_exceeded→ minute bucket. WaitRetry-Afterseconds (always ≤ 60), then retry.messagecontainsrpd_exceeded→ day bucket.Retry-Afteris the seconds-remaining-in-the-day (up to 86,400). Do not retry tight; wait the indicated time or escalate to the user.
retryAfterMs field on the error body mirrors Retry-After in milliseconds. Both recoverable: true and nextActions[0].label indicate that the call is safe to repeat once the window opens.
Recommended agent backoff
Minute-bucket overflow:Idempotency-Key, keep the same key across retries — the server treats the eventual successful call as a replay-safe completion of the original request. See Safe mutations.
What counts against your quota
Every authenticated request to a/v1 endpoint — 200, 4xx, 5xx — counts. The increment happens before the handler runs, so a malformed body that the handler would have rejected with a 422 still consumes one minute-bucket slot and one day-bucket slot.
Exceptions:
- Unauthenticated requests (rejected at the apiKey middleware before rate-limit increments) do not count.
- The health-check shortcut at
/healthzdoes not pass through the rate-limit middleware. - If the rate-limit Firestore transaction itself fails (infrastructure error), the request is failed open — it proceeds without an increment and without a 429. A structured log entry is emitted so the 5xx-rate alert surfaces the underlying infra failure.
Conventions
Stripe-compatible headers and semantics —X-RateLimit-* plus Retry-After. The same backoff library you’d use for Stripe works here unchanged.
Buckets are per key, not per account. If a single user has both mk_user_keyA and mk_user_keyB, each gets its own 60/10,000 budget. This is by design: a misbehaving integration on one key can’t starve a well-behaved integration on another key for the same user.