๐Ÿ“˜ AIC-Web REST API Reference

Base URL: https://aicc-web.com ยท Everything below is usable with plain HTTP โ€” no MCP session required. AI agents and scripts welcome.

Authentication

All student endpoints (/api/me/*) accept a Bearer token in the Authorization header. Two token kinds work:

TokenHow to get itLifetime
Student API keyPortal login (username + password at POST /api/me/login), or the magic-login linkLong-lived; rotates on each password login
Paired-agent tokenDevice pairing: POST /mcp/pair โ†’ student approves โ†’ POST /mcp/exchangeLong-lived; per-agent, revocable
# Get a token with username + password
curl -X POST https://aicc-web.com/api/me/login \
  -H 'Content-Type: application/json' \
  -d '{"username":"you","password":"..."}'
# โ†’ {"api_key":"<64 hex chars>", ...}

# Use it on every call
curl https://aicc-web.com/api/me -H 'Authorization: Bearer <api_key>'
The same auth works for the MCP endpoints (/mcp, /sse) โ€” one credential, every surface.

Identity & Quotas

GET/api/meYour id, username, limits (apps, static sites, DBs, disk) and live usage
curl https://aicc-web.com/api/me -H 'Authorization: Bearer <key>'
# โ†’ { "limits": {"maxApps":1,"maxStaticSites":5,...}, "usage": {"apps":0,"staticSites":0,"databases":0,"disk_mb":0} }

Apps (Node.js process apps)

Deploy

POST/api/me/appsDeploy from a GIT repo (JSON body)
POST/api/me/apps/uploadDeploy from a ZIP (multipart: name, file + optional fields)

Common optional fields (JSON snake_case; multipart same names):

FieldMeaning
git_url / git_key / git_branchRepo to clone / SSH private key for private repos (stored encrypted, reused on redeploys) / branch to track (default: repo's default)
root_dirMonorepo: subdirectory that contains the app (e.g. apps/web)
build_commandBuild step, e.g. npm run build (installs devDeps)
release_commandRuns after build, before the process swap (e.g. npx prisma migrate deploy). Failure aborts the deploy; the old version keeps serving
start_commandDefaults to package.json scripts.start
databaseauto (provision + inject DATABASE_URL), none, or an existing DB name
env / replace_envEnv vars (JSON) / full-replace instead of merge on redeploy
# Zip upload with migrations
curl -X POST https://aicc-web.com/api/me/apps/upload \
  -H 'Authorization: Bearer <key>' \
  -F name=myapp -F file=@app.zip \
  -F build_command='npm run build' \
  -F release_command='npx prisma migrate deploy'
# โ†’ { "app_id":"...", "url":"https://myapp-you.s1.aicc-web.com", "state":"RUNNING", "port":3154 }
The platform auto-runs npx prisma generate when prisma/schema.prisma exists. Include your lockfile โ€” npm/pnpm/yarn are all installed and auto-detected.

Operate

GET/api/me/appsList your process apps (static sites excluded). Git URLs are sanitized โ€” no embedded tokens
GET/api/me/apps/:nameStatus: state, pid, port, restarts, uptime, last exit code
POST/api/me/apps/:name/redeployRedeploy a git app from its STORED git URL + branch + commands + env. No body needed
GET/api/me/apps/:name/logs?lines=50&since=last_deployLogs โ€” timestamped, merged stdout+stderr; since:last_deploy scopes to the current boot
POST/api/me/apps/:name/stop|restart|deleteLifecycle actions
GET/api/me/apps/:name/statsVisitor stats from access logs (total, unique IPs, status codes)
GET/api/me/apps/:name/diskDisk usage of the app directory (MB)

Git settings + auto-deploy webhook

GET/api/me/apps/:name/git-settingsTracked branch, autoDeploy flag, webhook URL (secret never included)
PATCH/api/me/apps/:name/git-settingsUpdate {git_branch?, auto_deploy?}
POST/api/me/apps/:name/webhook-secretGenerate/regenerate the webhook secret โ€” plaintext returned once
GET/api/me/apps/:name/webhook-secret?reveal=trueReveal the stored secret
POST/api/hooks/github/:slugPUBLIC GitHub webhook. HMAC-verified (X-Hub-Signature-256); a matching push triggers an async redeploy. Same path works for static sites

Deploy keys (private repos without sharing secrets)

POST/api/me/deploy-keysGet-or-create the platform deploy key for a repo. Body: {git_url}. Returns the PUBLIC key + paste-on-GitHub instructions
GET/api/me/deploy-keysList your deploy keys (public halves only)
DELETE/api/me/deploy-keys/:idDelete a deploy key (clones of that repo stop working)
# Private repo, no secret ever shared:
curl -X POST https://aicc-web.com/api/me/deploy-keys \
  -H 'Authorization: Bearer <key>' -H 'Content-Type: application/json' \
  -d '{"git_url":"git@github.com:me/private-repo.git"}'
# โ†’ { "public_key":"ssh-ed25519 AAAAโ€ฆ aicweb-you", "instructions":"โ€ฆ" }
# student pastes it on GitHub (Deploy keys, read-only), then:
curl -X POST https://aicc-web.com/api/me/apps \
  -H 'Authorization: Bearer <key>' -H 'Content-Type: application/json' \
  -d '{"name":"myapp","git_url":"git@github.com:me/private-repo.git"}'
# Redeploy from the stored repo (no source re-supplied)
curl -X POST https://aicc-web.com/api/me/apps/myapp/redeploy \
  -H 'Authorization: Bearer <key>'
# โ†’ { "app_id":"...", "url":"https://myapp-you.s1.aicc-web.com", "state":"RUNNING", "port":3154 }

Environment

GET/api/me/apps/:name/envYour stored env vars (managed keys listed by name only)
PATCH/api/me/apps/:name/envMerge env keys and re-apply to the running process
PUT/api/me/apps/:name/envReplace the whole env
GET/api/me/apps/:name/env/resolved?reveal=1Full runtime env (secrets masked unless reveal=1)

One-off commands (no SSH needed)

POST/api/me/apps/:name/runRun a command in the app dir as you โ€” migrations, psql, seeds. DATABASE_URL injected. Body: {command, timeoutMs?} (max 300s)
curl -X POST https://aicc-web.com/api/me/apps/myapp/run \
  -H 'Authorization: Bearer <key>' -H 'Content-Type: application/json' \
  -d '{"command":"npx prisma migrate deploy"}'
# โ†’ { "exitCode":0, "stdout":"...", "stderr":"", "durationMs":2210 }

Files

GET/api/me/apps/:name/files?path=&root=app|storageList a directory (folders first). root=storage targets the persistent storage dir (process.env.STORAGE_PATH โ€” survives redeploys)
GET/api/me/apps/:name/files/content?path=&root=Read a file (binary/>1MB come back non-editable)
PUT/api/me/apps/:name/files?path=&root=Create/overwrite a file. Body: {content}. App-root edits need a restart; storage edits are live
DELETE/api/me/apps/:name/files?path=&root=Delete a file
Paths are server-validated to stay inside the chosen root โ€” traversal (../../etc/passwd) and absolute paths are rejected. Every deploy WIPES the code directory โ€” runtime uploads belong in STORAGE_PATH.

Custom domains

GET/api/me/apps/:name/domainsList custom domains
POST/api/me/apps/:name/domainsAdd one โ€” body {domain}. Returns the server IP for your A record; TLS is automatic
DELETE/api/me/apps/:name/domains/:domainRemove one

Static Sites

POST/api/me/static-sitesDeploy from git (JSON: name, git_url, git_key?, git_branch?, output_dir?, spa_fallback?)
POST/api/me/static-sites/uploadDeploy from a ZIP (multipart: name, file, output_dir?, spa_fallback?)
POST/api/me/static-sites/:name/redeployRedeploy a git site from its stored URL + branch
GET/api/me/static-sitesList your static sites
GET/api/me/static-sites/:nameStatus + root path
GET/api/me/static-sites/:name/diskDisk usage (MB)
DELETE/api/me/static-sites/:nameDelete the site

Files and custom domains work exactly like apps, under /api/me/static-sites/:name/files... and /domains. Saves are live instantly (no process).

Databases

POST/api/me/databasesCreate โ€” body {name}. Returns DATABASE_URL once
GET/api/me/databasesList with live size, cap, attached app, orphan flag
GET/api/me/databases/:nameConnection info (decrypted, one-time)
GET/api/me/databases/:name/tablesExplorer: public-schema table list
POST/api/me/databases/:name/queryExplorer: read-only SQL (SELECT/SHOW/EXPLAIN/WITH). Body: {sql}
DELETE/api/me/databases/:nameDrop the DB + role. Refused while attached to a live app
The query surface is read-only by design. Writes/migrations go through POST /api/me/apps/:name/run (e.g. psql "$DATABASE_URL" -c '...').

MCP (for AI agents)

GET/.well-known/mcp-auth.jsonMachine-readable auth spec
POST/mcp/pairStart device pairing โ†’ {agentId, code} (6 digits, reusable 120s)
POST/mcp/exchange{agentId, code} โ†’ {token, refresh_token}. Polls with 202 until the student approves
POST/mcp/refresh{refresh_token} โ†’ new token pair (rotated)
POST/mcpStreamable-HTTP MCP endpoint (Authorization: Bearer)
GET/sseSSE MCP transport (for clients preferring SSE) + POST /messages?sessionId=
# Typical agent flow
curl -X POST https://aicc-web.com/mcp/pair                 # โ†’ code shown to the student
# student enters the code in the portal โ†’
curl -X POST https://aicc-web.com/mcp/exchange \
  -H 'Content-Type: application/json' \
  -d '{"agentId":"<id>","code":"123-456"}'   # โ†’ {token, refresh_token}

Errors & Conventions

AIC-Web ยท Home ยท Deploy Guide ยท Student Portal