# HiRey: rate limits

> When HiRey says an operation is rate limited, it tells you the limit, how much is left, what counts, for whom, and exactly when the next call can succeed. Wait until then; retrying earlier never helps.

Some operations have a cap per person, for example research requests (`enrichment.request`) or Page writes (`page.compose`). Past the cap, the call is refused with HTTP `429` (REST also sends a `Retry-After` header) and `error_code` `rate_limited`, or the operation's own code such as `page_compose_daily_limit`, `person_lookup_daily_limit`, `company_index_daily_limit`, `post_daily_limit` or `presence_map_rate_limited`. Whatever the code, `data.rate_limit` says:

```json
{"code": "rate_limited", "operation": "enrichment.request",
 "limit": 40, "used": 40, "remaining": 0, "tier": "default",
 "counted_unit": "research requests (enrichment.request) started for you in this Workspace, including automatic card research",
 "scope": "person_workspace",
 "window": {"type": "rolling", "seconds": 86400},
 "retry_after_seconds": 5123, "next_available_at": "2026-10-18T05:02:11Z"}
```

- `limit`, `used`, `remaining`: the cap, how many calls count now, and how many are left (0 when refused).
- `counted_unit`: what one counted call is, in words.
- `scope`: whose calls count. `person`: the signed-in person across all their Workspaces. `person_workspace`: that person in this Workspace. `claim_link`: everyone opening that one claim link. `installation`: this app or browser install. `login_identity`: sign-in codes for this email or phone. `login_transaction`: this one sign-in. `email_address` / `email_domain`: verification emails to this address or domain. `service`: HiRey's own capacity, not your quota.
- `window`: `rolling` counts the last `seconds` (86400 is a rolling 24 hours: there is no midnight reset and no timezone). `fixed` counts from `started_at` for `seconds`.
- `retry_after_seconds` and `next_available_at` (UTC, whole seconds, never early): when one slot frees. In a rolling window that is a full window after the oldest call that still counts, so it can be hours away. For sign-in and cold-contact limits it is the latest time a slot frees.
- `tier`: `default`, or `high` for people HiRey has given a higher quota. Only HiRey sets the tier; nothing in a request changes it.

What to do:

1. Don't retry the same operation before `next_available_at`. Do other work, or stop and tell the user.
2. Tell the user plainly, with the time in their timezone: "HiRey allows 40 research requests a day; the next one is available at 10:02 PM."
3. Plan big batches against the caps below (HiRey reports `remaining` only when it refuses): if the user asks for research on 60 people and the cap is 40 a day, do 40 and say when the rest can run.

Default caps (per rolling 24 hours unless stated; the high tier is five times each):

| Operation | Default | Scope |
|---|---|---|
| `enrichment.request` (research, automatic card research included) | 40 | person in this Workspace |
| `page.compose` | 30 | person in this Workspace |
| `page.suggest` | 30 | person in this Workspace |
| `person.lookup` | 20 | person in this Workspace |
| `company.index` name searches / site researches | 60 each | person |
| post publications (`media.post`; a changed post republished counts, an unchanged call does not) | 20 (50 on the first day of posting) | person |

Safety limits that are the same for everyone: live map reads (20 a minute, 400 an hour), reply alerts codes (5 an hour), claim link opens (12 in 10 minutes), company verification emails (3 an hour per address, 5 per person, 10 per domain), sign-in codes and sign-ins (per email or phone and per install), people you start contacting cold (3, 10 or 25 a day by your account; `sender_daily_new_contacts_limit`), and people searches (`people.retrieve`, 120 a minute and 4 at once per person; these also keep `retry_after_seconds` and `limits` at the top level).
