Documentation/Getting Started/Quick Start
Quick Start
Register a domain, create a project, upload a schema, and start reading and writing data through the Supero REST API (and the Python SDK) in a few minutes.
Before You Begin
This guide walks through the real, minimal path to a working Supero backend using raw HTTP calls: register a domain, authenticate, create a project, upload a schema, and call the CRUD API. Everything here works from a terminal — no dashboard account is required to follow along, though you are welcome to do the same steps from app.supero.dev instead.
Raw HTTP is only one of five ways into the platform — Ways to Build lays out all of them (App Studio, MCP, the CLI, the SDKs, and the REST API) so you can pick the entry point that matches how you want to work.
- •A terminal with curl (or any HTTP client).
- •Basic familiarity with REST APIs and JSON.
- •Optionally, Python 3.9+ if you want to follow the SDK section at the end instead of raw HTTP.
Prefer to start in a browser rather than a terminal? Create Your Account walks through signup, and Ways to Build compares the five entry points.
ℹ️ Where things live
REST calls in this guide target https://api.supero.dev. The web dashboard lives at app.supero.dev; apps you eventually deploy run at their own subdomain on supero.live. Neither is required just to follow this guide.
Step 1: Register a Domain
A Domain sits at the top of the Supero hierarchy (Domain -> Project -> Tenant -> user/API key) — every project, schema, and record you create lives under one. Core Concepts explains each layer in depth. Register a new domain with its first admin user in a single call.
bash
curl -X POST https://api.supero.dev/api/v1/domains/register \
-H "Content-Type: application/json" \
-d '{
"domain_name": "acme-corp",
"admin_email": "[email protected]",
"admin_password": "SecurePass123!",
"domain_display_name": "Acme Corp"
}'domain_name must be unique across the platform and use only lowercase letters, numbers, and hyphens. domain_display_name is optional. Once the domain is registered, log in with the admin credentials to get a token (Step 2).
Step 2: Log In and Get a Token
Exchange the admin email and password for a session and an access token.
bash
curl -X POST https://api.supero.dev/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{
"domain": "acme-corp",
"email": "[email protected]",
"password": "SecurePass123!"
}'json
{
"auth": {
"access_token": "eyJ...",
"refresh_token": "eyJ...",
"token_type": "Bearer",
"expires_in": 28800,
"session_id": "sess_..."
},
"user": { "email": "[email protected]", "user_uuid": "..." },
"context": { "domain": "acme-corp", "project": "default-project", "tenant": "default-tenant" },
"policy": { }
}Save auth.access_token — every call below sends it as an Authorization: Bearer header. Access tokens last 8 hours; refresh with POST /api/v1/auth/refresh using the refresh_token (valid 7 days), and end a session with POST /api/v1/auth/logout.
⚠️ Bearer vs X-API-Key
A JWT access token goes in the Authorization: Bearer header. An API key — an opaque secret starting ak_..., created via POST /api/v1/domains/{domain}/api-key or from the dashboard — goes in a separate X-API-Key header instead. Never send an API key as a Bearer token. Authentication covers both credential types, their scopes, and refresh in full.
Step 3: Create a Project
Projects live under a domain and hold your schemas and data. Create one through the same CRUD endpoint pattern you will use for your own data later.
bash
curl -X POST https://api.supero.dev/api/v1/crud/acme-corp/project \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "my-first-app",
"fq_name": ["acme-corp", "my-first-app"],
"parent_type": "domain",
"display_name": "My First App"
}'Creating a project automatically creates a default-tenant under it — the response includes default_tenant_uuid and default_tenant_name alongside the project's own uuid. Keep both uuids handy; you will need the project uuid in Step 4 and the tenant uuid in Step 5.
Step 4: Define and Upload a Schema
Schemas are declarative, not JSON-Schema. There is no properties{} block or type:reference — an object type is a flat attributes[] list plus an optional references[] list, and each field is {name, type, mandatory}, optionally adding values for an enum or a default value. You may still meet the older spellings fields and required in existing schemas; both are accepted, but attributes and mandatory are the canonical pair — and a body sent with fields always reads back as attributes. The Schema Reference documents every field type and modifier.
json
{
"name": "Task",
"schema_type": "object",
"schema_content": {
"name": "Task",
"parent_type": "tenant",
"attributes": [
{ "name": "title", "type": "string", "mandatory": true },
{ "name": "priority", "type": "integer", "mandatory": false },
{
"name": "status",
"type": "string",
"mandatory": false,
"values": ["todo", "in_progress", "done"]
}
],
"references": []
},
"version": "1.0.0"
}parent_type: "tenant" means every Task record belongs to a tenant, matching the Domain -> Project -> Tenant -> record hierarchy. To link Task to another object type, add an entry to references[] naming the target type and its cardinality. To build on an existing type instead of repeating its fields, add "extends": "<namespace>:<type-name>" alongside attributes/references — see Transactional Services for the built-in base types you can extend.
bash
curl -X POST https://api.supero.dev/api/v1/schemas/upload \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"domain_name": "acme-corp",
"project_uuid": "PROJECT_UUID_FROM_STEP_3",
"schemas": [ { "...the Task schema above..." } ]
}'💡 No separate deploy step
There is no additional "Deploy" action: as soon as the upload call returns, https://api.supero.dev/api/v1/crud/acme-corp/task is live for POST/GET/PUT/DELETE.
⚠️ A newly uploaded schema can take a moment to become visible
One caveat worth knowing before it bites you in a script. A schema you just uploaded is briefly not visible to every server handling your requests, so an immediate write can come back with a "Schema not found" error even though the upload succeeded. The SDKs retry this for you. If you are calling the API directly, take the uuids from the upload response rather than re-reading the list, and retry a first write once rather than treating it as a failure. See Errors & Status Codes.
Step 5: Read and Write Data
Every object type — built-ins like project and tenant, and every custom type you upload — is reachable through the same pattern: POST | GET | PUT | DELETE https://api.supero.dev/api/v1/crud/{domain}/{type}[/{uuid}]. Records key on uuid, never id.
bash
curl -X POST https://api.supero.dev/api/v1/crud/acme-corp/task \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "task-1",
"fq_name": ["acme-corp", "my-first-app", "default-tenant", "task-1"],
"parent_type": "tenant",
"parent_uuid": "DEFAULT_TENANT_UUID_FROM_STEP_3",
"title": "Build the frontend",
"status": "todo",
"priority": 3
}'⚠️ This walkthrough writes into default-tenant
Your new project has only the default-tenant it was created with, so that is where this first record lands — which is fine for the tutorial data you are creating here. It is not fine for a real customer, or for a credential your application runs with: membership of a tenant named default-tenant grants project-wide access to every tenant in the project regardless of role. Before you onboard anyone real, create a named tenant per customer and point your app at that instead. See Building Multi-Tenant Apps.
name / fq_name / parent_type / parent_uuid place the record in the hierarchy; everything else is your schema's own fields. The create response returns system fields only (uuid, name, fq_name, created_at, updated_at, ...) — fetch the record by uuid to see your custom fields.
bash
curl https://api.supero.dev/api/v1/crud/acme-corp/task/TASK_UUID \
-H "Authorization: Bearer $ACCESS_TOKEN"bash
curl "https://api.supero.dev/api/v1/crud/acme-corp/task?limit=10&sort_by=priority&sort_order=desc" \
-H "Authorization: Bearer $ACCESS_TOKEN"List responses come back as {results: [...], pagination: {has_more, next_cursor}} — pass cursor=<next_cursor> to fetch the next page instead of an offset. Querying & Pagination covers filters, sorting, and cursors in full.
bash
curl -X PUT https://api.supero.dev/api/v1/crud/acme-corp/task/TASK_UUID \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "status": "in_progress" }'bash
curl -X DELETE https://api.supero.dev/api/v1/crud/acme-corp/task/TASK_UUID \
-H "Authorization: Bearer $ACCESS_TOKEN"For filtered, multi-field reads use POST /api/v1/crud/acme-corp/query with a JSON body ({"type": "task", "filters": {...}}); for high-volume paginated reads of a single type use POST /api/v1/crud/acme-corp/list-bulk. Scope any of these to a narrower project or tenant than what is already in your token by passing project and/or tenant as query params (GET/DELETE) or in the request body (POST/PUT).
Endpoint Quick Reference
| Method | Path | Purpose |
|---|---|---|
| POST | /api/v1/domains/register | Register a new domain and its admin user |
| POST | /api/v1/auth/login | Authenticate, receive access and refresh tokens |
| POST | /api/v1/auth/refresh | Exchange a refresh token for a new access token |
| POST | /api/v1/auth/logout | Revoke the current session |
| POST | /api/v1/schemas/upload | Upload one or more schemas to a project |
| POST | /api/v1/crud/{domain}/{type} | Create a record |
| GET | /api/v1/crud/{domain}/{type} | List records (limit, cursor, sort_by, sort_order) |
| GET | /api/v1/crud/{domain}/{type}/{uuid} | Get a record |
| PUT | /api/v1/crud/{domain}/{type}/{uuid} | Update a record |
| DELETE | /api/v1/crud/{domain}/{type}/{uuid} | Delete a record |
| POST | /api/v1/crud/{domain}/query | Filtered read with a JSON body |
| POST | /api/v1/crud/{domain}/list-bulk | Bulk paginated read of one type |
Step 6: Use the Python SDK Instead
The Python SDK wraps the same REST calls behind a fluent, synchronous API — reach for it once you are past the first curl call.
bash
pip install superopython
import supero
org = supero.login(
domain_name="acme-corp",
email="[email protected]",
password="SecurePass123!",
)
task = org.crud.create(
"task",
name="task-1",
title="Build the frontend",
status="todo",
priority=3,
)
todo_tasks = (
org.crud.query("task")
.filter(status="todo")
.order_by("-priority")
.limit(10)
.all()
)
org.crud.update("task", task["uuid"], status="in_progress")
org.crud.delete("task", task["uuid"])supero.connect(domain_name, api_key="ak_...") connects with an API key instead of a password when you would rather not manage a session. Both return the same org object: org.crud.create/get/list/update/delete for direct calls, plus the chainable org.crud.query(type).filter(...).order_by(...).limit(...).all() builder for reads. supero.register_domain(...) mirrors the REST call from Step 1 if you want to stay in Python end to end.
ℹ️ JavaScript
A JavaScript/Node package, @supero/js-lib, is also available for platform access from server-side or browser code. Its API surface differs from the Python SDK — check the JavaScript SDK reference for the current entry points before you build against it.
Next Steps
You now have a domain, a project, a live schema, and data flowing through the CRUD API.
- •Read Core Concepts for the full domain/project/tenant/schema mental model.
- •See the Schema Reference for the complete attributes/references/extends shape, including enums and inheritance.
- •See CRUD Endpoints for the full REST reference, including references and bulk operations.
- •Read Authentication for token refresh, API keys, and scoping details beyond this guide.
- •Compare the five entry points in Ways to Build if you would rather generate an app in App Studio, drive the platform from your AI editor over MCP, or use the CLI.
On this page