Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/UAnirudh/IntelliPlan/llms.txt

Use this file to discover all available pages before exploring further.

IntelliPlan is configured entirely through environment variables — there is no GUI settings panel and no config file committed to the repository. In local development, copy .env.example to .env (which is gitignored) and fill in real values. On Railway, Render, or any other PaaS, set these as dashboard environment variables rather than committing them. The sections below cover every variable IntelliPlan reads, what happens when one is absent, and where to get the value.
Never commit .env or any file containing real secrets to version control. The .env.example file in the repository is a safe template — all sensitive values are blank or set to placeholder strings.

Core

These four variables must be set in every environment. The application will start without them but will be insecure or non-functional.
SECRET_KEY
string
required
Flask’s cryptographic signing key. Used for session cookies, CSRF tokens, and any other signed value. Set this to a long, random string and never reuse it across deployments. Generate one with:
python -c "import secrets; print(secrets.token_hex(32))"
APP_BASE_URL
string
required
The canonical origin of the deployment, e.g. https://intelliplan.tech. Used to construct absolute URLs in emails, OAuth redirect URIs, push notification endpoints, and the IndexNow key file path. Include the scheme; omit the trailing slash.
DATABASE_URL
string
required
SQLAlchemy connection string. Defaults to sqlite:///intelliplan.db in the template, which is fine for local development. For production, use a Postgres URL such as postgresql://user:pass@host/dbname.
PORT
integer
default:"3000"
The port Gunicorn binds to. Most PaaS hosts inject this automatically; the value in .env is only needed for local runs.

Admin

ADMIN_EMAILS
string
Comma-separated list of email addresses that can access the admin panel at the path defined by ADMIN_PATH. Example: uanirudh0811@gmail.com. Users not on this list are rejected with 403.
ADMIN_PATH
string
default:"/admin-x9k2p7"
The URL path for the admin panel. The default is intentionally obscure. Change it to something secret for your deployment and keep it out of public documentation.

AI — Model Keys

GEMINI_API_KEY
string
required
API key for Google Gemini, IntelliPlan’s primary AI provider. Get one at aistudio.google.com/apikey. The free tier allows 20 requests per day on gemini-2.5-flash; once that quota is spent every AI feature stops unless a Groq fallback key is also set. See AI Providers for the full fallback chain.
GROQ_API_KEY
string
required
API key for Groq, IntelliPlan’s fallback AI provider. Strongly recommended even though it is technically optional — without it, exhausting the Gemini free-tier quota takes down all AI features. Get a free key at console.groq.com/keys.
ANTHROPIC_API_KEY
string
API key for Anthropic Claude. Only ever called for accounts on the paid plan — leaving this unset simply drops Claude from the provider chain. If set, paid users receive Claude Sonnet for standard tasks and Claude Haiku for fast tasks.
PAID_USER_EMAILS
string
Comma-separated list of email addresses that receive paid-plan AI access before a formal billing system exists. Useful for beta testers and team members.
GROQ_AUDIO_KEY
string
A dedicated Groq API key for speech transcription (Whisper). Speech requests run against this key so that a long voice session cannot exhaust the key used for text answers. Falls back to GROQ_API_KEY when unset.
GROQ_VISUAL_API_KEY
string
A dedicated Groq API key for image/vision requests. Falls back to GROQ_API_KEY when unset.
FISH_AUDIO_KEY
string
API key for Fish Audio, which powers Plani’s read-aloud voice feature. Get a key at fish.audio. Without this key the read-aloud button is hidden.
POLLINATIONS_API_KEY
string
Server-side sk_ secret key for Pollinations, used for AI image, video, and 3D generation. Obtain one at enter.pollinations.ai/keys. This must be a secret key — a publishable pk_ key in server code would allow anyone to spend the balance.

AI Firewall — Rate Limits

All limits are optional. When unset, the defaults shown below apply. Counters are stored in the database (not in process memory) so they survive deploys and are shared across multiple instances.
Rate limits are per account for signed-in users, and per signed device cookie for guests. A guest keeps their identity across IP changes, so a school behind one NAT address is not treated as a single student.
VariableDefaultDescription
AI_GUEST_RPH4Requests per hour
AI_GUEST_RPD8Requests per day
AI_GUEST_TPD12000Estimated tokens per day
AI_GUEST_MAX_OUTPUT1200Maximum output tokens per request
AI_KILL_SWITCH
string
Set to 1 to disable every AI feature site-wide without a deploy. Useful for cost emergencies or provider outages. Unset or set to 0 to re-enable.

