Build your first app

Build a small orders backend in about 15 minutes: model your data, call the REST API, sign customers in with row-level security, and add a workflow.

Last updated

In about 15 minutes you'll build a small orders backend. You'll model an orders entity, add records, read them over the REST API with an API key, let customers register and see only their own orders, and run a workflow when an order ships. Nothing to host and no server code.

Every step is shown three ways: in the Anythink dashboard, with the CLI and with an AI assistant over MCP. Pick one and follow it through, or mix them. They all change the same project.

Before you start#

  1. Create a free account and a project at my.anythink.cloud. Your project is provisioned in under a minute.
  2. Note your project ID: it's the number after /org/ in the dashboard address. Your API lives at https://api.my.anythink.cloud/org/{project_id}.

Using the dashboard only? That's all you need. For the CLI or an AI assistant, set one of them up now.

With the CLI

Install the CLI and sign in. Get started with the CLI covers installing it. From a terminal:

bash
anythink signup
anythink login
anythink projects create "My First App" --region lon1
anythink projects use my-first-app

signup creates your account and asks you to confirm your email address. login signs you in to the platform, projects create asks you to choose a plan if you don't pass --plan, and projects use points the CLI at the project once it's active. Run anythink projects list to check its status.

With an AI assistant (MCP)

Connect your assistant to the project by following Connect Claude to your backend with MCP. Then ask for each step in plain English. The prompts below are ready to paste.

You should see: the project open in the dashboard, or anythink entities list returning an empty list of your own entities.

Note: The examples below use the project ID in place of {project_id}. Replace it with yours, and keep API keys and tokens out of source control.

Step 1: Model your orders#

An entity is a kind of thing you store. Create orders with six fields: customer_name, customer_email, item, quantity (a whole number), total (a decimal) and status (a choice of new, paid or shipped). The customer_email field is for the workflow in step 5.

In the Anythink dashboard

  1. Go to Settings › Data Model and select Add Entity.
  2. Enter orders as the Entity Name and select Create Entity.
  3. Open the entity and select Add Field for each field below, then Create Field.
Name Field type Notes
customer_name Small text Required
customer_email Small text Required
item Small text Required
quantity Integer Required
total Decimal
status Small text, display type Select Options new, paid, shipped. Default new

With the CLI

bash
anythink entities create orders
anythink fields add orders customer_name --type varchar --required
anythink fields add orders customer_email --type varchar --required
anythink fields add orders item --type varchar --required
anythink fields add orders quantity --type integer --required
anythink fields add orders total --type decimal
anythink fields add orders status --type varchar --display select --options "new,paid,shipped" --default new
text
Creating entity 'orders'...
✓ Entity orders created (id: 671).
Adding field 'customer_name' to 'orders'...
✓ Field customer_name (id: 3286) added to orders.
…
Adding field 'status' to 'orders'...
✓ Field status (id: 3290) added to orders.

With an AI assistant (MCP)

text
Create an orders entity with customer_name, customer_email and item (required text), quantity (required integer), total (decimal) and status (a select with new, paid and shipped, defaulting to new).

The assistant uses the cli tool to run entities create orders and one fields add per field, then confirms with entities get orders.

You should see: orders in Settings › Data Model with your six fields, plus id, created_at and updated_at, which Anythink adds for you. The REST API for orders already exists. See Model your data for every field type.

Step 2: Add a few records#

In the Anythink dashboard

  1. Open the orders entity and select Create Order.
  2. Fill in the form, for example Alice Smith, alice@example.com, Oak desk, quantity 1, total 249, status new, and save.
  3. Repeat for two more orders.

With the CLI

