Skip to main content
PermitCore enforces per-tier monthly request + export ceilings on every quota-gated endpoint. The current tier model is Free / Pro / Enterprise — see permitcore.io/pricing for the buy flow.

Tier matrix

All tiers include all 22 cohorts and full history. Webhook event delivery is on the roadmap and not yet available.

Per-response rate-limit headers

Every 2xx response from /v1/permits (and other quota-gated endpoints) carries the following headers so your client can self-throttle:

X-RateLimit-Reset semantics (kind-aware)

The reset surface is interpreted via the X-RateLimit-Quota-Kind header (or the 429 body’s quota_kind field — they always agree): Branch on X-RateLimit-Quota-Kind (or quota_kind in the 429 body) if you need to display the right narrative to a user. Otherwise the retry guidance below works identically for both kinds.

429 response shape (RFC 9457 problem+json)

When a key exceeds its quota, the API returns 429 Too Many Requests with a Content-Type: application/problem+json body conforming to RFC 9457:

Field map

Title and detail are illustrative — the example body shows representative prose, but title/detail may change without notice. Always branch on type; never on the prose fields or the deprecated legacy_code. Sleep on retry_after_seconds (or the Retry-After header, or X-RateLimit-Reset) and retry — the timer is kind-aware on both daily and monthly quotas. All three surfaces agree. For monthly quotas the timer points at the next slot in the trailing 30-day window (not the full ceiling restoring at once), so a successful retry consumes that newly-available slot — back-to-back retries against a fully-exhausted monthly key will still 429.
Node.js
If you want to surface a user-facing message that distinguishes “daily quota — comes back at midnight UTC” from “monthly quota — slots restore progressively over the next 30 days,” branch on quota_kind for the narrative. The retry mechanics are the same either way.

Other guidance

  1. Cache responses when you can — most endpoints declare Cache-Control headers (e.g., cohort distribution caches 1 hour).
  2. Bulk over loop. Where the API supports bulk parameters, prefer them.
  3. Watch X-RateLimit-Remaining-Requests on 2xx responses — back off before the 429 fires.

Migration: away from legacy_code

The legacy_code field ("rate_limited") was added at launch for clients written against a pre-RFC-9457 error envelope shape. It is deprecated and being removed — do not depend on it. To migrate:
  • Move any client logic branching on error.code === "rate_limited" to branching on type (URI) instead.
  • The type URI pattern is stable: …/errors/{daily|monthly}-{requests|exports}-quota-exceeded.
  • As a fallback, branch on HTTP status 429 plus the X-RateLimit-* headers.
Watch the changelog for the removal notice.