Google OAuth + Calendar

GOOGLE_CLIENT_ID
string
required
OAuth 2.0 Client ID from Google Cloud Console. Used for “Sign in with Google” and Google Calendar sync.
GOOGLE_CLIENT_SECRET
string
required
OAuth 2.0 Client Secret matching GOOGLE_CLIENT_ID.
GOOGLE_REDIRECT_URI
string
required
Must be registered in Google Cloud Console and match byte-for-byte. Default: https://intelliplan.tech/oauth2callback.

Notion OAuth

NOTION_CLIENT_ID
string
Client ID from a public Notion integration created at app.notion.com/developers/connections. A public connection (not an internal integration) is required for users to authorize IntelliPlan to read their Notion workspace.
NOTION_CLIENT_SECRET
string
Client secret for the Notion integration.
NOTION_REDIRECT_URI
string
Must be registered in the Notion integration’s OAuth configuration and match byte-for-byte — Notion rejects the token exchange otherwise. Default: https://intelliplan.tech/oauth/notion/callback. Add a second redirect URI for local development if needed (e.g. http://localhost:5000/oauth/notion/callback).

Canvas OAuth

CANVAS_CLIENT_ID
string
Developer Key ID from Canvas (canvas.instructure.com for the public instance, or a school’s own Canvas host). See .env.example for step-by-step instructions on registering a Developer Key.
CANVAS_CLIENT_SECRET
string
Developer Key secret matching CANVAS_CLIENT_ID.
CANVAS_REDIRECT_URI
string
Default: https://intelliplan.tech/oauth/canvas/callback. Must match the Developer Key registration exactly.
CANVAS_DEFAULT_BASE
string
default:"https://canvas.instructure.com"
Base URL for the public Canvas instance. For schools with a self-hosted Canvas, set per-institution overrides using the pattern CANVAS_CLIENT_ID_<HOST_UPPERCASE> and CANVAS_CLIENT_SECRET_<HOST_UPPERCASE>, replacing dots and dashes with underscores.

Google Classroom

GOOGLE_CLASSROOM_CLIENT_ID
string
OAuth 2.0 Client ID for Google Classroom. Separate from the Google Calendar credentials — Classroom requires its own OAuth consent screen scope.
GOOGLE_CLASSROOM_CLIENT_SECRET
string
Client secret for Google Classroom OAuth.

Blackboard Learn OAuth

Blackboard uses a three-legged (3LO) OAuth flow. Three distinct values are issued by the Anthology developer portal — they are not interchangeable. Run python scripts/blackboard_doctor.py to validate your configuration without printing any secret values.
BLACKBOARD_APP_KEY
string
The UUID sent as OAuth client_id. This is not the Application ID — confusing the two causes Blackboard to return {"code":"illegalArgument","message":"invalid client_id"} after the student has already signed in.
BLACKBOARD_APP_SECRET
string
The secret matching BLACKBOARD_APP_KEY.
BLACKBOARD_APPLICATION_ID
string
The UUID the school’s Blackboard administrator must add under System Admin → Integrations → REST API Integrations with End User Access set to Yes. IntelliPlan shows this value to students whose school has not yet approved the integration so they can hand it to their admin.
BLACKBOARD_SCOPE
string
default:"read offline"
OAuth scopes. offline is required — without it Blackboard issues no refresh token and every connection dies at the first expiry (approximately one hour).
BLACKBOARD_REDIRECT_URI
string
Default: https://intelliplan.tech/api/lms/callback/blackboard. Must match the developer portal registration byte-for-byte.

Moodle

MOODLE_ENABLED
integer
default:"1"
Set to 0 to hide the Moodle integration in the Connect screen while an institution is not ready to issue web-service tokens. Does not affect existing connections.

Email — Resend (Preferred)

RESEND_API_KEY
string
required
API key from resend.com/api-keys. When set, Resend is used for all outgoing email. See Email Configuration for domain setup.
RESEND_FROM
string
default:"IntelliPlan <noreply@intelliplan.tech>"
The From address for all emails sent via Resend. Must use a domain verified in your Resend account. For the recommended subdomain setup, use IntelliPlan <noreply@send.intelliplan.tech>.

Email — SMTP Fallback

