Description
Currently, all authenticated Shutter API keys use the same @withApiKey rate limits. This prevents us from granting higher limits to continuous-use customers without raising limits for every authenticated user.
Introduce mutually exclusive API-key tiers with centrally managed rate-limit policies.
Proposed implementation
- Add an optional
tier column to keys.csv.
- Treat existing two-column rows as
standard for backward compatibility.
- Define endpoint limits and tier multipliers in
apikeys/limits.yaml.
- Support the following tiers:
unauthorized: anonymous access, counted per source IP
standard: existing authenticated limits
premium: increased limits for continuous users
- Generate separate Caddy matchers for each tier.
- Generate all rate-limit zones from
limits.yaml.
- Preserve
/check_authentication for valid keys from every tier.
- Reject unknown tiers and malformed policy configuration during compilation.
- Print the resolved limits and number of keys per tier during compilation.
- Document key creation, tier changes, recompilation, and Caddy restart procedures.
Target limits
| Endpoint |
Anonymous |
Standard |
Premium |
/time/register_identity |
5/day |
500/day |
2,500/day |
/time/get_data_for_encryption |
10/day |
1,000/day |
5,000/day |
/time/get_decryption_key |
20/day |
2,000/day |
10,000/day |
/decrypt_commitment |
10/day |
1,000/day |
5,000/day |
/event/compile_trigger_definition |
20/day |
2,000/day |
10,000/day |
/event/register_identity |
5/day |
500/day |
2,500/day |
/event/get_data_for_encryption |
10/day |
1,000/day |
5,000/day |
/event/get_trigger_expiration_block |
20/day |
2,000/day |
10,000/day |
/event/get_decryption_key |
20/day |
2,000/day |
10,000/day |
Acceptance criteria
Deployment validation
- Create separate standard and premium test keys.
- Compile the API-key and rate-limit configuration.
- Review the printed effective-limit table.
- Validate the generated Caddy configuration.
- Restart Caddy and confirm it loads the generated configuration.
- Test
/check_authentication with no key, an invalid key, a standard key, and a premium key.
- Confirm each request is handled by the expected tier.
- Test the
429 boundary using a temporary short-window policy.
- Restore the intended production policy.
- Run a short continuous time-based decryption test using the premium key.
Operational considerations
- Rate-limit counters are held in Caddy memory and reset when Caddy restarts.
- Changing a key's tier requires recompiling the snippet and restarting Caddy.
- Test keys must not belong to customers.
- API keys must not be printed in logs or committed to the repository.
- Registration limits are also spending limits because each registration consumes gas from the shared API signer.
Description
Currently, all authenticated Shutter API keys use the same
@withApiKeyrate limits. This prevents us from granting higher limits to continuous-use customers without raising limits for every authenticated user.Introduce mutually exclusive API-key tiers with centrally managed rate-limit policies.
Proposed implementation
tiercolumn tokeys.csv.standardfor backward compatibility.apikeys/limits.yaml.unauthorized: anonymous access, counted per source IPstandard: existing authenticated limitspremium: increased limits for continuous userslimits.yaml./check_authenticationfor valid keys from every tier.Target limits
/time/register_identity/time/get_data_for_encryption/time/get_decryption_key/decrypt_commitment/event/compile_trigger_definition/event/register_identity/event/get_data_for_encryption/event/get_trigger_expiration_block/event/get_decryption_keyAcceptance criteria
keys.csvfiles continue working.standardlimits./check_authenticationrecognizes valid keys from every assignable tier.limits.yamlconfiguration fails before Caddy starts.caddy validate.Deployment validation
/check_authenticationwith no key, an invalid key, a standard key, and a premium key.429boundary using a temporary short-window policy.Operational considerations