bash
anythink data create orders --data '{"customer_name":"Alice Smith","customer_email":"alice@example.com","item":"Oak desk","quantity":1,"total":249.00,"status":"new"}'
anythink data create orders --data '{"customer_name":"Bob Jones","customer_email":"bob@example.com","item":"Desk lamp","quantity":2,"total":58.50,"status":"paid"}'
anythink data create orders --data '{"customer_name":"Alice Smith","customer_email":"alice@example.com","item":"Monitor stand","quantity":1,"total":39.99,"status":"paid"}'
text
Creating orders record...
✓ Record created in orders (id: 1).
{
   "locked": false,
   "id": 1,
   "created_at": "2026-10-04T14:39:50.036524Z",
   "updated_at": "2026-10-04T14:39:50.036524Z",
   "customer_name": "Alice Smith",
   "item": "Oak desk",
   "quantity": 1,
   "total": 249,
   "status": "new",
   "customer_email": "alice@example.com",
   "__name": 1
}

With an AI assistant (MCP)

text
Add three orders: Alice Smith (alice@example.com) bought an Oak desk for 249, status new. Bob Jones (bob@example.com) bought 2 Desk lamps for 58.50, status paid. Alice also bought a Monitor stand for 39.99, status paid.

You should see: three records in the orders list, with ids 1, 2 and 3. anythink data list orders prints them as a table.

Step 3: Read them over the REST API#

Your own code reads records with an API key. Create one that can only read orders, then call the API with it.

In the Anythink dashboard

  1. Open My Account and select the API Keys tab.
  2. Enter a Name, such as orders-readonly, and choose Expires in (days): 30.
  3. Under Data Model Permissions, tick only orders read.
  4. Select Create API Key and copy the key from the banner. It's shown once.

With the CLI

bash
anythink api-keys create orders-readonly --permissions orders:read --expires-in 30 --yes
text
Resolving permissions...
Creating API key 'orders-readonly'...
✓ Created API key 'orders-readonly' (id: 40) — expires 2026-11-03.
Save this key now — it will not be shown again.

ak_3f9c1a…

With an AI assistant (MCP)

text
Create an API key called orders-readonly that can only read orders, expiring in 30 days.

The assistant runs api-keys create and shows you the key once. Anything you see in a chat passes through the assistant, so use a short expiry.

Now call the API. Put the key in the x-api-key header:

bash
curl "https://api.my.anythink.cloud/org/{project_id}/entities/orders/items?pageSize=2" \
  -H "x-api-key: ak_3f9c1a…"
json
{
  "items": [
    {
      "locked": false,
      "id": 1,
      "created_at": "2026-10-04T14:39:50.036524Z",
      "updated_at": "2026-10-04T14:39:50.036524Z",
      "customer_name": "Alice Smith",
      "item": "Oak desk",
      "quantity": 1,
      "total": 249,
      "status": "new",
      "customer_email": "alice@example.com",
      "__name": 1
    },
    {
      "locked": false,
      "id": 2,
      "created_at": "2026-10-04T14:39:54.499078Z",
      "updated_at": "2026-10-04T14:39:54.499078Z",
      "customer_name": "Bob Jones",
      "item": "Desk lamp",
      "quantity": 2,
      "total": 58.5,
      "status": "paid",
      "customer_email": "bob@example.com",
      "__name": 2
    }
  ],
  "page": 1,
  "page_size": 2,
  "total_items": 3,
  "total_pages": 2,
  "has_next_page": true,
  "has_previous_page": false,
  "retrieval_time": 6
}

You should see: two orders, and total_items of 3. The key can't write: a POST to the same URL returns 403 Forbidden, because the key holds only orders:read. Filtering, sorting and field selection are in the REST API reference, and API keys covers rotation and revoking.

Step 4: Let customers sign in and see only their own orders#

An API key is for your server. Your customers sign in instead, and each request then runs as that user. Four settings make that work: registration, a role with access to orders, row-level security, and a sign-in.

Allow registration and give new users access#

New users get a default role. Give that role permission to read and create orders, and turn off email confirmation for this tutorial so you can sign in straight away.

In the Anythink dashboard

  1. Go to Settings › Roles and Permissions, open the Standard User role, make sure API Access is ticked, and tick orders Read and Create. Save.
  2. Go to Settings › Users. In the User access card, tick Allow registrations, set Default role for new users to Standard User, and clear Require email confirmation for new users.
  3. Click Save.

