Configuration file - viames/pair GitHub Wiki

Pair framework: .env configuration

Pair reads runtime configuration from APPLICATION_PATH/.env through Pair\Core\Env.

This page reflects ~/Sites/pair/.env.example.

Reference .env template

# core app
APP_NAME="Pair Application"
APP_VERSION="1.0"
APP_ENV=production
APP_DEBUG=false

# database
DB_HOST=127.0.0.1
DB_NAME=pair
DB_USER=root
DB_PASS=
DB_UTF8=true

# framework behavior
OAUTH2_TOKEN_LIFETIME=3600
PAIR_SINGLE_SESSION=true
PAIR_AUTH_BY_EMAIL=true
PAIR_AUDIT_ALL=true
PAIR_API_RATE_LIMIT_ENABLED=true
PAIR_API_RATE_LIMIT_MAX_ATTEMPTS=60
PAIR_API_RATE_LIMIT_DECAY_SECONDS=60
PAIR_API_RATE_LIMIT_REDIS_PREFIX="pair:rate_limit:"
PAIR_TRUSTED_PROXIES=
PAIR_CACHE_DRIVER=file
PAIR_CACHE_PATH=
PAIR_CACHE_PREFIX=pair
PAIR_CACHE_REDIS_PREFIX="pair:cache:"
PAIR_OBSERVABILITY_ENABLED=false
PAIR_OBSERVABILITY_DEBUG_HEADERS=true
PAIR_OBSERVABILITY_TRACE_SAMPLE_RATE=1.0
PAIR_OBSERVABILITY_ERROR_SAMPLE_RATE=1.0
PAIR_OBSERVABILITY_MAX_SPANS=100
PAIR_OBSERVABILITY_MAX_EVENTS=50
UTC_DATE=true

# observability exporters (optional)
SENTRY_DSN=
SENTRY_ENVIRONMENT=
SENTRY_RELEASE=
SENTRY_TRACES_SAMPLE_RATE=1.0
SENTRY_ERROR_SAMPLE_RATE=1.0
SENTRY_TIMEOUT=10
SENTRY_CONNECT_TIMEOUT=3
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=
OTEL_EXPORTER_OTLP_HEADERS=
OTEL_SERVICE_NAME=
OTEL_SERVICE_VERSION=
OTEL_TIMEOUT=10
OTEL_CONNECT_TIMEOUT=3

# redis (optional, used by API rate limiting and cache when configured)
REDIS_HOST=
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=0
REDIS_TIMEOUT=1

# crypto
AES_CRYPT_KEY=
OPTIONS_CRYPT_KEY=

# logger and notifications
PAIR_LOGGER_DISABLED=false
PAIR_LOGGER_EMAIL_RECIPIENTS=
PAIR_LOGGER_EMAIL_THRESHOLD=4
PAIR_LOGGER_TELEGRAM_CHAT_IDS=
PAIR_LOGGER_TELEGRAM_THRESHOLD=4
TELEGRAM_BOT_TOKEN=
TELEGRAM_API_BASE_URL="https://api.telegram.org"
TELEGRAM_TIMEOUT=20
TELEGRAM_CONNECT_TIMEOUT=5
TELEGRAM_WEBHOOK_SECRET_TOKEN=

# passkey / webauthn
PASSKEY_RP_ID=
PASSKEY_RP_NAME=
PASSKEY_ALLOWED_ORIGINS=
PASSKEY_REQUIRE_USER_VERIFICATION=true

# google maps
GOOGLE_MAPS_API_KEY=
GOOGLE_MAPS_BROWSER_API_KEY=
GOOGLE_MAPS_TIMEOUT=15
GOOGLE_MAPS_CONNECT_TIMEOUT=5

# whatsapp cloud api
WHATSAPP_CLOUD_ACCESS_TOKEN=
WHATSAPP_CLOUD_PHONE_NUMBER_ID=
WHATSAPP_CLOUD_API_VERSION=v23.0
WHATSAPP_CLOUD_API_BASE_URL="https://graph.facebook.com"
WHATSAPP_CLOUD_TIMEOUT=20
WHATSAPP_CLOUD_CONNECT_TIMEOUT=5
WHATSAPP_CLOUD_WEBHOOK_VERIFY_TOKEN=
WHATSAPP_CLOUD_APP_SECRET=

# stripe (optional)
STRIPE_SECRET_KEY=
STRIPE_WEBHOOK_SECRET=
STRIPE_API_VERSION=

