Quickstart

Create an app, add a table, grant access to it, sign a user in, and read your rows over the API.

By the end of this page you will have a provisioned app with a notes table, a policy that lets your app's users write and read it, and an authenticated API call returning rows named by their uid. It takes about ten minutes.

Before you start

You need a console account. Open the console's sign-up page (/signup; the sign-in page links to it under Need an account first?).

Sign-up may be invite-only

When the sign-up page says Authoric is invite-only right now, fill in the request form (name, email, an optional company, and what you would like to build) and choose Request access. Once your request is approved you receive a one-time link to create your account. Google and GitHub sign-in also work for an approved address. A teammate can skip the request: an invitation from an admin of an existing organization is an approval in itself.

The samples below read two environment variables:

export AUTHORIC_URL="https://api.authoric.ai"   # your API's address
export APP_UID="<the App ID you copy in step 1>"

Create and provision an app

In the console, open Apps and choose Create App. Enter a name for the app (the field is labelled App ID; anything that is not already a uid is taken as the name, and the app's uid is minted for you), then choose Create app.

An app is its own database, with its own users, tables, roles, policies, handlers, storage and agents. Nothing is shared with your other apps.

A new app is created but not yet provisioned: its database does not exist until you provision it. Choose Provision from the app's row actions, or open the app and choose Provision app. It takes a few seconds; sections that need the database stay disabled, marked Provision this app first, until it finishes.

The Apps list showing several apps with their status
Each app is a separate database with its own users, tables and policies.

Open the app. Its header shows the App ID with a copy button. Copy it into APP_UID: every app-plane URL begins with it.

Create a table

In the app, open Database › Tables and choose New. Name the table notes, then use Add Column for two columns:

ColumnTypeNotes
titleVARCHAR (length 255)
bodyTEXTNullable

Leave Scope by org on, then choose Create table.

Every table also gets columns you do not define: id (the primary key, which never leaves the database), uid (the row's handle in the API), org_id (which organization the row belongs to, never returned), and created_at / updated_at.

The table now has a REST API: list, read, create, update and delete, at /{appUid}/autocrud/notes. You did not write a route.

A table's rows in the console data grid, with column names and types in the header
Rows are editable in place, and the same table is already a REST resource.

Grant your users access to it

A new table is reachable by nobody until a policy grants it. Your app's users all hold the built-in User role, so grant the table to that role:

  1. Open App access › Policies and choose Create Policy. Name it Notes access and choose Create policy.
  2. Under the policy's Permissions, choose Advanced (the per-table action grid) if it is not already selected. Find the notes table, tick create, read and readList (the policy keys notes:create, notes:read and notes:read_list), and choose Publish.
  3. Open App access › Roles, open the User role, pick Notes access under Assign Policy and choose Assign policy.
An app's policy catalog in the console
Policies name actions on resources; roles carry policies; principals hold roles.

Skip this step and the calls below return 403: a valid token is not permission.

Sign a user up

Your app's users are separate from your console account. Create the first one over the API. Passwords need at least eight characters with an uppercase letter, a lowercase letter, a digit and a symbol.

curl -X POST "$AUTHORIC_URL/$APP_UID/auth/signup" \
  -H "Content-Type: application/json" \
  -d '{ "email": "first@example.com", "password": "StrongPass!234" }'

# Keep the access token for the calls that follow
export TOKEN="<auth.accessToken from the response>"

Sign-up creates the user, gives them an organization of their own, and signs them in. The response names the account by uid and carries an auth object:

{
  "uid": "0199b2e4-5c1a-7d3e-8f42-6a9b0c1d2e3f",
  "email": "first@example.com",
  "orgUid": "0199b2e4-5c19-7a10-b5c2-3d4e5f6a7b8c",
  "auth": {
    "accessToken": "eyJhbGciOi…",
    "refreshToken": "…",
    "activeOrgUid": "0199b2e4-5c19-7a10-b5c2-3d4e5f6a7b8c"
  }
}

Send the access token as Authorization: Bearer <token>. It is short-lived (15 minutes by default); exchange the refresh token at POST /{appUid}/auth/token for a new pair. Later sign-ins use POST /{appUid}/auth/login with the same email and password, and get the same auth object. Magic links, email codes, and Google or GitHub sign-in end at the same tokens; see Sign-in methods.

Write and read a row

# Write
curl -X POST "$AUTHORIC_URL/$APP_UID/autocrud/notes" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "title": "First note", "body": "Written over the API." }'

# Read
curl "$AUTHORIC_URL/$APP_UID/autocrud/notes?limit=10&sort=created_at%20DESC" \
  -H "Authorization: Bearer $TOKEN"

The write answers with the new row's uid. The read comes back as items and paging:

{
  "items": [
    {
      "uid": "0199b2e6-0a4f-7c21-9d83-1e2f3a4b5c6d",
      "title": "First note",
      "body": "Written over the API.",
      "created_at": "2026-10-29T14:02:11.000Z",
      "updated_at": "2026-10-29T14:02:11.000Z"
    }
  ],
  "paging": { "limit": 10, "offset": 0, "count": 1, "total": 1 }
}

There is no id and no org_id in the row. A row is addressed by its uid from here on: GET, PATCH or DELETE /{appUid}/autocrud/notes/{rowUid}.

What just happened

The write succeeded because a policy bound to the User role grants notes:create, not because the token was valid. That check runs on every request, against the principal making it, whether that is one of your users, an API key, a scheduled job or an agent. The row also landed in the user's own organization, so another user of the app, in another organization, would not see it.

What's next

On this page