CallMineAI Docs
Home
  • Introduction
  • Architecture
  • Installation
  • Configuration
  • Deployment
  • Customer panel
  • Admin panel
  • Agents & Voices
  • Campaigns & Calls
  • Billing & Credits
  • Telephony (Twilio)
  • Voice & AI
  • SIP trunks
  • Messaging
  • REST API
Home
  • Introduction
  • Architecture
  • Installation
  • Configuration
  • Deployment
  • Customer panel
  • Admin panel
  • Agents & Voices
  • Campaigns & Calls
  • Billing & Credits
  • Telephony (Twilio)
  • Voice & AI
  • SIP trunks
  • Messaging
  • REST API
  • Getting started

    • Introduction
    • Architecture
    • Installation
    • Configuration
    • Deployment
  • Using CallMineAI

    • Customer Guide
    • Agents & Voices
    • Campaigns & Calls
    • Billing & Credits
  • Administration

    • Admin Guide
    • Roles & permissions
    • Localization
  • Integrations

    • Telephony (Twilio)
    • Voice & AI
    • SIP trunks
    • Messaging
    • REST API
  • Help

    • FAQ & troubleshooting

Deployment

Production hosting for CallMineAI. Assumes you've completed Installation and Configuration.

Build for production

npm ci
npx prisma db push        # or: npm run db:migrate
npm run build             # prisma generate + next build
npm start                 # serves on PORT (default 3000)

Recommended production .env:

APP_ENV=production
APP_DEBUG=false
APP_URL=https://your-domain.com
NEXT_PUBLIC_APP_URL=https://your-domain.com
AUTH_SECRET=<32+ random chars>
CRON_SECRET=<32+ random chars>

HTTPS is mandatory

Twilio (and SIP/WhatsApp) webhooks require a publicly reachable HTTPS URL. Set APP_URL to your HTTPS domain so the callback URLs resolve correctly.

Keep the app alive (PM2 or systemd)

npm start is a long-running Node process. Supervise it.

PM2:

pm2 start "npm start" --name callmineai --cwd /path/to/callmineai
pm2 start "npm run worker" --name callmineai-worker --cwd /path/to/callmineai
pm2 save && pm2 startup

systemd (/etc/systemd/system/callmineai.service):

[Unit]
Description=CallMineAI (Next.js)
After=network.target mysql.service

[Service]
Type=simple
WorkingDirectory=/path/to/callmineai
EnvironmentFile=/path/to/callmineai/.env
ExecStart=/usr/bin/npm start
Restart=always
User=www-data

[Install]
WantedBy=multi-user.target

Scheduled tasks

The dialer needs the scheduled tasks running. Pick one of the three:

1. The bundled worker — one supervised process, no cron config:

npm run worker

2. Crontab — POST the endpoints directly:

*     * * * * curl -fsS -X POST -H "X-Cron-Secret: $CRON_SECRET" https://your-domain.com/api/cron/dispatch      > /dev/null
*/5   * * * * curl -fsS -X POST -H "X-Cron-Secret: $CRON_SECRET" https://your-domain.com/api/cron/reap-stuck    > /dev/null
0 2   * * * curl -fsS -X POST -H "X-Cron-Secret: $CRON_SECRET" https://your-domain.com/api/cron/grant-monthly   > /dev/null
0 3   * * * curl -fsS -X POST -H "X-Cron-Secret: $CRON_SECRET" https://your-domain.com/api/cron/sync-subscriptions > /dev/null

3. A hosted scheduler — cron-job.org, Upstash QStash, GitHub Actions, or any service that can send an HTTP request on a schedule. Configure each job as POST with the X-Cron-Secret header, same URLs as above.

Vercel Cron needs a small change

Vercel Cron issues a GET and authenticates with Authorization: Bearer $CRON_SECRET. /api/cron/[task] exports POST only and reads X-Cron-Secret, so a vercel.json crons entry returns 405/401 as shipped. On Vercel, use an external scheduler (option 3) or add a GET export + bearer check to src/app/api/cron/[task]/route.js.

Verify it's wired

POST /api/cron/heartbeat with the same secret returns 200 when the schedule can reach the app. Without a running schedule, campaigns queue calls but nothing dials — see Campaigns & Calls.

Reverse proxy

Next.js serves HTTP itself; terminate TLS in front of it. Nginx example:

server {
    listen 443 ssl;
    server_name your-domain.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade           $http_upgrade;
        proxy_set_header Connection        "upgrade";
    }
}

Serverless notes (Vercel)

The app runs on Vercel with two caveats:

  • Uploads — KB documents and KYC files write to storage/app on local disk. Serverless filesystems are ephemeral, so point uploads at object storage (or run on a VPS) before going live.
  • Database connections — use a pooled DATABASE_URL so Prisma does not exhaust MySQL connections across lambdas.

Go-live checklist

  • [ ] APP_ENV=production, APP_DEBUG=false
  • [ ] npm run build succeeds; npm start (or Vercel) serving
  • [ ] HTTPS enabled; APP_URL and NEXT_PUBLIC_APP_URL set to the HTTPS domain
  • [ ] AUTH_SECRET and CRON_SECRET are long random values, not the defaults
  • [ ] APP_KEY copied verbatim if the database holds Laravel-encrypted credentials
  • [ ] Scheduled tasks running (worker, crontab or Vercel Cron) and heartbeat returns 200
  • [ ] Twilio status/recording callback URLs publicly reachable
  • [ ] Changed the default seed passwords
  • [ ] ElevenLabs key added + voices synced; OpenAI key set
  • [ ] Payment gateways configured (if selling subscriptions)
  • [ ] A backup strategy for the database and storage/

After deploying updates

git pull
npm ci
npx prisma db push          # only when the schema changed
npm run build
pm2 restart callmineai callmineai-worker
Last Updated: 8/15/26, 10:14 AM
Prev
Configuration