# openai (optional)
OPENAI_API_KEY=
OPENAI_API_BASE_URL="https://api.openai.com/v1"
OPENAI_RESPONSES_MODEL=gpt-5.4-mini
OPENAI_EMBEDDINGS_MODEL=text-embedding-3-small
OPENAI_REALTIME_MODEL=gpt-realtime
OPENAI_TIMEOUT=30
OPENAI_CONNECT_TIMEOUT=5
OPENAI_STORE_RESPONSES=false

# gemini (optional)
GEMINI_API_KEY=
GEMINI_API_BASE_URL="https://generativelanguage.googleapis.com/v1beta"
GEMINI_GENERATION_MODEL=gemini-2.5-flash
GEMINI_EMBEDDINGS_MODEL=gemini-embedding-2
GEMINI_TIMEOUT=30
GEMINI_CONNECT_TIMEOUT=5

# claude (optional)
CLAUDE_API_KEY=
CLAUDE_API_BASE_URL="https://api.anthropic.com/v1"
CLAUDE_MESSAGES_MODEL=claude-sonnet-4-5
CLAUDE_API_VERSION=2023-06-01
CLAUDE_MAX_TOKENS=1024
CLAUDE_TIMEOUT=30
CLAUDE_CONNECT_TIMEOUT=5

# resend (optional)
RESEND_API_KEY=
RESEND_API_BASE_URL="https://api.resend.com"
RESEND_FROM_ADDRESS=
RESEND_FROM_NAME=
RESEND_WEBHOOK_SECRET=
RESEND_TIMEOUT=20
RESEND_CONNECT_TIMEOUT=5

# cloudflare turnstile (optional)
CLOUDFLARE_TURNSTILE_SITE_KEY=
CLOUDFLARE_TURNSTILE_SECRET_KEY=
CLOUDFLARE_TURNSTILE_VERIFY_URL="https://challenges.cloudflare.com/turnstile/v0/siteverify"
CLOUDFLARE_TURNSTILE_RESPONSE_FIELD=cf-turnstile-response
CLOUDFLARE_TURNSTILE_TIMEOUT=10
CLOUDFLARE_TURNSTILE_CONNECT_TIMEOUT=3

# meilisearch (optional)
MEILISEARCH_HOST="http://127.0.0.1:7700"
MEILISEARCH_API_KEY=
MEILISEARCH_DEFAULT_INDEX=
MEILISEARCH_TIMEOUT=10
MEILISEARCH_CONNECT_TIMEOUT=3
MEILISEARCH_SEARCH_LIMIT=20

# supabase (optional)
SUPABASE_URL=
SUPABASE_ANON_KEY=
SUPABASE_SERVICE_ROLE_KEY=
SUPABASE_TIMEOUT=20
SUPABASE_CONNECT_TIMEOUT=5

# web push (vapid)
PUSH_VAPID_PUBLIC=
PUSH_VAPID_PRIVATE=
PUSH_VAPID_SUBJECT=

Key groups

Core app

  • APP_NAME
  • APP_VERSION
  • APP_ENV
  • APP_DEBUG

Database

  • DB_HOST
  • DB_NAME
  • DB_USER
  • DB_PASS
  • DB_UTF8

Framework behavior

  • OAUTH2_TOKEN_LIFETIME
  • PAIR_SINGLE_SESSION
  • PAIR_AUTH_BY_EMAIL
  • PAIR_AUDIT_ALL
  • PAIR_API_RATE_LIMIT_ENABLED
  • PAIR_API_RATE_LIMIT_MAX_ATTEMPTS
  • PAIR_API_RATE_LIMIT_DECAY_SECONDS
  • PAIR_API_RATE_LIMIT_REDIS_PREFIX
  • PAIR_TRUSTED_PROXIES
  • PAIR_CACHE_DRIVER
  • PAIR_CACHE_PATH
  • PAIR_CACHE_PREFIX
  • PAIR_CACHE_REDIS_PREFIX
  • PAIR_OBSERVABILITY_ENABLED
  • PAIR_OBSERVABILITY_DEBUG_HEADERS
  • PAIR_OBSERVABILITY_TRACE_SAMPLE_RATE
  • PAIR_OBSERVABILITY_ERROR_SAMPLE_RATE
  • PAIR_OBSERVABILITY_MAX_SPANS
  • PAIR_OBSERVABILITY_MAX_EVENTS
  • UTC_DATE

Cache

  • PAIR_CACHE_DRIVER
  • PAIR_CACHE_PATH
  • PAIR_CACHE_PREFIX
  • PAIR_CACHE_REDIS_PREFIX
  • REDIS_HOST
  • REDIS_PORT
  • REDIS_PASSWORD
  • REDIS_DB
  • REDIS_TIMEOUT

