API reference

The CUIT SaaS API.
Upload a session. Get a regression spec.

This is the data plane. Customer recorders POST captured sessions to POST /v1/sessions; the warehouse auto-generates a Playwright/Vitest spec, persists it under tenant isolation, and returns the spec id and confidence in the same response. Everything else — spec list, insights, audit log export, MCP tool surface — is a thin shell over the same shape.

Spec is OpenAPI 3.0, sourced from the same Zod schemas that validate inbound requests at runtime. Same source of truth as the server. When the API changes, this page changes — there is no hand-maintained docs drift.

OpenAPI 3.0Bearer token authMulti-tenant via Postgres RLSJSON only

Authentication

Per-tenant bearer token issued at onboarding. Pass on every /v1/* request:

authorization: Bearer <TOKEN>

Token resolves to a tenant_id which we set in the Postgres connection's app.current_tenant_idGUC. Row Level Security handles cross-tenant isolation; the application code cannot accidentally read another tenant's data.

Servers

https://cuit-saas-pilot.fly.devPilot — LIVE today on Fly.io (IAD) + Neon (us-east-1)
http://localhost:7710Local development
https://api.cuit.devProduction — sprint week 8 (AWS ECS Fargate + Aurora)

Pilot is on Fly.io + Neon Postgres. Production lands on AWS ECS Fargate + Aurora in sprint week 8 — same OpenAPI surface, no breaking changes.

Versioning

Path-prefixed under /v1/. We bump /v2/ only for genuine breaking changes; additive fields and new optional parameters ship under /v1/ forever.

OpenAPI 3.0.0
CUIT SaaS API v0.1.0

Errors

Every error is JSON, always shape { error: string, message?: string, issues?: [] }. HTTP status is the source of truth for category; the body is the source of truth for what to tell the developer.

statuserrorwhen
400invalid payloadBody did not match the route's Zod schema. issues is the Zod error array verbatim.
401missing bearer tokenNo Authorization header. Or the header doesn't start with Bearer .
401invalid tokenToken didn't resolve to a tenant. Rotated? Revoked? Typo?
404not foundResource ID doesn't exist in this tenant. RLS makes cross-tenant 404s look identical to genuinely missing — by design.
500server errorOur fault. message is the underlying exception. We log every 500 with a request id; mention it when you file a ticket.

Agent integration — MCP is the primary surface

The REST API exists for CI workflows, batch scripts, and direct integration. The MCP server (@cuit-saas/mcp) is what Claude Code / Cursor / Codex consume in-loop. Both call the same endpoints below. If you're wiring an agent: use MCP. If you're wiring CI: use REST.

// ~/.claude/mcp_servers.json
{
  "mcpServers": {
    "cuit": {
      "command": "npx",
      "args": ["-y", "@cuit-saas/mcp"],
      "env": {
        "CUIT_API_URL": "https://api.cuit.dev",
        "CUIT_TENANT_TOKEN": "<YOUR_TENANT_TOKEN>"
      }
    }
  }
}

The MCP server ships 3 of 8 tools wired today (query_sessions, find_similar_sessions, flake_rate). The remaining 5 ship across sprint weeks 3-8 — see docs/12 §6 for the frozen tool interface.

Endpoints

Auto-generated from openapi.json. Same schemas as the runtime validation. Examples are real shapes the API accepts — copy and paste them.

ops(1 endpoint)

Health and operations endpoints (no auth)

get/healthzliveops

Health check

Returns 200 OK if the API process is alive. No auth required.

responses

200OK
fieldtypenotes
ok*boolean
ts*string

example — curl

curl -X GET 'http://localhost:7710/healthz'

admin(5 endpoints)

Tenant + token management. Admin or tenant-bearer auth.

post/v1/admin/tenantsliveadmin

Create a new tenant

Admin-only. Issues an initial bearer token returned in the response. Token is shown ONCE; we store only its hash. Customer onboarding flow uses this endpoint.

request body

fieldtypenotes
slug*string
display_name*string
tier*"team" | "business" | "enterprise"
pii_redactionboolean
retention_daysinteger

responses

201Tenant created
fieldtypenotes
tenant*object
initial_token*object
401Admin auth required
fieldtypenotes
error*string
messagestring
issuesobject[]
409Slug already in use
fieldtypenotes
error*string
messagestring
issuesobject[]

example — curl

curl -X POST 'http://localhost:7710/v1/admin/tenants' \
  -H 'content-type: application/json' \
  -d '{
       "slug": "acme-corp",
       "display_name": "Acme Corp",
       "tier": "business",
       "pii_redaction": true,
       "retention_days": 0
     }'
post/v1/admin/tokensliveadmin

Issue a new bearer token for the current tenant

Used to rotate tokens or to issue scoped tokens for specific environments (CI vs. dev). Token shown ONCE in the response.

request body

fieldtypenotes
label*string
expires_atstring<date-time>

responses

201Token issued
fieldtypenotes
token*stringPlaintext bearer token. Shown ONCE; we store only a hash. Save it now.
token_id*string<uuid>
label*string
created_at*string
expires_at*string
401Missing or invalid bearer token
fieldtypenotes
error*string
messagestring
issuesobject[]

example — curl

curl -X POST 'http://localhost:7710/v1/admin/tokens' \
  -H 'authorization: Bearer <YOUR_TENANT_TOKEN>' \
  -H 'content-type: application/json' \
  -d '{
       "label": "github-actions-ci",
       "expires_at": "2027-01-01T00:00:00Z"
     }'
get/v1/meliveadmin

Current tenant info

Returns the tenant resolved from the bearer token. Useful for the dashboard.

responses

200OK
fieldtypenotes
tenant*object
401Invalid token
fieldtypenotes
error*string
messagestring
issuesobject[]

example — curl

curl -X GET 'http://localhost:7710/v1/me' \
  -H 'authorization: Bearer <YOUR_TENANT_TOKEN>'
get/v1/auditliveadmin

Stream audit log as CSV / JSON / NDJSON

Compliance export. Returns a streaming response in the requested format. For large windows, prefer NDJSON for line-by-line consumption.

parameters

nameintypenotes
since*querystring<date-time>
until*querystring<date-time>
formatquery"csv" | "json" | "ndjson"

responses

200Streamed export
type: object[]
401Invalid token
fieldtypenotes
error*string
messagestring
issuesobject[]

example — curl

curl -X GET 'http://localhost:7710/v1/audit' \
  -H 'authorization: Bearer <YOUR_TENANT_TOKEN>'
delete/v1/admin/tenantliveadmin

Purge all tenant data (GDPR right-to-delete)

Hard-deletes sessions, specs, runs, signals, audit log for the authenticated tenant. Asynchronous: completes within 30 days. Returns a purge job id.

responses

202Purge job accepted
fieldtypenotes
purge_job_id*string<uuid>
eta_at*string
401Invalid token
fieldtypenotes
error*string
messagestring
issuesobject[]

example — curl

curl -X DELETE 'http://localhost:7710/v1/admin/tenant' \
  -H 'authorization: Bearer <YOUR_TENANT_TOKEN>'

sessions(5 endpoints)

Capture session upload and retrieval

get/v1/sessionslivesessions

List sessions for the authenticated tenant

Returns up to `limit` most-recent sessions ordered by created_at DESC.

parameters

nameintypenotes
limitquerystring

responses

200OK
fieldtypenotes
tenant*string
sessions*object[]
count*integer
401Missing or invalid bearer token
fieldtypenotes
error*string
messagestring
issuesobject[]

example — curl

curl -X GET 'http://localhost:7710/v1/sessions' \
  -H 'authorization: Bearer <YOUR_TENANT_TOKEN>'
post/v1/sessionslivesessions

Upload a captured session

Accepts a SessionEvent[] captured by the recorder. Auto-generates a regression spec when feasible (rule-based today; LLM pipeline ships sprint week 5). Idempotent on (tenant_id, session_id).

request body

fieldtypenotes
sessionId*string
vendor*"cuit" | "jam" | "logrocket" | "sentry-replay" | "fullstory" | "datadog-rum"
createdAtnumber
url*string
events*object[]
gitShastring
gitBranchstring
capturedByUserIdstring<uuid>

responses

201Session stored. Spec may have been generated.
fieldtypenotes
id*string<uuid>
tenant*string
event_count*integer
spec_id*string<uuid>
confidence*number
400Invalid payload
fieldtypenotes
error*string
messagestring
issuesobject[]
401Missing or invalid bearer token
fieldtypenotes
error*string
messagestring
issuesobject[]

example — curl

curl -X POST 'http://localhost:7710/v1/sessions' \
  -H 'authorization: Bearer <YOUR_TENANT_TOKEN>' \
  -H 'content-type: application/json' \
  -d '{
       "sessionId": "tur-live-1717459200000",
       "vendor": "cuit",
       "createdAt": 0,
       "url": "http://localhost:3000/projects/abc?cuitRecorder=1",
       "events": [
         {
           "seq": 7,
           "vendor": "cuit",
           "vendorEventId": "tur-001-p-10",
           "ts": 1200,
           "wallClock": 1748952001200,
           "type": "pointer"
         }
       ],
       "gitSha": "abc1234",
       "gitBranch": "developNoWaveFormFinal",
       "capturedByUserId": "00000000-0000-0000-0000-000000000000"
     }'
get/v1/sessions/{id}livesessions

Fetch one session by id

parameters

nameintypenotes
id*pathstring<uuid>

responses

200OK
fieldtypenotes
tenant*string
session*object
401Missing or invalid bearer token
fieldtypenotes
error*string
messagestring
issuesobject[]
404Session not found
fieldtypenotes
error*string
messagestring
issuesobject[]

example — curl

curl -X GET 'http://localhost:7710/v1/sessions/:id' \
  -H 'authorization: Bearer <YOUR_TENANT_TOKEN>'
get/v1/sessions/{id}/similarlivesessions

Find sessions vector-similar to this one

Backed by pgvector cosine similarity over per-session embeddings (voyage-3-lite). The MCP tool `cuit__find_similar_sessions` is a thin wrapper around this endpoint.

parameters

nameintypenotes
id*pathstring<uuid>
thresholdquerystring

responses

200OK
fieldtypenotes
reference_session_id*string<uuid>
threshold*number
similar*object[]
401Invalid token
fieldtypenotes
error*string
messagestring
issuesobject[]
404Reference session not found
fieldtypenotes
error*string
messagestring
issuesobject[]

example — curl

curl -X GET 'http://localhost:7710/v1/sessions/:id/similar' \
  -H 'authorization: Bearer <YOUR_TENANT_TOKEN>'
get/v1/sessions/{id}/eventslivesessions

Fetch the full events array for a single session

Returns the JSONB events column for a session. This is the AX-compliant drill-down counterpart to GET /v1/sessions, which returns only compact id+summary rows to stay within token budget (ADR-011 Rule 2). Pass the returned events to cuit__close_loop to generate and run a regression spec.

parameters

nameintypenotes
id*pathstring<uuid>

responses

200AX ok envelope with full events array
fieldtypenotes
outcome*"ok"
summary*string
data*object
400Non-UUID id path param
fieldtypenotes
error*string
messagestring
issuesobject[]
401Missing or invalid bearer token
fieldtypenotes
error*string
messagestring
issuesobject[]
404Session not found (AX error envelope)
fieldtypenotes
outcome*"error"
error*string
fix_hint*string

example — curl

curl -X GET 'http://localhost:7710/v1/sessions/:id/events' \
  -H 'authorization: Bearer <YOUR_TENANT_TOKEN>'

specs(3 endpoints)

Generated regression specs

get/v1/specslivespecs

List generated specs for the authenticated tenant

Returns up to 100 most-recent specs ordered by created_at DESC.

responses

200OK
fieldtypenotes
tenant*string
specs*object[]
401Missing or invalid bearer token
fieldtypenotes
error*string
messagestring
issuesobject[]

example — curl

curl -X GET 'http://localhost:7710/v1/specs' \
  -H 'authorization: Bearer <YOUR_TENANT_TOKEN>'
post/v1/specs/generatelivespecs

Generate a spec synchronously from a session payload OR session id

POST /v1/sessions auto-generates a spec asynchronously. Use this endpoint when you want the spec back in the same HTTP response — typical for CI integrations or the /cuit-loop skill. Calls the LLM 3-pass pipeline (Haiku normalize → Sonnet ground → Opus materialize) with prompt caching; falls back to rule-based when model_tier=rule-based.

request body

fieldtypenotes
sessionIdstring<uuid>Existing session UUID OR session payload below.
sessionobject
model_tier"rule-based" | "haiku" | "sonnet" | "opus" | "auto"
force_regenerateboolean

responses

201Spec generated
fieldtypenotes
id*string<uuid>
session_id*string<uuid>
model_version*string
confidence*number
auto_pr_eligible*boolean
primitives*object[]
serialized*stringThe rendered .spec.ts source code.
created_at*string
400Invalid payload
fieldtypenotes
error*string
messagestring
issuesobject[]
401Invalid token
fieldtypenotes
error*string
messagestring
issuesobject[]
422Generator could not produce a confident spec from this session
fieldtypenotes
error*string
messagestring
issuesobject[]

example — curl

curl -X POST 'http://localhost:7710/v1/specs/generate' \
  -H 'authorization: Bearer <YOUR_TENANT_TOKEN>' \
  -H 'content-type: application/json' \
  -d '{
       "sessionId": "00000000-0000-0000-0000-000000000000",
       "session": {
         "sessionId": "tur-live-1717459200000",
         "vendor": "cuit",
         "createdAt": 0,
         "url": "http://localhost:3000/projects/abc?cuitRecorder=1",
         "events": [
           {
             "seq": 7,
             "vendor": "cuit",
             "vendorEventId": "tur-001-p-10",
             "ts": 1200,
             "wallClock": 1748952001200,
             "type": "pointer"
           }
         ],
         "gitSha": "abc1234",
         "gitBranch": "developNoWaveFormFinal",
         "capturedByUserId": "00000000-0000-0000-0000-000000000000"
       },
       "model_tier": "rule-based",
       "force_regenerate": true
     }'
get/v1/specs/{id}livespecs

Fetch one spec by id (with full primitives + source)

parameters

nameintypenotes
id*pathstring<uuid>

responses

200OK
fieldtypenotes
id*string<uuid>
session_id*string<uuid>
model_version*string
confidence*number
auto_pr_eligible*boolean
primitives*object[]
serialized*stringThe rendered .spec.ts source code.
created_at*string
401Invalid token
fieldtypenotes
error*string
messagestring
issuesobject[]
404Not found
fieldtypenotes
error*string
messagestring
issuesobject[]

example — curl

curl -X GET 'http://localhost:7710/v1/specs/:id' \
  -H 'authorization: Bearer <YOUR_TENANT_TOKEN>'

runs(3 endpoints)

Spec executions against customer URLs

post/v1/specs/{id}/runliveruns

Run a spec against a customer URL; returns RED or GREEN with step-level annotations

The runner spins up a vitest-in-process worker (or headless Playwright per `browser`), executes the spec, and returns the structured outcome. On RED: the response includes `failed_at_primitive`, `last_snapshot`, and the preceding event window so an agent can reason about the failure without re-reading the spec source.

parameters

nameintypenotes
id*pathstring<uuid>

request body

fieldtypenotes
target_url*string<uri>
browser"chromium" | "firefox" | "webkit" | "jsdom"
expected_outcome"red" | "green" | "either"

responses

200Run complete
fieldtypenotes
id*string<uuid>
spec_id*string<uuid>
outcome*"red" | "green" | "error"
browser*string
duration_ms*integer
git_sha_at_run*string
is_flake*boolean
created_at*string
state_at_assertionobject
failed_at_primitiveobject
last_snapshotobjectWhen outcome=red: the state snapshot at the moment of failure.
preceding_eventsobject[]When outcome=red: the last N events before failure for context.
stepsobject[]
400Invalid request
fieldtypenotes
error*string
messagestring
issuesobject[]
401Invalid token
fieldtypenotes
error*string
messagestring
issuesobject[]
404Spec not found
fieldtypenotes
error*string
messagestring
issuesobject[]
408Run timed out
fieldtypenotes
error*string
messagestring
issuesobject[]

example — curl

curl -X POST 'http://localhost:7710/v1/specs/:id/run' \
  -H 'authorization: Bearer <YOUR_TENANT_TOKEN>' \
  -H 'content-type: application/json' \
  -d '{
       "target_url": "http://localhost:3000/projects/abc?cuitRecorder=1",
       "browser": "chromium",
       "expected_outcome": "red"
     }'
get/v1/runsliveruns

List runs across all specs for this tenant

Filterable by `spec_id`, `outcome`, `since`, `until`. Default: last 100 runs across the tenant.

parameters

nameintypenotes
spec_idquerystring<uuid>
outcomequery"red" | "green" | "error"
sincequerystring<date-time>
untilquerystring<date-time>
limitquerystring

responses

200OK
fieldtypenotes
tenant*string
runs*object[]
401Invalid token
fieldtypenotes
error*string
messagestring
issuesobject[]

example — curl

curl -X GET 'http://localhost:7710/v1/runs' \
  -H 'authorization: Bearer <YOUR_TENANT_TOKEN>'
post/v1/loop/closeliveruns

One-shot loop close: generate spec → run spec → persist trace

ADR-011 Rule 6 (one-shot composition) + Rule 7 (self-measuring). Runs generate→run→report in ONE call inside a single DB transaction (spec row + run row + loop_trace row + audit row). Returns the loop AX envelope with outcome green|red|error and a trace {turns_to_green, tool_calls, tokens, wall_ms}. Always returns HTTP 200 — the envelope carries the outcome. NOTE: not deduplicated in v0 (each call inserts a new spec row; non-destructive).

request body

fieldtypenotes
session_idstring<uuid>sessions.id UUID. Mutually exclusive with session.
sessionobjectInline session payload. Mutually exclusive with session_id.
target_url*string<uri>URL the spec runner will navigate to.

responses

200Loop close complete. outcome green|red|error in envelope.
fieldtypenotes
outcome*"green" | "red" | "error"
summary*string
next_actions*string[]
details_ref*string
data*object
trace*object
400Invalid payload
fieldtypenotes
error*string
messagestring
issuesobject[]
401Missing or invalid bearer token
fieldtypenotes
error*string
messagestring
issuesobject[]
404Session not found (when session_id supplied)
fieldtypenotes
outcome*"green" | "red" | "error"
summary*string
next_actions*string[]
details_ref*string
data*object
trace*object
422No spec could be generated from the session events
fieldtypenotes
outcome*"green" | "red" | "error"
summary*string
next_actions*string[]
details_ref*string
data*object
trace*object

example — curl

curl -X POST 'http://localhost:7710/v1/loop/close' \
  -H 'authorization: Bearer <YOUR_TENANT_TOKEN>' \
  -H 'content-type: application/json' \
  -d '{
       "session_id": "00000000-0000-0000-0000-000000000000",
       "session": {
         "sessionId": "string",
         "vendor": "cuit",
         "url": "string",
         "events": [
           {
             "seq": 7,
             "vendor": "cuit",
             "vendorEventId": "tur-001-p-10",
             "ts": 1200,
             "wallClock": 1748952001200,
             "type": "pointer"
           }
         ],
         "gitSha": "string",
         "gitBranch": "string",
         "capturedByUserId": "00000000-0000-0000-0000-000000000000"
       },
       "target_url": "http://localhost:3000/projects/abc"
     }'

instrument(2 endpoints)

App-shape detection and instrumentation proposals (powers /cuit-instrument skill)

post/v1/instrument/detect-shapeliveinstrument

Detect customer app shape (framework, state libs, selectors)

Used by the `/cuit-instrument` skill via the `cuit__detect_app_shape` MCP tool. Returns the structured shape so the proposal step can target the right files.

request body

fieldtypenotes
package_json*objectContents of the customer repo package.json
file_treestring[]Flat list of source file paths.
sample_filesobjectOptional map of path → content for AST hints.

responses

200OK
fieldtypenotes
framework*"next.js" | "vite" | "cra" | "remix" | "astro" | "sveltekit" | "unknown"
router*string
state_libs*string[]
ui_libs*string[]
test_runner*string
pkg_manager*"pnpm" | "npm" | "yarn" | "bun"
selectors_in_use*object
candidate_state_files*string[]
candidate_root_files*string[]
401Invalid token
fieldtypenotes
error*string
messagestring
issuesobject[]

example — curl

curl -X POST 'http://localhost:7710/v1/instrument/detect-shape' \
  -H 'authorization: Bearer <YOUR_TENANT_TOKEN>' \
  -H 'content-type: application/json' \
  -d '{
       "package_json": null,
       "file_tree": [
         "string"
       ],
       "sample_files": null
     }'
post/v1/instrument/proposeliveinstrument

Given an app shape, propose the instrumentation diff

Used by the `/cuit-instrument` skill via `cuit__propose_instrumentation`. The returned operations[] is consumed by Claude Code's Edit/Write tools to apply the diff.

request body

fieldtypenotes
app_shape*object
overridesobject

responses

200OK
fieldtypenotes
operations*object[]
npm_dependencies*string[]
github_actions_secrets*string[]
estimated_minutes*integer
rationale*string
401Invalid token
fieldtypenotes
error*string
messagestring
issuesobject[]

example — curl

curl -X POST 'http://localhost:7710/v1/instrument/propose' \
  -H 'authorization: Bearer <YOUR_TENANT_TOKEN>' \
  -H 'content-type: application/json' \
  -d '{
       "app_shape": {
         "framework": "next.js",
         "router": "string",
         "state_libs": [
           "string"
         ],
         "ui_libs": [
           "string"
         ],
         "test_runner": "string",
         "pkg_manager": "pnpm",
         "selectors_in_use": null,
         "candidate_state_files": [
           "string"
         ],
         "candidate_root_files": [
           "string"
         ]
       },
       "overrides": null
     }'

insights(2 endpoints)

Per-tenant analytics (flake rate, bug-class distribution)

get/v1/insights/flake-rateliveinsights

Per-spec flake rate over the last 28 days

Returns up to 20 specs ordered by flake rate descending. A spec with `reds`/`runs` close to 1.0 is highly unstable.

responses

200OK
fieldtypenotes
tenant*string
window*string
flake_rates*object[]
401Missing or invalid bearer token
fieldtypenotes
error*string
messagestring
issuesobject[]

example — curl

curl -X GET 'http://localhost:7710/v1/insights/flake-rate' \
  -H 'authorization: Bearer <YOUR_TENANT_TOKEN>'
get/v1/insights/bug-class-distributionliveinsights

Aggregate bug-class stats by component over a time window

parameters

nameintypenotes
windowquerystring

responses

200OK
fieldtypenotes
tenant*string
window*string
classes*object[]
401Invalid token
fieldtypenotes
error*string
messagestring
issuesobject[]

example — curl

curl -X GET 'http://localhost:7710/v1/insights/bug-class-distribution' \
  -H 'authorization: Bearer <YOUR_TENANT_TOKEN>'

billing(3 endpoints)

Usage stats and Stripe subscription details

get/v1/billing/usagelivebilling

Current-period usage stats

Returns sessions, specs, runs, inference tokens, and estimated cost for the current billing period.

responses

200OK
fieldtypenotes
tenant*string
period_start*string
period_end*string
seats_active*integer
sessions_uploaded*integer
specs_generated*integer
specs_run*integer
inference_tokens*integer
estimated_cost_usd*number
tier*"team" | "business" | "enterprise"
401Invalid token
fieldtypenotes
error*string
messagestring
issuesobject[]

example — curl

curl -X GET 'http://localhost:7710/v1/billing/usage' \
  -H 'authorization: Bearer <YOUR_TENANT_TOKEN>'
get/v1/billing/subscriptionlivebilling

Stripe subscription details for the current tenant

Returns subscription status + a link to the Stripe customer portal for self-service.

responses

200OK
fieldtypenotes
tenant*string
stripe_subscription_id*string
status*"active" | "past_due" | "canceled" | "trialing"
tier*"team" | "business" | "enterprise"
current_period_end*string
cancel_at_period_end*boolean
customer_portal_url*string
401Invalid token
fieldtypenotes
error*string
messagestring
issuesobject[]

example — curl

curl -X GET 'http://localhost:7710/v1/billing/subscription' \
  -H 'authorization: Bearer <YOUR_TENANT_TOKEN>'
post/webhooks/stripelivebilling

Stripe webhook receiver

Stripe webhook receiver. NOT bearer-authenticated — signature verified via HMAC-SHA256 of the raw body against STRIPE_WEBHOOK_SECRET. Routes customer.subscription.created/deleted and invoice.payment_failed events to tenant updates and audit log entries.

parameters

nameintypenotes
stripe-signature*headerstring

request body

fieldtypenotes

responses

200Event received and queued for processing
fieldtypenotes
received*true
400Missing or invalid Stripe-Signature header, or webhook misconfigured
fieldtypenotes
error*string
messagestring
issuesobject[]

example — curl

curl -X POST 'http://localhost:7710/webhooks/stripe' \
  -H 'content-type: application/json' \
  -d '{}'

public(1 endpoint)

Unauthenticated endpoints — no bearer token required

post/v1/public/signuplivepublic

Self-serve tenant signup

No authentication required. Creates a tenant (tier=team) and returns an initial bearer token in a single round-trip. Rate-limited to 3 signups per IP per rolling hour. The token is shown ONCE in the response — store it securely. PII (email, IP) is stored server-side for compliance and is never echoed back.

request body

fieldtypenotes
email*string<email>
company_name*string
requested_slug*stringLowercase slug for your tenant. Must start with a letter.

responses

201Tenant created. Contains the tenant object and a one-time-visible bearer token.
fieldtypenotes
tenant*object
initial_token*object
getting_started_url*string<uri>
400Invalid payload (missing fields, bad slug format, etc.)
fieldtypenotes
error*string
messagestring
issuesobject[]
409Requested slug (and up to 9 auto-suffixed variants) are all taken
fieldtypenotes
error*string
messagestring
issuesobject[]
429Rate limit exceeded — more than 3 signups from this IP in the past hour
fieldtypenotes
error*string
retry_after_seconds*integer

example — curl

curl -X POST 'http://localhost:7710/v1/public/signup' \
  -H 'content-type: application/json' \
  -d '{
       "email": "dev@acme.com",
       "company_name": "Acme Corp",
       "requested_slug": "acme-corp"
     }'

What ships next

  • Sprint week 3: POST /v1/sessions auto-triggers the LLM spec-gen pipeline (today: rule-based). Confidence threshold ≥ 0.75 enables auto-PR.
  • Sprint week 4: POST /v1/specs/:id/run against a customer URL, returns RED or GREEN with structured step-level annotations.
  • Sprint week 5: cuit__find_similar_sessions wires the pgvector query end-to-end. New endpoints land for app-shape detection + instrumentation proposal — see the /cuit-instrument skill.
  • Sprint week 7: GET /v1/audit?since=...&until=... with streaming CSV export. Stripe billing webhooks. Rate limits per tier.
  • Sprint week 8: api.cuit.dev is the production URL. SOC 2 evidence collection begins.