> ## Documentation Index
> Fetch the complete documentation index at: https://docs.propaideals.co.uk/llms.txt
> Use this file to discover all available pages before exploring further.

# Rate limits

> Per-second rate limits, monthly request quotas, AI chat quotas, and rate limit headers for the Prop AI Deals API. Covers the Starter, Professional, and Business plans with concrete numbers.

# Rate limits

The Prop AI Deals API enforces three types of limits on every `paid_*` request:

1. **Per-second rate limit** — Sliding-window counter, rejects with `429` when exceeded
2. **Monthly request quota** — **Hard cap** at the plan's `monthly_request_limit`. No soft/hard split, no 2× tolerance. Once you hit the cap, requests are blocked until the next billing period.
3. **AI chat quota** — Separate quota for AI endpoints (which also cost 5× normal requests against your monthly quota)

All limits are per **account** (not per IP, not per key). Your subscription buys one shared pool: every API key you create draws from the **same** per-second rate limit, monthly request quota, and AI chat quota. Creating more keys does **not** increase your limits.

## Plan comparison

| Plan             | Price (GBP/mo) | Requests / month | £/request | Per-second | AI chats / month | Batch limit |
| ---------------- | -------------- | ---------------- | --------- | ---------- | ---------------- | ----------- |
| **Starter**      | £99            | 20,000           | £0.00495  | 10 req/s   | 100              | 100         |
| **Professional** | £299           | 100,000          | £0.00299  | 25 req/s   | 1,000            | 200         |
| **Business**     | £999           | 400,000          | £0.00250  | 50 req/s   | 4,000            | 500         |
| **Enterprise**   | Custom         | Custom           | —         | Custom     | Custom           | Custom      |

**All tiers are paid — there is no free tier.** Every plan grants read access to properties, market data, investment calculators, spatial search, planning data, lead generators, EPC certificates, UPRN, demographics, flood risk, and heritage data, plus the `ai:chat` scope (the AI chat quota scales by tier — see the table above). Professional and Business additionally include `build-cost:read`.

> **Per-request value:** at every tier we're cheaper per request than the closest UK competitor AND give 20–25× higher per-second rate limits than equivalent tiers at PropertyData.

**Enterprise** plans are custom-provisioned (negotiated limits, dedicated infrastructure, SLAs). Email `info@propaideals.co.uk` to discuss.

Live plan details: `GET https://api.propaideals.co.uk/api/v1/api-billing/plans`

## How limits are enforced

### Per-second rate limit

Sliding-window counter per account in Redis (shared across all your keys). If you exceed it, the request fails immediately with `429 rate_limit_exceeded`:

```json theme={null}
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded. Retry after 1.0 seconds.",
    "retry_after": 1.0
  }
}
```

