Platform
ScaiWave ScaiGrid ScaiCore ScaiBot ScaiDrive ScaiKey Models Tools & Services
Solutions
Organisations Developers Internet Service Providers Managed Service Providers AI-in-a-Box
Resources
Support Documentation Blog Downloads
Company
About Research Careers Investment Opportunities Contact
Log in

Quickstart

Get a local ScaiControl running end-to-end in about 15 minutes. By the end you'll have:

  • A running backend on :8000 with the OpenAPI Swagger UI.
  • A running portal on :5173.
  • A registered ScaiKey app + a super-admin user.
  • One service in the catalog, one trial subscription, one finalised invoice.

For production deployment, see the operator runbook (separate from this guide).

Prerequisites#

Tool Version
Python 3.12+
Node.js 20+
MariaDB (or use aiosqlite for dev) 10.11+
Redis 7+
ScaiKey instance Reachable URL with operator account

You also need:

  • An S3-compatible bucket (MinIO works locally) — for invoice PDFs and uploads.
  • Operator access to a ScaiSend instance (or accept that emails will be logged-only).

1. Clone & install backend#

bash
1
2
3
4
5
git clone <your-fork> scaicontrol
cd scaicontrol/backend
python3.12 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

2. Configure environment#

Create .env at the repo root (one level up from backend/):

bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
DATABASE_URL=mysql+asyncmy://scaicontrol:secret@localhost/scaicontrol
REDIS_URL=redis://localhost:6379/0
PORTAL_URL=http://localhost:5173
API_URL=http://localhost:8000

S3_BUCKET=scaicontrol-dev
S3_REGION=us-east-1
S3_ENDPOINT_URL=http://localhost:9000   # MinIO
S3_ACCESS_KEY_ID=minio
S3_SECRET_ACCESS_KEY=minio12345

OPERATOR_LEGAL_NAME=ScaiLabs Demo Co.

SCAIKEY_*, SCAISEND_*, payment provider keys — leave blank for now; we'll populate them via the CLI in step 4 (or set them inline if you already have credentials).

3. Run migrations#

bash
1
2
cd backend
alembic upgrade head

Should print "Running upgrade … 008_eu_invoicing" (or later) and exit clean.

4. Register with ScaiKey#

bash
1
2
3
4
scaicontrol setup register \
  --scaikey-url https://scaikey.scailabs.ai \
  --url http://localhost:8000 \
  --email you@example.com

This submits a registration request. An operator approves it in ScaiKey. Then:

bash
1
scaicontrol setup status

Repeat until APPROVED. The CLI writes SCAIKEY_CLIENT_ID, SCAIKEY_CLIENT_SECRET, SCAIKEY_APP_ID, and SCAIKEY_ISSUER to .env.

5. Sync users + assign super_admin#

bash
1
2
scaicontrol sync                # pulls users from ScaiKey
scaicontrol admin grant --email you@example.com --role super_admin

You now exist locally with full bypass on require_permission() checks.

6. Start backend + worker + frontend#

In three terminals:

bash
1
2
3
# Terminal 1 — API server
cd backend
uvicorn scaicontrol.main:app --reload --host 0.0.0.0 --port 8000
bash
1
2
3
# Terminal 2 — background worker (cron jobs, webhook dispatch, dunning)
cd backend
arq scaicontrol.workers.main.WorkerSettings
bash
1
2
3
4
# Terminal 3 — portal
cd frontend
npm install
npm run dev

Visit:

  • http://localhost:5173 — portal (you'll redirect through ScaiKey to log in).
  • http://localhost:8000/docs — Swagger UI (interactive API explorer).

7. Make your first API call#

Grab a JWT by logging in through the portal, then open browser DevTools → Application → Local Storage → copy the access_token. Or use curl with ScaiKey's /oauth/token directly.

bash
1
2
3
4
TOKEN=eyJhbGc...

curl -H "Authorization: Bearer $TOKEN" \
     http://localhost:8000/api/v1/auth/me

Expected: a JSON CurrentUser payload with your roles and permissions.

8. Add a service to the catalog#

Either via the portal (/admin/registry) or API:

bash
1
2
3
4
5
6
7
8
9
curl -X POST http://localhost:8000/api/v1/admin/registry \
     -H "Authorization: Bearer $TOKEN" \
     -H "Content-Type: application/json" \
     -d '{
       "slug": "scaikey",
       "name": "ScaiKey",
       "base_url": "https://scaikey.scailabs.ai",
       "description": "Identity & access management"
     }'

Approve it (auto-approved if its slug is in AUTO_APPROVED_APP_IDS):

bash
1
2
curl -X POST http://localhost:8000/api/v1/admin/registry/{id}/approve \
     -H "Authorization: Bearer $TOKEN"

9. Add a plan#

bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
curl -X POST http://localhost:8000/api/v1/admin/plans \
     -H "Authorization: Bearer $TOKEN" \
     -H "Content-Type: application/json" \
     -d '{
       "service_slug": "scaikey",
       "plan_key": "scaikey.starter",
       "name": "Starter",
       "monthly_price_cents": 1900,
       "currency": "EUR",
       "billing_period": "monthly"
     }'

10. Subscribe (as a tenant) and finalise an invoice#

This part assumes you have a tenant in ScaiKey already synced via step 5. From the portal:

  1. Switch to the tenant context.
  2. Open /services, find "ScaiKey", click "Subscribe → Starter".
  3. As the operator, open /admin/billing, find the auto-generated draft invoice for this month, click Finalize.
  4. Click Send — the invoice PDF is now in S3 and the customer gets an email (or a log entry if ScaiSend isn't configured).

You now have a working end-to-end flow: catalog → subscription → invoice → PDF in S3.

Next steps#

  • Understand the model — read Concepts: architecture and Multi-tenancy.
  • Wire up payments — set STRIPE_API_KEY etc. and a webhook endpoint; see the catalog page for your provider in API reference.
  • Subscribe to webhooks — register a subscriber at /admin/webhook-subscriptions; consume events.
  • Customise invoice branding/admin/billing/templates → GrapesJS designer; see Concepts: templates.
  • Run the integration test suitecd backend && pytest.

Common first-run issues#

Problem Fix
alembic upgrade head errors with "Access denied" Wrong DATABASE_URL. For dev without MariaDB: DATABASE_URL=sqlite+aiosqlite:///./dev.db
setup status always pending Operator hasn't approved in ScaiKey yet, OR SCAIKEY_ISSUER is unreachable
Portal redirects to ScaiKey then 404s Check SCAIKEY_CLIENT_ID is set in .env AND in the ScaiKey app config; the redirect URI must match exactly
Invoice finalize 500s See Troubleshooting: invoice not finalising
Worker process exits immediately Redis isn't reachable, or REDIS_URL is wrong
Updated 2026-05-18 01:48:39 View source (.md) rev 3