Notes:

  • PAIR_CACHE_DRIVER accepts file, apcu, or redis
  • file is the dependency-free default and uses PAIR_CACHE_PATH when provided
  • apcu requires APCu to be installed and enabled in the current runtime
  • redis requires the Redis PHP extension and REDIS_HOST
  • PAIR_CACHE_REDIS_PREFIX namespaces cache keys independently from rate limiter keys

Example:

PAIR_CACHE_DRIVER=redis
PAIR_CACHE_REDIS_PREFIX="pair:cache:"
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=0
REDIS_TIMEOUT=1

Redis for API rate limiting

  • REDIS_HOST
  • REDIS_PORT
  • REDIS_PASSWORD
  • REDIS_DB
  • REDIS_TIMEOUT
  • PAIR_API_RATE_LIMIT_REDIS_PREFIX

Notes:

  • if REDIS_HOST is empty, Pair falls back to file-based rate limiting
  • if Redis is temporarily unavailable, Pair falls back to file-based storage automatically
  • PAIR_TRUSTED_PROXIES should contain exact IPs and/or CIDR ranges for trusted reverse proxies

Example:

PAIR_API_RATE_LIMIT_ENABLED=true
PAIR_API_RATE_LIMIT_MAX_ATTEMPTS=120
PAIR_API_RATE_LIMIT_DECAY_SECONDS=60
PAIR_API_RATE_LIMIT_REDIS_PREFIX="pair:rate_limit:"
PAIR_TRUSTED_PROXIES=127.0.0.1,10.0.0.0/8
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=0
REDIS_TIMEOUT=1

Crypto

  • AES_CRYPT_KEY
  • OPTIONS_CRYPT_KEY

Logger and observability

  • PAIR_OBSERVABILITY_ENABLED
  • PAIR_OBSERVABILITY_DEBUG_HEADERS
  • PAIR_OBSERVABILITY_TRACE_SAMPLE_RATE
  • PAIR_OBSERVABILITY_ERROR_SAMPLE_RATE
  • PAIR_OBSERVABILITY_MAX_SPANS
  • PAIR_OBSERVABILITY_MAX_EVENTS
  • PAIR_LOGBAR_SLOW_REQUEST_MS
  • PAIR_LOGBAR_SLOW_QUERY_MS
  • PAIR_LOGBAR_QUERY_BUDGET
  • PAIR_LOGBAR_DUPLICATE_QUERY_BUDGET
  • PAIR_LOGBAR_MAX_EVENTS
  • PAIR_LOGBAR_SHOW_SQL_VALUES
  • PAIR_LOGGER_DISABLED
  • PAIR_LOGGER_EMAIL_RECIPIENTS
  • PAIR_LOGGER_EMAIL_THRESHOLD
  • PAIR_LOGGER_TELEGRAM_CHAT_IDS
  • PAIR_LOGGER_TELEGRAM_THRESHOLD
  • TELEGRAM_BOT_TOKEN
  • TELEGRAM_API_BASE_URL
  • TELEGRAM_TIMEOUT
  • TELEGRAM_CONNECT_TIMEOUT
  • TELEGRAM_WEBHOOK_SECRET_TOKEN

Notes:

  • PAIR_LOGGER_TELEGRAM_CHAT_IDS accepts standard Telegram numeric chat IDs, including negative IDs for groups and channels
  • PAIR_OBSERVABILITY_ENABLED=true enables Pair runtime spans without requiring a third-party package in the core framework
  • PAIR_OBSERVABILITY_DEBUG_HEADERS=true allows explicit responses to expose correlation and timing headers only when APP_DEBUG=true
  • PAIR_OBSERVABILITY_TRACE_SAMPLE_RATE and PAIR_OBSERVABILITY_ERROR_SAMPLE_RATE control telemetry volume before provider adapters are called
  • PAIR_OBSERVABILITY_MAX_SPANS and PAIR_OBSERVABILITY_MAX_EVENTS cap in-process retained telemetry
  • PAIR_LOGBAR_SLOW_REQUEST_MS, PAIR_LOGBAR_SLOW_QUERY_MS, PAIR_LOGBAR_QUERY_BUDGET, and PAIR_LOGBAR_DUPLICATE_QUERY_BUDGET tune local LogBar diagnostics
  • PAIR_LOGBAR_MAX_EVENTS caps retained LogBar entries for one request
  • PAIR_LOGBAR_SHOW_SQL_VALUES=false keeps SQL bound values hidden by default; sensitive values are still masked when the flag is enabled
  • TELEGRAM_API_BASE_URL can target the official cloud endpoint or a local Bot API server
  • TELEGRAM_WEBHOOK_SECRET_TOKEN is the shared secret Telegram sends in X-Telegram-Bot-Api-Secret-Token