Sleep for `retry_after` seconds and retry. See [retry policy](./errors#recommended-retry-policy).

### Monthly request quota — HARD cap

The plan's `monthly_request_limit` is a **hard ceiling** (not a soft target). Example for Professional at 100,000 requests/month:

* Request #99,999 → ✅ 200 OK, `X-Monthly-Usage: 99999`
* Request #100,000 → ✅ 200 OK, `X-Monthly-Usage: 100000`
* Request #100,001 → ❌ 429 `monthly_quota_exceeded`

Once you've consumed the full quota, **every subsequent request returns 429** until the calendar month rolls over or you upgrade your plan.

```json theme={null}
{
  "error": {
    "code": "monthly_quota_exceeded",
    "message": "Monthly request quota exceeded (100000/100000). Upgrade your plan or wait until the next billing period.",
    "used": 100000,
    "limit": 100000
  }
}
```

We recommend setting up alerts at **80% of your monthly quota** so you have time to upgrade before hitting the cap. Monitor `meta.usage.monthly_used` on every response, or poll `GET /api/v1/api-billing/usage` periodically.

### AI chat quota

AI endpoints (`/api/v1/ultimate-ai/*`) consume two budgets simultaneously:

1. **5 requests** from the monthly request quota (AI requests cost 5×)
2. **1 AI chat call** from the separate AI chat quota

When the AI quota is exhausted: `429 ai_chat_quota_exceeded`. Non-AI endpoints continue to work normally until the main monthly quota is also exhausted.

```json theme={null}
{
  "error": {
    "code": "ai_chat_quota_exceeded",
    "message": "AI chat quota exceeded (1000/1000). Upgrade your plan or wait until the next billing period.",
    "used": 1000,
    "limit": 1000
  }
}
```

**Every paid plan includes AI chat** — Starter 100 chats/month, Professional 1,000, Business 4,000. When the AI quota is exhausted the AI endpoints return `429 ai_chat_quota_exceeded`; all other endpoints keep working until the main monthly request quota is also used up.

### Request cost by endpoint

Most endpoints cost **1 request** against your monthly quota. Some cost more:

| Cost | Endpoints                                                                                                                                                                              |
| ---- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1    | Atomic data endpoints — `/prices`, `/sold-prices`, `/demand`, `/growth`, `/comparables`, `/sold-history`, `/rental-estimate`, `/playbook-tiers`, `/motivation-score`, plus most others |
| 2    | `/valuation`, `/deal-score`, `/strategy-scores`                                                                                                                                        |
| 5    | `/ultimate-ai/*` (AI chat)                                                                                                                                                             |
| 10   | `/property-pack`, `/area-summary` (convenience bundles)                                                                                                                                |

The `X-Request-Cost` response header and `meta.usage.request_cost` tell you exactly what each call consumed. The bundles (`/property-pack`, `/area-summary`) cost 10 because they assemble several atomic endpoints in one call — only cheaper than fetching the slices individually when you need most of them.

### Service-level backpressure (`503`)

During high concurrent traffic, the API server may return `503 Service temporarily busy` when its database connection pool is >85% utilized. This is a protective fast-fail to prevent cascade failures — not an authentication or quota error. The response includes a `Retry-After: 2` header.

```json theme={null}
{
  "error": "Service temporarily busy",
  "detail": "Database connection pool at capacity. Please retry.",
  "retry_after": 2
}
```

**Recommended handling:** retry after `retry_after` seconds with exponential backoff. 503s don't count against your monthly quota — we only increment usage on successful handler execution.

## Rate-limit headers

Every successful response includes these headers so you can budget without polling separately:

```
X-RateLimit-Limit: 25           # Per-second cap for your account (matches your plan)
X-RateLimit-Remaining: 23       # Per-second budget left in this 1-second window (account-wide)
X-Request-Cost: 1               # How much this request consumed (1 for most, 5 for AI)
X-Monthly-Usage: 4321           # Requests used this billing period (after this call)
X-Monthly-Limit: 100000         # Your plan's monthly hard cap
```

The same data appears in the response envelope:

```json theme={null}
{
  "meta": {
    "usage": {
      "monthly_used": 4321,
      "monthly_limit": 100000,
      "request_cost": 1
    }
  }
}
```

## Live usage endpoint

Get the current state of all quotas in one call (uses Clerk session auth, not API key):

```bash theme={null}
curl https://api.propaideals.co.uk/api/v1/api-billing/usage \
  -H "Authorization: Bearer eyJ..."
```

```json theme={null}
{
  "requests_used": 4321,
  "requests_limit": 100000,
  "ai_chat_used": 87,
  "ai_chat_limit": 1000,
  "plan_tier": "professional",
  "plan_name": "Professional",
  "billing_period_start": "2026-04-01T00:00:00+00:00",
  "billing_period_end": "2026-05-01T00:00:00+00:00"
}
```

## Best practices

### Throttle client-side

Most production traffic is bursty. Add a token-bucket or leaky-bucket throttle so you never hit the per-second limit in the first place.

```javascript theme={null}
import { RateLimiter } from 'limiter'

// Professional plan: 25 req/s — leave 10-20% headroom
const limiter = new RateLimiter({ tokensPerInterval: 22, interval: 'second' })

async function fetchProperty(id) {
  await limiter.removeTokens(1)
  return fetch(`https://api.propaideals.co.uk/api/v1/properties/${id}`, {
    headers: { Authorization: `Bearer ${process.env.PROPAIDEALS_API_KEY}` },
  }).then(r => r.json())
}
```

```python theme={null}
from ratelimit import limits, sleep_and_retry

# Professional plan: 25 req/s — leave 10-20% headroom
@sleep_and_retry
@limits(calls=22, period=1)
def fetch_property(property_id):
    return requests.get(
        f"https://api.propaideals.co.uk/api/v1/properties/{property_id}",
        headers={"Authorization": f"Bearer {API_KEY}"},
    ).json()
```

Leave 10–20% headroom below your nominal limit to absorb clock skew and transient bursts.

### Cache aggressively

Properties don't change second-to-second. A simple in-memory cache with a 5-minute TTL can cut your bill by 80%+ for read-heavy workloads.

```python theme={null}
from cachetools import TTLCache, cached

cache = TTLCache(maxsize=10_000, ttl=300)  # 5 minutes

@cached(cache)
def get_property(property_id: str) -> dict:
    return fetch_property(property_id)
```

### Batch where possible

Use the search endpoints (`GET /api/v1/properties?area=...&limit=100`) instead of N parallel `GET /api/v1/properties/{id}` calls. One paginated request returns up to 100 properties for the cost of one request — saves 99 quota units and improves latency.

### Monitor `meta.usage`

Log `meta.usage.monthly_used` on every response. Page yourself when usage crosses **80%** of your monthly limit so you can upgrade before hitting the hard cap.

For Professional (100,000 requests/month), 80% = 80,000 requests. At 25 req/s sustained, that's \~53 minutes. At 5 req/s sustained, that's \~4.4 hours. Set your alerting accordingly.

### Handle `429` and `503` with exponential backoff

Both `429 rate_limit_exceeded` (per-second) and `503 Service temporarily busy` (server pressure) are transient and should be retried with backoff. `429 monthly_quota_exceeded` is NOT transient — don't retry, upgrade instead.

See [Errors › Recommended retry policy](./errors#recommended-retry-policy) for a copy-paste retry helper.

### Use separate keys per environment

Give production, staging, and CI each their own key so you can revoke or rotate one without disrupting the others, and tell traffic apart in `GET /api/v1/api-billing/logs` and `/usage/daily`. **Note:** all keys on your account share one quota pool — separate keys improve hygiene and attribution, they do **not** raise your limits, so a runaway CI script still draws down the same monthly quota. Add a client-side throttle to non-production keys if that's a concern. You can have up to 5 active keys per account.
