Configuration
The Ony.ai server reads its configuration from environment variables (or a local .env), all
prefixed ONY_. This page documents the ones that matter. The full annotated list lives in
.env.example in the repo.
The one value you must set
Section titled “The one value you must set”For a real deployment, the only variable you are required to set is the signing secret. Everything else has a sensible default or is optional.
# Signs decision tokens and the audit chain. Generate a strong, unique value per environment.ONY_SIGNING_SECRET=$(openssl rand -hex 32)| Variable | Default | Purpose |
|---|---|---|
ONY_ENV |
local |
production for any public host. local/test/dev enable dev conveniences (passwordless reset token, dev login, webhook-signature skip) that are unsafe in production |
ONY_EDITION |
oss |
oss is fully featured standalone. cloud unlocks the managed multi-tenant extension points |
ONY_SIGNING_SECRET |
dev-only-change-me |
Signs decision tokens and the audit chain. Override per environment |
ONY_DATABASE_URL |
postgresql+psycopg://ony:ony@localhost:5432/ony |
SQLAlchemy database URL |
ONY_REDIS_URL |
redis://localhost:6379/0 |
Valkey/Redis for rate limiting, idempotency, and call correlation. Optional for a single API instance (falls back to in-memory) |
ONY_PUBLIC_BASE_URL |
empty | Public base URL clients and the telephony provider reach. Must be https://<your-domain> in production so webhook callback URLs are correct |
ONY_WEB_BASE_URL |
ONY_PUBLIC_BASE_URL |
Base URL for user-facing links (reset/invite emails, SMS deep links). Set separately when the public base is a webhook-only edge |
ONY_DEFAULT_HANDOFF_TTL_SECONDS |
900 |
Server-assigned handoff TTL. The client-supplied expires_at is only a hint |
ONY_DETAILS_RETENTION_DAYS |
0 |
After N days a daily sweep scrubs the sensitive details payload from handoffs, keeping metadata and the audit chain. 0 = keep forever |
ONY_LOG_FORMAT |
plain |
plain (human) or json (structured, for log shippers) |
ONY_SENTRY_DSN |
empty | Optional Sentry error reporting; events are scrubbed before sending |
Telephony
Section titled “Telephony”Telephony is optional. Leave the whole section blank to configure a carrier from the
dashboard (Settings -> Integrations -> Telephony), or run on the built-in mock provider,
where handoffs are decided in the dashboard with no real call. If you set a provider here,
only that provider’s credentials are needed.
| Variable | Default | Purpose |
|---|---|---|
ONY_TELEPHONY_PROVIDER |
signalwire |
Active carrier: signalwire, twilio, telnyx, plivo, or mock |
SignalWire
Section titled “SignalWire”ONY_TELEPHONY_PROVIDER=signalwireONY_SIGNALWIRE_SPACE_URL=ONY_SIGNALWIRE_PROJECT_ID=ONY_SIGNALWIRE_API_TOKEN=ONY_SIGNALWIRE_FROM_NUMBER=ONY_SIGNALWIRE_AUTH_TOKEN= # the space's signing key (starts "PSK_"), NOT an API tokenTwilio, Telnyx, Plivo
Section titled “Twilio, Telnyx, Plivo”Each provider is selected with ONY_TELEPHONY_PROVIDER and needs its own credentials:
- Twilio (
twilio):ONY_TWILIO_ACCOUNT_SID,ONY_TWILIO_AUTH_TOKEN,ONY_TWILIO_FROM_NUMBER. The auth token also verifies webhook signatures. - Telnyx (
telnyx):ONY_TELNYX_ACCOUNT_SID(TeXML application id),ONY_TELNYX_API_KEY,ONY_TELNYX_PUBLIC_KEY(base64 Ed25519 public key for webhook verification),ONY_TELNYX_FROM_NUMBER. - Plivo (
plivo):ONY_PLIVO_AUTH_ID,ONY_PLIVO_AUTH_TOKEN,ONY_PLIVO_FROM_NUMBER. The auth token signs webhooks and authenticates REST.
Voice brain and speech-to-text (optional)
Section titled “Voice brain and speech-to-text (optional)”The inbound “talk to your agent” voice feature can use an LLM brain and higher-accuracy transcription, but works without either.
| Variable | Default | Purpose |
|---|---|---|
ONY_LLM_PROVIDER |
auto |
auto (use whatever key is set), openai, anthropic, or none (force the deterministic fallback) |
ONY_OPENAI_API_KEY |
empty | Key for the OpenAI-compatible brain. Point ONY_OPENAI_BASE_URL at Groq/Together/OpenRouter/a local server to switch backends |
ONY_ANTHROPIC_API_KEY |
empty | Key for the Anthropic (Claude) brain |
ONY_ASR_MODE |
carrier |
carrier uses the telephony provider’s built-in recognition (zero config); whisper transcribes via an OpenAI-compatible endpoint (needs ONY_WHISPER_API_KEY) |
With no key configured, the brain falls back to deterministic intent matching, so inbound voice still works.
Security and networking
Section titled “Security and networking”| Variable | Default | Purpose |
|---|---|---|
ONY_RATE_LIMIT_ENABLED |
true |
Rate limiting on the auth surface, OTP sends, call placement, and handoffs. Disable only for isolated load testing |
ONY_TRUSTED_PROXY_HOPS |
0 |
Number of trusted reverse proxies for client-IP extraction. 0 uses the socket peer (no proxy). The compose files set this for you |
ONY_TRUST_CF_CONNECTING_IP |
false |
Behind a Cloudflare Tunnel, key per-IP rate limiting off CF-Connecting-IP. Leave false for a plain reverse proxy |
ONY_FORWARDED_ALLOW_IPS |
127.0.0.1 |
Which upstream peers uvicorn trusts X-Forwarded-* from behind a TLS-terminating edge |
ONY_TURNSTILE_SITE_KEY / ONY_TURNSTILE_SECRET_KEY |
empty | Cloudflare Turnstile CAPTCHA on signup/login. Both empty disables it (the OSS/Lite default) |
Escalation and fallback channels
Section titled “Escalation and fallback channels”Multi-channel escalation retries and falls back across channels when a call goes unanswered (call -> Telegram -> SMS by default). Off by default; the out-of-box behavior is a single call plus one backup-contact attempt. See escalation.
| Variable | Default | Purpose |
|---|---|---|
ONY_ESCALATION_ENABLED |
false |
Enable the multi-channel escalation engine |
ONY_TELEGRAM_BOT_TOKEN |
empty | Telegram decision channel bot token (from @BotFather) |
ONY_TELEGRAM_BOT_USERNAME |
empty | The bot’s username (no @), used to build the account-linking deep link |
ONY_TELEGRAM_WEBHOOK_SECRET |
empty | Matched against the X-Telegram-Bot-Api-Secret-Token header (required in production when the bot token is set) |
ONY_SLACK_BOT_TOKEN |
empty | Slack decision channel bot token |
ONY_SLACK_SIGNING_SECRET |
empty | Verifies X-Slack-Signature (required in production when the bot token is set) |
Single sign-on (OIDC)
Section titled “Single sign-on (OIDC)”Point Ony.ai at any OpenID Connect provider (Authentik, Keycloak, Google Workspace, Azure AD).
SSO is disabled while ONY_OIDC_ISSUER is empty. Register the callback URL
<ONY_PUBLIC_BASE_URL>/api/v1/auth/oidc/callback with your IdP.
| Variable | Default | Purpose |
|---|---|---|
ONY_OIDC_ISSUER |
empty | Discovery base URL. Empty disables SSO |
ONY_OIDC_CLIENT_ID / ONY_OIDC_CLIENT_SECRET |
empty | OIDC client credentials |
ONY_OIDC_SCOPES |
openid email profile |
Requested scopes |
ONY_OIDC_ALLOWED_DOMAINS |
empty | Comma-separated email domains allowed to just-in-time create an account on first SSO login. Empty = no JIT |
ONY_OIDC_ADMIN_GROUP / ONY_OIDC_VIEWER_GROUP |
empty | Map OIDC groups to Ony.ai roles. Admin wins over viewer; absent both, a JIT user defaults to member |
ONY_OIDC_GROUPS_CLAIM |
groups |
Name of the token claim carrying group membership |
Password-reset, invite, and welcome emails. Leave ONY_EMAIL_PROVIDER empty for the console
fallback (the message is printed to the server log), which is fine for a single-admin
self-host. Set smtp and point it at any relay for a multi-user deployment.
| Variable | Default | Purpose |
|---|---|---|
ONY_EMAIL_PROVIDER |
empty | smtp or empty (console fallback) |
ONY_EMAIL_FROM |
Ony <noreply@ony.ai> |
From header and envelope sender |
ONY_SMTP_HOST / ONY_SMTP_PORT |
empty / 587 |
SMTP relay host and port |
ONY_SMTP_USERNAME / ONY_SMTP_PASSWORD |
empty | SMTP credentials |
ONY_SMTP_TLS_MODE |
starttls |
starttls (587), tls (implicit SMTPS, 465), or none (local relay) |
Backups
Section titled “Backups”The optional backup overlay (deploy/docker-compose.backup.yml) runs a nightly pg_dump with
optional at-rest encryption and an offsite copy - see
BACKUP.md for the full ONY_BACKUP_*
set. For a privacy review, this window and ONY_DETAILS_RETENTION_DAYS above are the two retention
variables: together they bound how long sensitive payloads persist (see
data handling).
| Variable | Default | Purpose |
|---|---|---|
ONY_BACKUP_RETENTION_DAYS |
30 |
Days of nightly database dumps the backup overlay keeps before pruning |
Hosted edition only (billing)
Section titled “Hosted edition only (billing)”These apply only to the managed hosted edition, which enforces plans. OSS self-host is always fully featured, so an empty Stripe key means no checkout.
| Variable | Default | Purpose |
|---|---|---|
ONY_STRIPE_SECRET_KEY |
empty | Stripe secret key (use TEST keys outside production) |
ONY_STRIPE_WEBHOOK_SECRET |
empty | Verifies Stripe webhook signatures |
ONY_STRIPE_PRICE_PRO / ONY_STRIPE_PRICE_TEAM |
empty | Map plans to Stripe recurring price ids |
Connector config files
Section titled “Connector config files”The ony connector on each machine keeps its own local config, separate from the server
environment above.
~/.ony/config.json- the machine’s device identity: server URL, device id, device token, per-device decision key, and the global default mode. Written byony enroll/ony init. It holds a long-lived device token, so on POSIX it is created owner-only (0600). Override the directory with theONY_HOMEenvironment variable.<project>/.ony/project.json- per-project settings, chiefly themode(on,away, oroff) set byony on|away|offor the/onyskill, and theheadless_gateflag fromony hooks install --headless. The project mode overrides the global default for every session in that project.
See the CLI reference for the commands that write these files.