API service operations
The API service runs the TelAPI server — a Fastify-based HTTP and WebSocket API that handles call tokens, browser-to-ARI channel communication, provider webhooks, and external API endpoints. Multiple instances run behind a managed Load Balancer with TLS termination and sticky sessions.
- Overview
- Runbook
- Configuration
- Troubleshooting
Instance
| Field | Value |
|---|---|
| Network | Private only — no public IP; traffic arrives via managed load balancer |
| Scalable | Yes — set initial count in your provisioning tool; the Ops Scaler can adjust count dynamically |
Containers
| Container | Image | Port | Purpose |
|---|---|---|---|
voiceai-telapi | ${ECR_REGISTRY}/voiceai-telapi:${ECR_TAG} (Node 24-alpine) | 3001 | API + WebSocket gateway (host network) |
voiceai-otel-collector | otel/opentelemetry-collector-contrib:0.154.0 | — | Telemetry collector |
Load balancer
| Field | Value |
|---|---|
| Frontend | HTTPS :443 with managed TLS for DOMAIN_API |
| Backend | :3001 |
| Health check | GET /health |
| Sticky sessions | Enabled — required for WebSocket |
| Target selection | role=api,environment=${ENVIRONMENT} |
Networking
Private network only — no public IP. All traffic arrives through the LB. Outbound to ECR, AWS Secrets, and provider APIs goes through the Squid proxy.
API surface by feature flag
| Surface | FEATURE_API_ACCESS=true | FEATURE_API_ACCESS=false | FEATURE_WEBRTC=false |
|---|---|---|---|
GET /health | Available | Available | Available |
/metrics | Available | Available | Available |
/api/v1/webhooks/* | Available | Available | Available |
/api/v1/sessions/* | Available | Not registered | Registered, but WebRTC session-token requests return 503 |
/api/v1/runtime/* | Available | Not registered | Available when API access is enabled |
/api/v1/endpoints | Available | Not registered | Available when API access is enabled |
/ws/session | Available | Not registered | Available only for non-WebRTC modes when API access is enabled |
Use FEATURE_API_ACCESS=false for webhook-only deployments. TelWeb also hides API keys and API Server Config surfaces when API access is disabled.
Scaling
Set the initial API instance count in your provisioning tool. The Ops service Scaler can also manage count dynamically based on active connections.
Instances are named ${environment}-api-01, -02, etc. New instances register with the LB automatically via labels.
Deploy and update
cd /opt/services/api
./init.sh # bring up
./update.sh --ecr-tag v0.9.13 # roll a new image
./update.sh --restart-only
init.sh fetches config from S3, loads env vars from SSM / Secrets Manager into memory via fetch-env.sh, logs into ECR, and starts Compose. Standard flags: --skip-images, --skip-fetch, --restart-only, --dry-run.
Rate limiting
TelAPI server-protection limits are not env vars. SUPERUSERs configure IP-based tiers (API, webhook, auth) in TelWeb under Admin Settings → API Server Config. TelAPI reloads limits from Redis when the config is saved — no restart required.
Remove deprecated RATE_LIMIT_MAX and RATE_LIMIT_WINDOW_MS from the API service env bundle after upgrading to v0.9.13-patch3. See API server config.
TTS media cache
TelAPI reads/writes the Media service cache over HTTPS using TTS_MEDIA_CACHE_BASE_URL, TTS_MEDIA_CACHE_UPLOAD_TOKEN, and TTS_MEDIA_CACHE_CA_BUNDLE. The bundle is decoded in memory (base64 or raw PEM) at process startup.
If TLS to the media host fails, check the TelAPI startup line TTS media cache TLS bootstrap (sanitized) — the tlsDiag fields (mediaCacheTlsMode, decodedCaBundleByteLength, decodedCaLooksLikePem) pinpoint the issue without logging secrets. The helper common/check-tts-media-cache-tls.sh --docker voiceai-telapi reproduces the same TLS stack with OpenSSL and curl.
| Name | Source | Scope | Default | Description |
|---|---|---|---|---|
TELAPI_PORT | SSM | all | 3001 | HTTP listen port. |
LOG_LEVEL | SSM | all | info | Application log level. |
DATABASE_URL | Secrets Manager | all | — | PostgreSQL connection string. |
DATABASE_SSL_MODE | SSM | all | disable | disable | require | verify-ca | verify-full. |
DATABASE_SSL_CA_BUNDLE_B64 | Secrets Manager | all | — | Base64 PEM CA for Postgres client TLS; decoded by prepare-tls.sh. Through PgBouncer must sign PgBouncer’s cert; for RDS use the AWS RDS CA. |
DATABASE_SSL_CA_FILE | env | all | /etc/ssl/database/ca.crt | Mount path for the decoded DB CA inside the TelAPI container. |
DATABASE_SECRET_ARN | env | prod | — | Optional Secrets Manager secret used to refresh runtime database credentials after authentication failures. |
REDIS_HOST | SSM | all | — | Redis server address. |
REDIS_PASSWORD | Secrets Manager | all | — | Redis authentication. |
REDIS_TLS_ENABLED | SSM | all | false | Enable TLS to Redis. |
REDIS_TLS_CA_BUNDLE_B64 | Secrets Manager | all | — | Base64 PEM CA for Redis TLS; optional when using public CA-signed Redis (e.g. ElastiCache). |
REDIS_TLS_CA_FILE | env | all | /etc/ssl/redis/ca.crt | Mount path for the decoded Redis CA inside the TelAPI container. |
JWT_SECRET | Secrets Manager | all | — | JWT signing key — must match TelWeb NEXTAUTH_SECRET pairings. |
DOMAIN_TELPRO | SSM | all | — | TelPro domain — used to build WebRTC config. |
FEATURE_WEBRTC | env | all | true | Controls browser SDK session/runtime/endpoint routes and /ws/session registration. |
FEATURE_API_ACCESS | env | all | true | Controls external REST/SDK access. When false, TelAPI registers health, metrics, and webhooks only. |
TTS_MEDIA_CACHE_BASE_URL | SSM | all | — | HTTPS base URL for the Media service. |
TTS_MEDIA_CACHE_UPLOAD_TOKEN | Secrets Manager | all | — | Bearer token for media cache writes / deletes. |
TTS_MEDIA_CACHE_CA_BUNDLE | SSM | all | — | Raw or base64 PEM CA bundle for private media TLS. |
OTEL_ENABLED | SSM | all | true | Enable OpenTelemetry export. |
ENABLE_PII_LOGGING | env | all | false | When not true, TelAPI redacts browser-action transcript text before DB persist; voiceai-otel-collector scrubs exported logs. Production: false except short support sessions; staging/dev may use true for debugging. |
MSISDN_UNMASKED_DIGITS | env | all | 4 | Trailing digits kept when masking phone numbers in collector log export. Set on telapi and voiceai-otel-collector. |
The authoritative list lives in this service's vars.yaml. Run common/show-env.sh --service api on the host for the full set.
See Configuration model for how SSM / Secrets Manager / TelWeb / DB sources fit together.
| Symptom | Likely cause | Check |
|---|---|---|
| LB targets unhealthy | TelAPI startup crash | docker compose ps; check /health on an instance. |
| 502 from LB | All instances down | At least one healthy instance is required. |
| 429 from TelAPI | IP tier or team daily quota | Check RATE_LIMIT_EXCEEDED details; review API server config and team API limits. |
| WebSocket disconnects | Sticky sessions misconfigured | LB sticky sessions must be enabled for WebSocket. |
| 401 auth failures | JWT_SECRET drift between API and TelWeb | Both must read the same Secrets Manager value. |
DEPTH_ZERO_SELF_SIGNED_CERT on media fetch | TTS_MEDIA_CACHE_CA_BUNDLE empty / wrong | Inspect tlsDiag fields in TelAPI startup logs; run common/check-tts-media-cache-tls.sh --docker voiceai-telapi. |
| Postgres connection drops | DB or PgBouncer cycling | See Database operations. |
See also
- Web operations — TelWeb consumer.
- Voice operations — channel-WS counterpart.
- Media operations — TTS cache target.