powered by

Call the instant REST API

Every entity gets a REST API as soon as you create it. Authenticate, then list, get, create, update and delete records with curl, the CLI or MCP.

Last updated

You don't write an API with Anythink. You model your data, and the API is already there. Create an entity called orders, add a few fields, and you can list, read, create, change and delete orders over HTTP straight away. This guide takes you from a new entity to working requests. For every endpoint, parameter and status code, keep REST API reference open beside it.

How the API is generated

Each entity is a table, and each field is a typed column. When you save either one, Anythink changes the database and the API in the same step. There's nothing to deploy and no routes to write.

  • Add a field and it appears in requests and responses at once.
  • Every entity gets the same nine record endpoints, so what you learn for orders works for every other entity.
  • Four permissions are created with the entity: orders:read, orders:create, orders:update and orders:delete. Each endpoint checks one of them.
  • Requests and responses are JSON, and every property name is snake_case.

The examples on this page use an orders entity with five fields:

Field Type Notes
reference Small text Required and unique. It's the entity's name field.
total Decimal
status Small text A select with the choices draft, paid and shipped.
placed_on Date
paid Boolean Defaults to false.

To create it yourself, follow Model your data: entities, fields, relations. Every record also gets an id, created_at and updated_at, which Anythink sets for you.

Base URL and project ID

Every endpoint lives under your project:

text
https://api.my.anythink.cloud/org/{project_id}

Your project ID is the number after /org/ in the dashboard address. The record endpoints for an entity sit under /entities/{entity}/items, so the orders list is:

text
GET https://api.my.anythink.cloud/org/{project_id}/entities/orders/items

The entity name is the lower-case name from your data model, written exactly as it is there.

The curl examples below read two environment variables, so you can paste them as they are:

bash
export ORG_ID=12345
export ANYTHINK_API_KEY=ak_your_key_here
export BASE=https://api.my.anythink.cloud/org/$ORG_ID

Authenticate

Every record endpoint needs credentials. Send one of two things:

Credential Header Use it for
User access token Authorization: Bearer <access_token> Apps where a person is signed in. Each request runs as that user. See Sign in users.
API key x-api-key: ak_… Servers, scripts and CI with nobody signed in. See API keys.

The two calls below do the same thing:

bash
curl "$BASE/entities/orders/items" -H "Authorization: Bearer $ACCESS_TOKEN"
curl "$BASE/entities/orders/items" -H "x-api-key: $ANYTHINK_API_KEY"

Authentication says who is calling. Permissions say what they may do. A user gets permissions from their role, and an API key carries the permissions picked when it was created. A caller without the permission for an endpoint gets 403 Forbidden. Never put an API key in a browser or mobile app. Apps should sign users in and call the API as them, as in Anythink SDK: sign-in and sessions.

The CLI and the local MCP server sign in as you, so they need no header. They use the project your active profile points at. See Install and use the Anythink CLI.

Your first requests

The five requests below cover most of what an app does. Each is shown with curl, with the CLI and as a prompt for an AI assistant over MCP. All three go to the same endpoints and return the same records.

Create a record

POST sends the field values as a JSON object.

The raw request:

bash
curl -X POST "$BASE/entities/orders/items" \
  -H "x-api-key: $ANYTHINK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"reference": "A-1", "total": 10.5, "status": "paid", "placed_on": "2026-10-02", "paid": true}'
json
{
  "locked": false,
  "id": 1,
  "created_at": "2026-10-05T09:12:41.813603Z",
  "updated_at": "2026-10-05T09:12:41.813603Z",
  "reference": "A-1",
  "total": 10.5,
  "status": "paid",
  "placed_on": "2026-10-02T00:00:00",
  "paid": true,
  "__name": "A-1"
}

The status is 201 Created, and the Location header points at the new record. __name is the value of the entity's name field.

With the CLI

bash
anythink data create orders --data '{"reference": "A-1", "total": 10.5, "status": "paid", "placed_on": "2026-10-02", "paid": true}'
text
Creating orders record...
✓ Record created in orders (id: 1).

The CLI then prints the new record as JSON.

With an AI assistant (MCP)

text
Create an order with reference A-1, a total of 10.50, status paid, placed on 2 October 2026 and paid.

The assistant uses the cli tool to run data create orders with those values and shows you the record it gets back.

To create several at once, send an array to /entities/orders/items/bulk. The response is the array of new records.

List records

GET on the collection returns a page of records, wrapped with paging details.

The raw request:

bash
curl "$BASE/entities/orders/items" -H "x-api-key: $ANYTHINK_API_KEY"
json
{
  "items": [
    { "locked": false, "id": 1, "reference": "A-1", "total": 10.5, "status": "paid", "paid": true, "__name": "A-1" },
    { "locked": false, "id": 2, "reference": "A-2", "total": 20, "status": "draft", "paid": false, "__name": "A-2" }
  ],
  "page": 1,
  "page_size": 25,
  "total_items": 2,
  "total_pages": 1,
  "has_next_page": false,
  "has_previous_page": false,
  "retrieval_time": 5
}

The records above are shortened to the most useful fields. A real response includes every field you're allowed to read.

With the CLI

bash
anythink data list orders --limit 10

The CLI prints a table. Add --json for the records as JSON.

With an AI assistant (MCP)

text
List my orders.

The assistant runs data list orders and summarises what comes back.

Get one record

Put the record's id on the end of the path. The response is the record on its own, without the paging wrapper. An unknown ID returns 404.

