Skip to main content
Version: 0.9.17 — archived documentation

API server config

Path: /admin-settings → API Server Config tab

Configure how the API server (TelAPI) instance set scales under load, and how inbound requests are throttled.

General​

FieldRequiredDescription
EnabledYesMaster toggle for the config.

Auto-scaling​

Same model as Server groups applied to API server instances.

FieldRequiredDefaultDescription
Scaling EnabledYesfalseMaster toggle.
Min InstancesYes1Never scales below.
Max InstancesYes10Never scales above.
Scale Up ThresholdYes0.7Utilisation (0 – 1) triggering scale-up.
Scale Down ThresholdYes0.3Utilisation triggering scale-down.
Cooldown SecondsYes300Min wait between actions.
Scaling ProviderYes—hetzner / aws / custom.
Scaling ConfigNo—Provider-specific JSON.

Rate limiting​

TelAPI applies IP-based server protection by route tier. Limits are stored in this config, cached in Redis, and reloaded automatically when you save (revision key voiceai:api-server-config:rev). /health and /metrics are always exempt.

FieldDefaultDescription
Rate Limit EnabledtrueMaster toggle for all tiers except health.
API Rate Limit Max600Max requests per client IP per window for authenticated API routes.
API Rate Limit Window (ms)60000Window for the API tier (60 000 = one minute).

Auth routes (/api/v1/auth/*) use a fixed preset of 20 requests per minute per client IP until dedicated fields are added here.

When a tier limit is exceeded, TelAPI returns 429 Too Many Requests with error.code: RATE_LIMIT_EXCEEDED and optional details (max, after, ttlMs). See Errors.

Deprecated env vars — v0.9.13-patch3

TelAPI no longer reads RATE_LIMIT_MAX or RATE_LIMIT_WINDOW_MS. Remove them from the API service env bundle after upgrade. The former Per API Key toggle is also removed — server protection is always keyed by client IP + route tier.

Daily team limit

This screen controls platform-wide server protection. Teams also have per-team daily quotas under Users and teams → API Access Configuration. A request can hit either limit independently.

API credential retry jail​

The credential retry jail is configured through installation-level environment variables, separately from the request rate limits above. TelAPI counts failed authentication attempts per client IP in Redis across REST API keys and session WebSockets.

By default, the fifth failed authentication attempt within five minutes triggers a five-minute jail. The counting window starts with the first failure; later failures do not extend it. Successful authentication clears the retry counter. While jailed, the same IP remains blocked even with valid credentials until the jail expires. Protected HTTP requests receive 429 RATE_LIMIT_EXCEEDED with Retry-After. Authorization failures after successful authentication, such as a missing scope (403), do not count. Redis errors are logged and fail open.

VariableDefaultPurpose
API_CREDENTIAL_JAIL_ENABLEDtrueEnable credential retry protection.
API_CREDENTIAL_MAX_RETRIES5Failure count that triggers the jail.
API_CREDENTIAL_RETRY_WINDOW_MS300000Counting window from the first failure, in milliseconds.
API_CREDENTIAL_JAIL_MS300000Jail duration in milliseconds.

Use the exact name API_CREDENTIAL_JAIL_MS. API_CREDENTIAL_JAIL_DURATION_MS is not read by TelAPI.

Configure an API installation​

  1. Deploy API infrastructure configuration containing all five variables in both /opt/services/api/vars.yaml and the telapi.environment section of /opt/services/api/docker-compose.yaml. The manifest controls which settings the loader exports; Compose controls which settings reach the container. The containers: [telapi] manifest field does not automatically inject them.
  2. Set installation overrides in AWS SSM Parameter Store under /<NAMESPACE>/api/<VARIABLE_NAME>; for example, /VGW-DEV-GROUP-C2/api/API_CREDENTIAL_JAIL_MS. These non-sensitive settings use the normal SSM source and manifest defaults. If provisioning through Terraform, apply the updated service manifest to create the parameters.
  3. From /opt/services/api, run ./init.sh --restart-only. This loads settings and recreates the containers using cached images. Ensure the deployed configuration source is updated too: init.sh can refresh files through fetch-config, overwriting host-only edits.
  4. Check the container environment:
docker exec voiceai-telapi env | sort | grep '^API_CREDENTIAL_'

For bootstrap-managed installations, source: local reads values from /opt/deployment/.env; the Compose mappings are still required. source: env is not a supported bootstrap source in fetch-env.sh. The environment index's “env” source label describes how the application reads a setting, not a vars.yaml source value. Do not put these settings in /opt/services/api/.env: init.sh removes that file before starting containers. SSM values can override bootstrap values for the same variable.

v0.9.17.0 deployment omission

The original v0.9.17.0 application supports these settings, but its API infrastructure manifest and Compose file omitted all five mappings. Adding .env values or editing only vars.yaml does not resolve the omission; deploy both corrected infrastructure files. This configuration fix does not require rebuilding the application image.

When variables are absent, TelAPI uses its application defaults. Those defaults do not appear in docker exec ... env, so an empty environment check alone does not prove the jail is disabled.

Verify behavior​

Use an isolated source IP and a protected REST API endpoint. Verify a valid request succeeds, fewer than five invalid attempts return 401, and a subsequent valid request resets the count. Then verify the fifth consecutive failure within the window returns 429 with Retry-After, a valid key from the jailed IP also returns 429, and valid requests succeed after expiry. Repeated authorization-only 403 responses must not create a jail.

Workflows​

Configure rate limiting​

Enable the config → toggle Enable Rate Limiting → set API max/window → save. Changes apply to running TelAPI instances without a container restart.

Enable auto-scaling​

Enable the config → toggle Scaling on → set min/max/thresholds/cooldown/provider/config → save.

See also​