Candidate provider packages, with the rate-limit pattern each one would exercise. Networks are the first use case of Tapyr, not its boundary (ADR 0011): any metric-oriented API whose quota is worth planning can become a package.
This is a pool of ideas, not a commitment, and contributions are welcome: read Provider packages first. The limits below were gathered from public documentation in November 2026: verify them before writing a package, and cite their sources in the package. A provider that needs one of the engine gaps starts with an issue, since the engine changes first.
Per-minute and monthly limits depending on plan, verify
Strava
Activities, training load
Read: 100 per 15 min (reset at :00, :15, :30, :45) and 1000 per day (reset at midnight UTC); both values packed in one header (X-ReadRateLimit-Usage: 15min,daily)
Needs 15-minute aligned windows and quota sync from expressions
Most of the APIs above fit the configuration model as it is: rate, concurrency, calendar and rolling quota windows, scopes, header sync and Retry-After (04-budget-engine.md). Four mechanisms are missing. Each one is a generic, configurable feature, designed in its own issue before any package needs it:
Gap
Today
Needed by
Request cost
A quota counts one unit per request
GitHub GraphQL (points per query, returned in the response), RIPE Atlas (credits per measurement), AWS Cost Explorer (every request is billed), Shodan (query credits)
Quota windows aligned on any duration
A fixed window is a calendar period (minute, hour, day, week, month)
Strava (15 minutes, reset at :00, :15, :30 and :45)
Quota sync from expressions
The limit, the remaining and the reset come from one header each
Strava (two windows packed in one header), APIs that report their quota in the body
Rate limiting signaled other than by a status
errors.rateLimited matches HTTP statuses
VirusTotal v2 (204 without a body), APIs answering 200 with an error object
Windows that start at the first request (ThousandEyes) are not a gap when the API sends a reset header: every response sets the end of the window to the provider's (04-budget-engine.md, Header sync). They would be one for an API that sends none.