Observability exporters

  • SENTRY_DSN
  • SENTRY_ENVIRONMENT
  • SENTRY_RELEASE
  • SENTRY_TRACES_SAMPLE_RATE
  • SENTRY_ERROR_SAMPLE_RATE
  • SENTRY_TIMEOUT
  • SENTRY_CONNECT_TIMEOUT
  • OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
  • OTEL_EXPORTER_OTLP_HEADERS
  • OTEL_SERVICE_NAME
  • OTEL_SERVICE_VERSION
  • OTEL_TIMEOUT
  • OTEL_CONNECT_TIMEOUT

Notes:

  • SENTRY_DSN is used by SentryObservabilityAdapter
  • SENTRY_ENVIRONMENT falls back to APP_ENV
  • SENTRY_RELEASE falls back to APP_VERSION
  • OTEL_EXPORTER_OTLP_TRACES_ENDPOINT is used by OpenTelemetryHttpExporter
  • OTEL_EXPORTER_OTLP_HEADERS accepts comma-separated Name=value pairs
  • OTEL_SERVICE_NAME and OTEL_SERVICE_VERSION default to app metadata when empty

Supabase

  • SUPABASE_URL
  • SUPABASE_ANON_KEY
  • SUPABASE_SERVICE_ROLE_KEY
  • SUPABASE_TIMEOUT
  • SUPABASE_CONNECT_TIMEOUT

Notes:

  • SUPABASE_URL is the project base URL used by SupabaseClient
  • SUPABASE_ANON_KEY is used for user-scoped requests and Realtime URL construction
  • SUPABASE_SERVICE_ROLE_KEY is for trusted server-side calls only and must never be exposed to browsers or client apps
  • SUPABASE_TIMEOUT and SUPABASE_CONNECT_TIMEOUT control the dependency-free HTTP bridge

Passkey / WebAuthn

  • PASSKEY_RP_ID
  • PASSKEY_RP_NAME
  • PASSKEY_ALLOWED_ORIGINS
  • PASSKEY_REQUIRE_USER_VERIFICATION

Google Maps

  • GOOGLE_MAPS_API_KEY
  • GOOGLE_MAPS_BROWSER_API_KEY
  • GOOGLE_MAPS_TIMEOUT
  • GOOGLE_MAPS_CONNECT_TIMEOUT

WhatsApp Cloud API

  • WHATSAPP_CLOUD_ACCESS_TOKEN
  • WHATSAPP_CLOUD_PHONE_NUMBER_ID
  • WHATSAPP_CLOUD_API_VERSION
  • WHATSAPP_CLOUD_API_BASE_URL
  • WHATSAPP_CLOUD_TIMEOUT
  • WHATSAPP_CLOUD_CONNECT_TIMEOUT
  • WHATSAPP_CLOUD_WEBHOOK_VERIFY_TOKEN
  • WHATSAPP_CLOUD_APP_SECRET

Notes:

  • WHATSAPP_CLOUD_ACCESS_TOKEN should be a long-lived or system user token with whatsapp_business_messaging
  • WHATSAPP_CLOUD_PHONE_NUMBER_ID is the business phone number ID used by the /messages and /media endpoints
  • WHATSAPP_CLOUD_WEBHOOK_VERIFY_TOKEN is your own shared secret for the hub.* verification challenge
  • WHATSAPP_CLOUD_APP_SECRET lets Pair verify X-Hub-Signature-256 on inbound webhooks

Stripe

  • STRIPE_SECRET_KEY
  • STRIPE_WEBHOOK_SECRET
  • STRIPE_API_VERSION

Notes:

  • STRIPE_SECRET_KEY is required only when using the default StripeGateway SDK client
  • STRIPE_WEBHOOK_SECRET is required only for Stripe webhook signature verification
  • STRIPE_API_VERSION is optional; leave it empty to use the Stripe account default

OpenAI

  • OPENAI_API_KEY
  • OPENAI_API_BASE_URL
  • OPENAI_RESPONSES_MODEL
  • OPENAI_EMBEDDINGS_MODEL
  • OPENAI_REALTIME_MODEL
  • OPENAI_TIMEOUT
  • OPENAI_CONNECT_TIMEOUT
  • OPENAI_STORE_RESPONSES

Notes:

  • OPENAI_API_KEY is required only when using OpenAIClient outbound calls
  • OPENAI_STORE_RESPONSES=false keeps Responses API calls privacy-first by default
  • OPENAI_RESPONSES_MODEL, OPENAI_EMBEDDINGS_MODEL, and OPENAI_REALTIME_MODEL can be changed per application or per request