With the CLI

Permissions for the role. Take the id of Standard User from roles list (here it's 104):

bash
anythink roles list
anythink roles permissions add 104 orders --actions read,create
text
✓ Added read, create on orders to role 104.

Registration is a project setting that you change in the dashboard. Use step 2 above.

With an AI assistant (MCP)

text
Give the Standard User role read and create permission on orders.

The assistant runs roles permissions add. It can't change the registration settings, so use the dashboard for those.

Note: In a real app, leave email confirmation on. Customers then confirm their address before they can sign in. See Sign in users.

Register a customer and sign in#

The register and sign-in endpoints need no credentials. Your app calls them directly:

bash
curl -X POST "https://api.my.anythink.cloud/org/{project_id}/auth/v1/register" \
  -H "Content-Type: application/json" \
  -d '{"first_name":"Alice","last_name":"Smith","email":"alice@example.com","password":"Str0ng!passphrase"}'
text
Registration successful
bash
curl -X POST "https://api.my.anythink.cloud/org/{project_id}/auth/v1/token" \
  -H "Content-Type: application/json" \
  -d '{"email":"alice@example.com","password":"Str0ng!passphrase"}'
json
{
  "access_token": "eyJhbGciOi…",
  "refresh_token": "O4q52BlAgNm8…",
  "expires_in": 1800
}

The access token lasts 30 minutes. In the CLI use anythink fetch /auth/v1/register --method POST --body '{…}', and in an AI assistant ask it to register a test user, using a throwaway password.

Before turning on row-level security, call the same endpoint as Alice:

bash
curl "https://api.my.anythink.cloud/org/{project_id}/entities/orders/items" \
  -H "Authorization: Bearer eyJhbGciOi…"

You should see: all three orders, including Bob's. A role's permissions say what a user may do with orders, not which records. Row-level security does that.

Turn on row-level security#

Turn it on before your app stores data it must protect. Records created while it was off have no grants, so after you switch it on they're visible only to administrators. That's what you want here: Alice's token will see none of the three records you added in step 2.

In the Anythink dashboard

  1. Go to Settings › Data Model and select Edit on orders.
  2. Tick Enable Row-Level Security and select Update Entity.

With the CLI

bash
anythink entities update orders --rls true
anythink entities get orders
text
── Entity: orders ──────────────────────────────────
  Table: orders
  Public: no
  RLS enabled: yes
  System entity: no
  Lock new records: no

With an AI assistant (MCP)

text
Turn on row-level security for the orders entity.

Create an order as the customer#

Alice's token sees nothing yet:

bash
curl "https://api.my.anythink.cloud/org/{project_id}/entities/orders/items" \
  -H "Authorization: Bearer eyJhbGciOi…"
json
{"items":[],"page":1,"page_size":25,"total_items":0,"total_pages":0,"has_next_page":false,"has_previous_page":false,"retrieval_time":14}

Now she places an order. Anythink grants the creator read and write access to a record they create, so you don't write any ownership code:

bash
curl -X POST "https://api.my.anythink.cloud/org/{project_id}/entities/orders/items" \
  -H "Authorization: Bearer eyJhbGciOi…" \
  -H "Content-Type: application/json" \
  -d '{"customer_name":"Alice Smith","customer_email":"alice@example.com","item":"Standing mat","quantity":1,"total":45.00}'
json
{
  "locked": false,
  "id": 4,
  "created_at": "2026-10-04T14:41:30.592945Z",
  "updated_at": "2026-10-04T14:41:30.592945Z",
  "customer_name": "Alice Smith",
  "item": "Standing mat",
  "quantity": 1,
  "total": 45,
  "status": "new",
  "customer_email": "alice@example.com",
  "__name": 4
}

Check that she sees only her own orders#

bash
curl "https://api.my.anythink.cloud/org/{project_id}/entities/orders/items?fields=id,item,status" \
  -H "Authorization: Bearer eyJhbGciOi…"
json
{"items":[{"locked":false,"id":4,"item":"Standing mat","status":"new","__name":4}],"page":1,"page_size":25,"total_items":1,"total_pages":1,"has_next_page":false,"has_previous_page":false,"retrieval_time":9}

You should see: one order, her own. Run the same request with your orders-readonly API key and you get all four, because a key runs as the user who created it, and you're an administrator. Administrators bypass row-level security. Share a record with another user or a group in Groups and row-level security, and read Roles and permissions for field-level control.

Step 5: Automate: act when an order ships#

A workflow runs when something happens. This one runs when an order's status changes to shipped. A trigger filter checks the change before a job is created.

The finished workflow would email the customer. Sending email needs a verified sending domain and an email template, which means adding DNS records at your domain provider. That takes longer than this tutorial, so here you'll log each shipment to a new order_events entity instead. Swapping in the email step is a one-step change once your domain is verified: see Send email from a workflow.

In the Anythink dashboard

  1. In Settings › Data Model, create an entity order_events with an integer field order_id and a text field message, both required.
  2. Open Workflows and select New Workflow. Name it order-shipped and select Create Workflow.
  3. Select Workflow Settings. Add a trigger with type Event, event Entity Updated and entity orders. Add a filter condition: field status, operator changed_to, value shipped. Save the settings.
  4. Select Add Step and choose Create data. Set the key to log_shipment and the entity to order_events, then set the payload:
json
{
  "order_id": "{{ $anythink.trigger.id }}",
  "message": "Order shipped: {{ $anythink.trigger.data.item }} for {{ $anythink.trigger.data.customer_name }}"
}
  1. Connect Start to the step, then save and enable the workflow.

With the CLI

bash
anythink entities create order_events
anythink fields add order_events order_id --type integer --required
anythink fields add order_events message --type text --required

anythink workflows create order-shipped --trigger Event --entity orders --event EntityUpdated \
  --filter '{"field":"status","op":"changed_to","value":"shipped"}' --enabled
text
✓ Workflow order-shipped created (id: 209).

Add the step, using the workflow id it printed. In a CLI step the payload is a string that holds JSON, so its quotes are escaped:

bash
anythink workflows step-add 209 log_shipment --name "Log shipment" --action CreateData --start --enabled \
  --params '{"entity_name":"order_events","payload":"{\"order_id\":\"{{ $anythink.trigger.id }}\",\"message\":\"Order shipped: {{ $anythink.trigger.data.item }} for {{ $anythink.trigger.data.customer_name }}\"}"}'
text
✓ Step log_shipment (id: 581) added to workflow 209.

With an AI assistant (MCP)

text
Create an order_events entity with an order_id integer and a message text field. Then create a workflow called order-shipped that runs when an order is updated and its status changes to shipped, and creates an order_events record saying which item shipped and for whom.

The assistant runs entities create, fields add, workflows create with an event filter, and workflows step-add.

Now ship an order and check the result:

bash
anythink data update orders 2 --data '{"status":"shipped"}'
anythink workflows jobs 209
anythink data list order_events --json
text
Fetching jobs for workflow 209...
── Jobs (1) ────────────────────────────────────────────────────────────────────

  Job #133197 Success — ?
json
[
  {
    …
    "id": 2,
    "order_id": 2,
    "message": "Order shipped: Desk lamp for Bob Jones",
    …
  }
]

You should see: one successful job and one order_events record. Updating an order to any status other than shipped starts no job at all. Workflows read every record, whatever the entity's row-level security says, so filter explicitly when a step should touch only some. The workflow tutorial goes deeper, and How workflows work explains triggers, steps and jobs.

You built a backend#

Part What it did
orders entity A data model that became a REST API
API key Read-only server access to orders
Registration and role Customers sign up and can read and create orders
Row-level security Each customer's token returns only their own orders
Workflow Reacted to a status change with no server code

Next steps#