Common Issues
Troubleshooting
Solutions to the most common issues encountered during setup, development, and deployment of KaiVox AI.
Dashboard Shows Negative Trial Days
Fixed. This was caused by a null trial_ends_at in the subscriptions table. The dashboard now guards against null values before computing the difference.
If you encounter this again, check the subscriptions table for the affected tenant and ensure trial_ends_at is set correctly (14 days from the subscription created_at).
Dashboard Checklist Items Showing False
The onboarding checklist on the dashboard checks for: at least one service, at least one staff member, a phone number, and a working AI connection. If any item shows false:
- Services: Go to Services → Add at least one service
- Staff: Go to Staff → Add at least one staff member
- Phone number: Go to Phone Numbers → Purchase or manually add a number
- AI connected: Ensure
OPENAI_API_KEY is set in .env
AI Not Responding on Calls
| Symptom | Cause | Fix |
| Call answered but AI is silent | OPENAI_API_KEY missing or invalid | Check .env; test key at platform.openai.com |
| AI answers but gives generic error | Failover triggered — OpenAI returned error | Check ai_action_logs table for event_type = failover_activated |
| AI gives wrong business info | Knowledge Brain empty | Add FAQ and business info at Knowledge → Add Item |
| AI uses wrong greeting | AI Persona not configured | Settings → AI Persona → set greeting message |
| AI doesn't book appointments | No services or staff configured | Add at least one service and one staff member with working hours |
Webhook Not Firing (Vobiz / Twilio)
| Symptom | Cause | Fix |
| Call goes through but no AI answer | Answer URL not set in provider dashboard | Check Vobiz or Twilio Console — set Answer URL to the correct tenant slug URL |
| Answer URL set but unreachable | Using localhost URL — not publicly accessible | Use ngrok tunnel or test on staging server; local .test domain is not reachable from the internet |
| Wrong slug in URL | Tenant slug mismatch | Find your slug on the Dashboard page under "Your Webhook URLs". Copy it exactly. |
| SSL error on webhook | Self-signed cert or HTTP URL | Vobiz and Twilio require HTTPS with a valid SSL certificate. Use staging domain which has a real cert. |
| Webhook 500 error | Server error in KaiVox | Check storage/logs/laravel.log on the server for the stack trace |
SMS Not Sending
| Symptom | Cause | Fix |
| SMS not sent after booking | Twilio credentials missing | Set TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, TWILIO_FROM_NUMBER in .env |
| SMS delivered but from wrong number | TWILIO_FROM_NUMBER wrong format | Must be E.164 format: +12025551234 — include country code with + |
| SMS to Indian numbers failing | Twilio number not SMS-enabled for India | Use Vobiz for India SMS, or enable India delivery in Twilio Console |
| SMS job queued but not processing | Queue worker not running | Run php artisan queue:work locally; on server check if the queue daemon is running |
| WhatsApp not delivered | Sandbox not joined by recipient | For Twilio sandbox, recipient must have joined the sandbox first. Not needed for production WhatsApp. |
Google Calendar Not Connecting
Known limitation: Google Calendar OAuth cannot be tested on localhost (http://kaivox-ai.test). Google rejects it as an invalid redirect URI. Must be tested on staging or production.
| Symptom | Cause | Fix |
| "Invalid redirect" error from Google | Using localhost or .test domain | Test on staging (kaivox-test.omajestic.com) only |
| Connect button does nothing | GOOGLE_CLIENT_ID not set | Settings shows "coming soon" message when creds are missing — expected behaviour |
| OAuth returns error after consent | GOOGLE_REDIRECT_URI mismatch | URI in .env must exactly match what is registered in Google Cloud Console |
| Events not appearing in Google Calendar | Token expired and refresh failed | Disconnect and reconnect Google Calendar to get a fresh token |
Emails Not Sending
Local limitation: SMTP ports 587 and 465 are blocked by local ISP/Windows Firewall. Emails will not send from local development. This is intentional and documented.
- Local dev fix: Set
MAIL_MAILER=log to see emails in storage/logs/laravel.log, or install Mailpit to catch emails at localhost:8025
- On staging/production: Hostinger SMTP works fine. Set
MAIL_MAILER=smtp and fill all MAIL_* variables in .env
- Queue not running: Email jobs are queued. Run
php artisan queue:work or check the queue daemon is running on the server
Stripe / Razorpay Payment Not Credited
| Symptom | Fix |
| Stripe checkout completes but wallet not updated | Check Laravel logs for errors in BillingController::stripeSuccess(). Ensure STRIPE_SECRET is set correctly. |
| Razorpay signature verification fails | Check RAZORPAY_SECRET matches exactly what is in Razorpay Dashboard → Settings → API Keys |
| Test payment rejected | Ensure you are using test keys (pk_test_, rzp_test_) — live keys reject test card numbers |
Migrations Failing
| Error | Fix |
SQLSTATE: 1071 Specified key was too long | Add Schema::defaultStringLength(191); in AppServiceProvider::boot() |
Class not found during seeding | Run composer dump-autoload first |
| Migration rolls back unexpectedly | Check storage/logs/laravel.log for the specific error. Common cause: duplicate column or missing foreign key table. |
php artisan migrate uses wrong PHP version | Use full path: D:\xampp\php82\php.exe artisan migrate |
Kiosk / Public Profile Not Loading
| Symptom | Fix |
/kiosk/{slug} shows 404 | Tenant slug must match exactly — check tenants.slug in DB |
/p/{slug} shows 404 | Same — verify tenant slug. The route is GET /p/{slug} registered in web.php |
| Profile shows "hidden" badge | Tenant has set profile visibility to "hidden" — Settings → Public Profile → make it Public |
| Cover photo not showing | Run php artisan storage:link to create the symlink from public/storage to storage/app/public |
Queue Jobs Stuck / Not Processing
- Run
php artisan queue:work in a terminal — it must keep running
- Check
jobs table in database for stuck jobs
- Run
php artisan queue:flush to clear failed jobs if needed
- On production (Hostinger), set up a supervisor or cron to restart the queue worker if it dies
Getting More Debug Info
- Set
APP_DEBUG=true temporarily (never on production) to see full error stack traces
- Check
storage/logs/laravel.log — this is the first place to look for any error
- Check
ai_action_logs table for AI-related errors
- Check
webhook_deliveries table for outbound webhook delivery failures
- Check
failed_jobs table for queue job failures