Gemini

  • GEMINI_API_KEY
  • GEMINI_API_BASE_URL
  • GEMINI_GENERATION_MODEL
  • GEMINI_EMBEDDINGS_MODEL
  • GEMINI_TIMEOUT
  • GEMINI_CONNECT_TIMEOUT

Notes:

  • GEMINI_API_KEY is required only when using GeminiClient outbound calls
  • GEMINI_GENERATION_MODEL and GEMINI_EMBEDDINGS_MODEL can be changed per application or per request

Claude

  • CLAUDE_API_KEY
  • CLAUDE_API_BASE_URL
  • CLAUDE_MESSAGES_MODEL
  • CLAUDE_API_VERSION
  • CLAUDE_MAX_TOKENS
  • CLAUDE_TIMEOUT
  • CLAUDE_CONNECT_TIMEOUT

Notes:

  • CLAUDE_API_KEY is required only when using ClaudeClient outbound calls
  • CLAUDE_API_VERSION configures the required Anthropic API version header
  • CLAUDE_MAX_TOKENS is the default output cap when callers omit max_tokens

Resend

  • RESEND_API_KEY
  • RESEND_API_BASE_URL
  • RESEND_FROM_ADDRESS
  • RESEND_FROM_NAME
  • RESEND_WEBHOOK_SECRET
  • RESEND_TIMEOUT
  • RESEND_CONNECT_TIMEOUT

Notes:

  • RESEND_API_KEY is required only when using ResendMailer outbound calls
  • RESEND_FROM_ADDRESS and RESEND_FROM_NAME provide the default sender identity
  • RESEND_WEBHOOK_SECRET is required only for signed webhook verification

Cloudflare Turnstile

  • CLOUDFLARE_TURNSTILE_SITE_KEY
  • CLOUDFLARE_TURNSTILE_SECRET_KEY
  • CLOUDFLARE_TURNSTILE_VERIFY_URL
  • CLOUDFLARE_TURNSTILE_RESPONSE_FIELD
  • CLOUDFLARE_TURNSTILE_TIMEOUT
  • CLOUDFLARE_TURNSTILE_CONNECT_TIMEOUT

Notes:

  • CLOUDFLARE_TURNSTILE_SITE_KEY is used by CloudflareTurnstile to render browser widgets
  • CLOUDFLARE_TURNSTILE_SECRET_KEY is required only for server-side token validation
  • CLOUDFLARE_TURNSTILE_RESPONSE_FIELD defaults to the standard Turnstile field posted by implicit widgets
  • Turnstile works independently from Cloudflare CDN usage

Meilisearch

  • MEILISEARCH_HOST
  • MEILISEARCH_API_KEY
  • MEILISEARCH_DEFAULT_INDEX
  • MEILISEARCH_TIMEOUT
  • MEILISEARCH_CONNECT_TIMEOUT
  • MEILISEARCH_SEARCH_LIMIT

Notes:

  • MEILISEARCH_HOST points MeilisearchClient to the Meilisearch instance
  • MEILISEARCH_API_KEY is optional only for unsecured local development instances
  • MEILISEARCH_DEFAULT_INDEX is used by read-model sync when an index is not passed explicitly
  • MEILISEARCH_SEARCH_LIMIT applies only when a search call does not pass explicit pagination

Web Push (VAPID)

  • PUSH_VAPID_PUBLIC
  • PUSH_VAPID_PRIVATE
  • PUSH_VAPID_SUBJECT

Notes

  • Keep secrets in .env, not in Git.
  • Keep numeric/boolean values unquoted if you want automatic type casting.
  • Keep APP_ENV aligned with your deployment target (development/staging/production).
  • Use environment-specific .env values for local/staging/production.
  • Keep GOOGLE_MAPS_API_KEY server-side only and use a browser-restricted key for GOOGLE_MAPS_BROWSER_API_KEY.
  • Keep WHATSAPP_CLOUD_ACCESS_TOKEN and WHATSAPP_CLOUD_APP_SECRET server-side only.
  • Keep CLOUDFLARE_TURNSTILE_SECRET_KEY server-side only and validate tokens before public writes.
  • Keep MEILISEARCH_API_KEY server-side only and index only fields that are safe to expose in search results.
  • Keep observability exporter credentials server-side only and avoid sending request bodies or secrets in telemetry attributes.
  • Tune API limits by traffic class and verify 429 handling in clients.

See also: Env, API, RateLimiter, ThrottleMiddleware, Request, CloudflareTurnstile, MeilisearchClient.