Hand-off document for whoever flips Phase 1 on. The code is in production today as preview-mode stubs; this page lists everything that has to happen outside the source tree to switch real LLM responses on. The site is engineered so this is the only ritual — no further C# changes are required.
Deploy-time steps
1. Provision the AI schema
Run App_Data/CreateAITables.sql against the production database. The script is idempotent (uses IF NOT EXISTS guards) so re-running is safe. Creates:
AISubscription — one row per active AI tier subscription.
AIUsage — per-action audit row, written by AIService.RecordSuccess.
AIDisable — account-level kill switch (one row = AI off for that account, with a Reason string).
AIAccountKey — encrypted account-level OpenAI or Claude key for BYO-key calls.
vw_AIMonthlyUsage — aggregated view over AIUsage grouped by AccountID + first-of-month.
Verify: hit /dashboard/AIUsage.aspx as any logged-in user. Banner should switch from "AI schema not yet provisioned" to "no active subscription" (the schema-present-no-subscription state).
2. Configure the LLM provider
Add to Web.config <appSettings>:
<add key="JSOAI.Provider" value="claude" />
<add key="JSOAI.ClaudeApiKey" value="sk-ant-..." />
<!-- Optional: model override; defaults to claude-sonnet-4-5 (AIService.DEFAULT_CLAUDE_MODEL). -->
<add key="JSOAI.ClaudeModel" value="claude-sonnet-4-5" />
For OpenAI:
<add key="JSOAI.Provider" value="openai" />
<add key="JSOAI.OpenAIApiKey" value="sk-..." />
<!-- Optional: defaults to gpt-5 (AIService.DEFAULT_OPENAI_MODEL). -->
<add key="JSOAI.OpenAIModel" value="gpt-5" />
If you want to test the wiring without a site-wide API key, leave JSOAI.Provider on preview (or remove the provider key entirely). The endpoints stay up; they just keep returning the rule-based preview envelopes. Individual dashboard accounts can also save encrypted OpenAI or Claude keys at /dashboard/AISettings.aspx.
3. Flip the global enable flag
In AIService.cs there is a single IsGloballyEnabled property. Today it returns false via the JSOAI.Enabled appSetting (default off). Add:
<add key="JSOAI.Enabled" value="true" />
This flag controls the site-wide managed AI path. Accounts with an encrypted BYO provider key can still run live AI when managed AI is globally disabled, so use AIDisable or remove the account provider key when the goal is to stop a specific account. Accounts with no provider key fall back to preview behavior.
4. Configure Stripe billing
The handlers /v1/ai/checkout-create.ashx and /v1/ai/stripe-webhook.ashx ship as Phase 1 code, but checkout must stay disabled until Stripe products, prices, and webhook verification are ready. Keep this setting false until the billing surface is live:
<add key="JSOAI.ManagedBillingEnabled" value="false" />
When managed billing is enabled, the handlers use the existing site-wide Stripe settings by default:
<add key="StripeSecureKey" value="sk_live_..." />
<add key="StripeWebhookKey" value="whsec_..." />
Optional AI-specific overrides are also supported:
<add key="StripeApiKey" value="sk_live_..." />
<add key="StripeAiBasicPriceId" value="price_..." />
<add key="StripeAiCorporatePriceId" value="price_..." />
<add key="StripeAiEnterprisePriceId" value="price_..." />
<add key="StripeAiWebhookSecret" value="whsec_..." />
In the Stripe dashboard:
- Either let
checkout-create.ashx find or create the three recurring Prices automatically by lookup key, or create Products/Prices manually (JSO AI Basic / Corporate / Enterprise) at $19, $79, $299 per month and copy each Price ID into the optional appSetting above.
- Configure a webhook endpoint at
https://www.javascriptobfuscator.com/v1/ai/stripe-webhook.ashx. Subscribe to checkout.session.completed, customer.subscription.created, customer.subscription.updated, customer.subscription.deleted. Use StripeAiWebhookSecret if you want an AI-specific secret; otherwise the handler falls back to StripeWebhookKey.
If managed billing is disabled, checkout-create.ashx returns managed_billing_disabled in a normal JSON response and the dashboard order page points users to BYO-key setup or support. If managed billing is enabled but no Stripe secret key is available, the endpoint returns checkout_not_configured. When Stripe is configured, checkout can create the missing AI Prices on first use.
5. (Optional) Seed early-access subscriptions
While Stripe billing is being provisioned, the early-access cohort gets manual subscriptions via /jsomanage/AISubscriptions.aspx (admin only). Direct SQL works too:
INSERT INTO AISubscription (AccountID, Tier, MonthlyActionsCap, MonthlyTokensCap, MonthlyCostCapCents)
VALUES (12345, 'Corporate', 500, 2000000, 30000);
6. Confirm via the config-check page
Admin-only at /jsomanage/AIConfigCheck.aspx — live mirror of this checklist. Reads every appSetting the AI / Stripe surface consumes and reports which are wired (secrets masked). One green pill = "all required appSettings configured" before you flip the global flag.
7. Run the live smoke
cd packages/jso-protector
JSO_BASE_URL=https://www.javascriptobfuscator.com npm run verify:ai-live
Expected: 7/7 PASS (preset-suggest, compat-check, explain-error, checkout-create auth-fail, stripe-webhook 405, usage, rate-limit). The 429 case is localhost-guarded and SKIPs on prod targets so we don't burn a real visitor's rate-limit bucket. If any endpoint fails, the harness message includes the upstream provider error or HTTP status — debug from there. The smoke harness uses "x" as the APIKey, so passing is "wire format intact"; confirm "real LLM calls work" by hitting the endpoint with a real Corporate APIKey and observing actionsUsed tick up.