The raw request:

bash
curl "$BASE/entities/orders/items/1" -H "x-api-key: $ANYTHINK_API_KEY"

With the CLI

bash
anythink data get orders 1

With an AI assistant (MCP)

text
Show me order 1.

The assistant runs data get orders 1.

Update a record

PUT changes only the fields you send. Fields you leave out keep their values, so you don't need to send the whole record. There is no PATCH.

The raw request:

bash
curl -X PUT "$BASE/entities/orders/items/1" \
  -H "x-api-key: $ANYTHINK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status": "shipped"}'

The response is 204 No Content with no body. Read the record again if you need the new values.

With the CLI

bash
anythink data update orders 1 --data '{"status": "shipped"}'
text
Updating orders/1...
✓ Record orders/1 updated.

With an AI assistant (MCP)

text
Mark order 1 as shipped.

The assistant runs data update orders 1 with the new status.

Delete a record

The raw request:

bash
curl -X DELETE "$BASE/entities/orders/items/1" -H "x-api-key: $ANYTHINK_API_KEY"

The response is 204 No Content. Deleting is permanent.

With the CLI

bash
anythink data delete orders 1 --yes
text
Deleting record...
✓ Record orders/1 deleted.

Without --yes the CLI asks you to confirm.

With an AI assistant (MCP)

text
Delete order 1.

The assistant runs data delete orders 1. Deleting is permanent, so check the order number in your prompt.

Page and sort results

The list endpoint takes these query parameters. The full table is in REST API reference.

Parameter Default What it does
page 1 Page number, starting at 1.
pageSize 25 Records per page, from 1 to 1000.
sortBy id The field to sort by.
sortDirection asc asc or desc.
fields all fields Comma-separated fields to return. id, locked and __name always come back.

pageSize, sortBy and sortDirection are camel case in the query string, even though the JSON is snake case.

bash
curl "$BASE/entities/orders/items?sortBy=total&sortDirection=desc&pageSize=1&page=2&fields=reference,total" \
  -H "x-api-key: $ANYTHINK_API_KEY"
json
{
  "items": [
    { "locked": false, "id": 1, "reference": "A-1", "total": 10.5, "__name": "A-1" }
  ],
  "page": 2,
  "page_size": 1,
  "total_items": 3,
  "total_pages": 3,
  "has_next_page": true,
  "has_previous_page": true,
  "retrieval_time": 5
}

Keep asking for the next page while has_next_page is true. In the CLI, anythink fetch calls any path with your project's base URL and signs the request for you, so the same query string works there:

bash
anythink fetch "/entities/orders/items?sortBy=total&sortDirection=desc&pageSize=1&page=2"

Filter records

Add a field name and a value to the query string. A bare value means equals. Put an operator in front of the value for anything else. Filters on different fields combine with AND.

bash
curl "$BASE/entities/orders/items?status=paid&total=GTE:10" -H "x-api-key: $ANYTHINK_API_KEY"
anythink data list orders --filter 'status=paid&total=GTE:10'

To put two conditions on one field, separate them with a comma. total=GTE:6,LT:30 means 6 or more and under 30. A filter on a field the entity doesn't have is ignored, so a misspelt name returns unfiltered records. If a total looks too high, check the field name first.

Filter operators reference lists every operator, how values are read for each field type and how to combine conditions.

Relationships in responses

When an entity has relationship fields, each record includes the related data under the field's name.

Relationship Shape under the field name
Many to one, one to one The related record as an object, or null when it isn't set.
One to many, many to many An object { "__count": n, "__data": [ … ] }.

For an orders entity where each order has a customer:

json
{
  "id": 3,
  "reference": "A-3",
  "customer": { "id": 1, "name": "Ada Lovelace", "__name": "Ada Lovelace" },
  "__name": "A-3"
}

And the other way round, where each customer has many orders:

json
{
  "id": 1,
  "name": "Ada Lovelace",
  "orders": {
    "__count": 2,
    "__data": [
      { "id": 3, "__name": "A-3" },
      { "id": 7, "__name": "A-7" }
    ]
  }
}

By default a many-to-one or one-to-one field comes back expanded, while a one-to-many or many-to-many field comes back with each related record's id and __name. Use fields to ask for more or less, for example fields=reference,customer.name. The related records you get are filtered by the caller's permissions, so two callers can see different data for the same record. REST API reference covers expansion in full, and Connect entities with relationships shows how to model and write them.

Errors

Read the status code first. The body depends on where the error came from, so don't assume it's JSON.

Status Meaning Example
400 A bad parameter or body, a locked record, or a value the database refuses, such as a duplicate in a unique field. 'pageSize' must be between 1 and 1000
401 No credentials, or credentials that aren't valid. JSON with "title": "Unauthorized" and a traceId.
403 The caller lacks the permission for this endpoint. An empty body.
404 The record doesn't exist, or the caller can't see it. JSON with "title": "Not Found" and a traceId.
405 The method isn't supported, such as PATCH. An empty body.
429 Too many requests. Wait for retry_after seconds. JSON with retry_after.

If a request that should work returns 403, check the caller's role or the API key's permissions before anything else. Log the traceId from error bodies with the request. It's what support needs to find a failure.

Know where your API is documented

The dashboard documents your own project's API from your current data model, so it includes the entities you created yesterday. See Your project's own API documentation for the interactive pages and the OpenAPI documents you can feed to a client generator.

Next steps