Used only when RESEND_API_KEY is not set.
SMTP_HOST
string
Hostname of the SMTP server (e.g. smtp.gmail.com).
SMTP_PORT
integer
default:"587"
SMTP port. 587 (STARTTLS) is the standard for most providers.
SMTP_USER
string
SMTP username, usually the sending email address.
SMTP_PASSWORD
string
SMTP password. For Gmail, create an App Password at myaccount.google.com/apppasswords — spaces are stripped automatically.
SMTP_FROM
string
The From address when using SMTP. Defaults to SMTP_USER when unset.

Lifecycle Email — Reply Routing

MARKETING_POSTAL_ADDRESS
string
required
Physical postal address printed in the footer of every marketing email (newsletter, feedback request). Required by CAN-SPAM §7704(a)(5). With this unset, newsletter and feedback sends refuse to run and log loudly. A PO box or registered agent’s address is acceptable. See Email Configuration for details.
MARKETING_REPLY_TO
string
required
Where student replies to lifecycle emails actually land. Must be a mailbox that receives email — a send-only domain silently bounces every reply. Use a Gmail address or any working inbox until the sending domain has MX records.
SUPPORT_EMAIL
string
Support contact address printed in email bodies as a mailto: link. Falls back to MARKETING_REPLY_TO when unset.

Push Notifications (VAPID)

VAPID_PUBLIC_KEY
string
required
Base64url-encoded uncompressed ECDH public key. Generate once with python vapid.py. See Push Notifications for full setup instructions.
VAPID_PRIVATE_KEY
string
required
Base64url-encoded raw 32-byte ECDH private key. Treat like a password — rotating it invalidates every existing browser subscription.
VAPID_EMAIL
string
required
An email address a push service can reach you at. Sent as the sub claim in the VAPID JWT; some services (notably FCM) reject pushes that lack it.

Cron

CRON_SECRET
string
required
Shared secret that authorizes calls to all cron endpoints (/cron/notifications, /cron/send-reminders, /cron/lifecycle-emails, /cron/weekly-newsletter). Pass as the X-Cron-Token or X-Cron-Secret header, or as a ?secret= query parameter. Without this set, every cron endpoint returns 503 and nothing is ever delivered.

Sentry

SENTRY_DSN
string
Data Source Name from your Sentry project. When set, unhandled exceptions and errors are reported to Sentry. Leaving this unset disables error reporting entirely — the application functions normally without it.

Encryption at Rest

DATA_ENCRYPTION_KEY
string
required
Fernet key used to encrypt all third-party OAuth tokens stored in the database (Canvas, Google, Notion, Blackboard, Moodle). Without it those tokens are stored in plaintext. Generate a key with:
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
To rotate: put the new key first, comma-separated (new,old). Values are decrypted with any listed key and always written with the first. Then run scripts/encrypt_existing_tokens.py. Losing this key is not recoverable — affected students must reconnect their accounts.

reCAPTCHA

RECAPTCHA_SITE_KEY
string
Public site key from google.com/recaptcha/admin. Both RECAPTCHA_SITE_KEY and RECAPTCHA_SECRET_KEY must be set or the check remains off entirely.
RECAPTCHA_SECRET_KEY
string
Secret key for server-side verification. Never expose this in client-side code.
RECAPTCHA_VERSION
string
default:"v2"
Which reCAPTCHA widget to render. v2 draws a checkbox; v3 is invisible and score-based. This must match the type of key you registered — a mismatch causes the widget to not appear at all.
RECAPTCHA_SCORE_THRESHOLD
number
default:"0.5"
v3 only. Google’s default is 0.5. Setting this too high causes real students on shared or VPN’d connections to be refused. Verification fails open if Google is unreachable — a Google outage will not cause an IntelliPlan outage.

Analytics

IntelliPlan loads no third-party analytics script in the browser. Product usage is measured server-side via PostHog, which sets no browser cookie. Microsoft Clarity was removed to honour the privacy promise made to schools. Any analytics added in future must be declared in cookie_policy.py and gated on consent.

IndexNow

INDEXNOW_KEY
string
IndexNow key served at /<key>.txt. Used to notify participating search engines (Bing, Yandex) when public URLs change. The default value in .env.example is the live production key.
INDEXNOW_KEY_LOCATION
string
Full URL to the key file, e.g. https://intelliplan.tech/15d38c49db0d48efa4ec2ad2635b43c9.txt.
INDEXNOW_ENDPOINT
string
default:"https://api.indexnow.org/indexnow"
IndexNow submission endpoint.

Build docs developers (and LLMs) love