Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.permitcore.io/llms.txt

Use this file to discover all available pages before exploring further.

Status: rate limits are currently uniform across all keys at 100K requests / month. Tier-aware enforcement ships in ~3 weeks as part of the Bucket 2 data-pipeline release. Your tier still controls cohort coverage + history depth today; the request ceiling unifies during this early launch window.

Tier matrix (future state)

TierRequest quotaCohortsHistoryWebhooks
Free1,000 / day6 (subset)30 days
Hobby ($49/mo)10,000 / monthAll 1890 days1
Builder ($149/mo)100,000 / monthAll 18Full5
Growth ($299/mo)500,000 / monthAll 18Full25
ProCustomAll 18 + customFullUnlimited
Free tier resets daily at 00:00 UTC. Paid tiers reset monthly on the first of each month UTC. See permitcore.io/pricing for the full breakdown.

429 responses

When a key exceeds its quota, the API returns:
HTTP/1.1 429 Too Many Requests
Retry-After: 3600
Content-Type: application/json

{
  "error": {
    "code": "rate_limited",
    "message": "Rate limit exceeded. Quota resets at the indicated time.",
    "detail": {
      "period": "month",
      "limit": 100000,
      "used": 100000,
      "resets_at": "2026-06-01T00:00:00Z"
    }
  }
}
  1. Respect Retry-After. Header value is in seconds. For quota-based 429s the value is large (until period reset); for burst-based 429s (future) it’ll be short.
  2. Exponential backoff for transient 429s (Retry-After < 60s).
  3. Cache responses when you can — most endpoints declare Cache-Control headers (e.g., cohort distribution caches 1 hour).
  4. Bulk over loop. Where the API supports bulk parameters, prefer them.

Example: handling 429 with backoff

Node.js
async function permitcoreWithRetry(path, attempt = 1) {
  const res = await fetch(`https://api.permitcore.io${path}`, {
    headers: {
      Authorization: `Bearer ${process.env.PERMITCORE_API_KEY}`,
      Accept: "application/json",
    },
  });
  if (res.status === 429) {
    const retryAfter = Number(res.headers.get("retry-after") ?? "0");
    if (retryAfter < 60 && attempt < 3) {
      await new Promise((r) => setTimeout(r, retryAfter * 1000 || 2 ** attempt * 1000));
      return permitcoreWithRetry(path, attempt + 1);
    }
    throw new Error(`Rate limited; retry at ${new Date(Date.now() + retryAfter * 1000)}`);
  }
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json();
}

Future: burst limits + per-endpoint quotas

Bucket 2 (~3 weeks) introduces:
  • Per-endpoint burst limits (e.g., 30 req/sec sustained for permits endpoint)
  • Per-tier request ceilings (matrix above — Free is daily, paid tiers monthly)
  • Cohort-coverage gating (Free tier capped to 6 subset cohorts)
  • Webhook event quotas (paid tiers only)
Watch the changelog for rollout notes.