Your first API in 10 minutes¶
Every new admin or developer account of API Maker comes with a sample shop : an instance named mongodb, a database shop with the schemas of categories, customers, products, orders and orderItems, custom APIs under /default/…, hooks, an event, a migration script and a utility class. This page uses it, so you only need a MongoDB to point it at.
Nothing installed yet ?
Install on a server with one command, or run API Maker on your computer with the desktop app. Both print the URL of the admin panel and the sign-in details. The defaults of the install script are [email protected] / Admin_123456789.
In the commands below, $AM is the URL of your API Maker (http://127.0.0.1:38246, or the domain of your server) and admin is the user path of the account.
1. Point the sample instance at a MongoDB¶
- Open the default secret Admin panel → API Security → Secret Management → the secret named
Default. It is TypeScript : acommonobject with keys, connection strings and the passwords of API users. - Set
common.connectionString.mongodbThe sample instance reads its connection string from that path. Paste the string of any MongoDB you can reach (the MongoDB of API Maker Local Run, a MongoDB Atlas cluster, the one the install script created : it is in/root/config/.env). Save.connectionString: { mongodb: 'mongodb://user:[email protected]:27017/?authSource=admin&replicaSet=rs0&directConnection=true', // ... }, - Check the instance API Info → Instance API (DB API) → instance
mongodb→ Test Instance. The databaseshopappears in the list after the first save below : MongoDB creates databases and collections on first write.
2. Get a token¶
The account has an API user named default. Its password is the value of common.apiUserPasswords.default in the secret : 12345 until you change it.
curl -s -X POST "$AM/api/system-api/admin/token" \
-H "Content-Type: application/json" \
-d '{ "u": "default", "p": "12345" }'
{
"success": true,
"statusCode": 200,
"data": { "token": "eyJhbGciOi…", "refresh_token": "eyJhbGciOi…", "expires_in": 259200 }
}
Keep the token in a variable : TOKEN=eyJhbGciOi…. Every call below sends it in x-am-authorization. The group Default of this API user allows every API, which is fine for a first try and wrong for production : see Handle role based permissions.
3. Save a category, then a product¶
The product schema needs a category (a relation to categories._id), a currency from IN, US or GB, and a price_cents. So the category comes first.
curl -s -X POST "$AM/api/schema/admin/mongodb/shop/categories/save-single-or-multiple" \
-H "Content-Type: application/json" -H "x-am-authorization: $TOKEN" \
-d '{ "name": "Accessories" }'
{
"success": true,
"statusCode": 201,
"data": { "_id": "66fa1c2d9b1e4a0012a3c001", "name": "Accessories", "slug": "accessories" }
}
The _id was generated by API Maker (isAutoGenerateByAM) and the slug by the conversionFun of the schema. Now the product :
curl -s -X POST "$AM/api/schema/admin/mongodb/shop/products/save-single-or-multiple" \
-H "Content-Type: application/json" -H "x-am-authorization: $TOKEN" \
-d '{ "name": " Wireless Mouse ", "currency": "in", "price_cents": 129900, "category": "66fa1c2d9b1e4a0012a3c001" }'
{
"success": true,
"statusCode": 201,
"data": {
"_id": "66fa1c9a9b1e4a0012a3c002",
"public_id": "01J8Z3C9F2X4Q7N8V1M6K5R0TA",
"product_no": 1000,
"name": "Wireless Mouse",
"slug": "wireless-mouse",
"status": "DRAFT",
"currency": "IN",
"price_cents": 129900,
"is_active": true,
"created_at": "2026-09-30T10:15:22.418Z",
"updated_at": "2026-09-30T10:15:22.418Z",
"category": "66fa1c2d9b1e4a0012a3c001"
}
}
Look at what the schema did : the name was trimmed, currency upper-cased, status and is_active got their defaults, created_at its default function, product_no the next number of its auto increment, public_id a ULID, slug a value computed from the name. That is the schema pipeline ; the generated APIs under /api/gen would have stored the body as it came.
4. Read it back¶
Get all products, only some fields, with the category populated from its relation :
curl -s "$AM/api/schema/admin/mongodb/shop/products?select=name,slug,price_cents,category&deep=[{s_key:'category'}]" \
-H "x-am-authorization: $TOKEN"
{
"success": true,
"statusCode": 200,
"data": [
{
"_id": "66fa1c9a9b1e4a0012a3c002",
"name": "Wireless Mouse",
"slug": "wireless-mouse",
"price_cents": 129900,
"category": { "_id": "66fa1c2d9b1e4a0012a3c001", "name": "Accessories", "slug": "accessories" }
}
]
}
deep only needed the source key : the target table and key come from the schema. The same filters work as query params on get all, or in the body of the query API :
curl -s -X POST "$AM/api/schema/admin/mongodb/shop/products/query" \
-H "Content-Type: application/json" -H "x-am-authorization: $TOKEN" \
-d '{ "find": { "status": "DRAFT", "price_cents": { "$gte": 100000 } }, "sort": "-created_at", "limit": 10, "getTotalCount": true }'
5. See a refusal¶
Send a product that breaks three rules at once :
curl -s -X POST "$AM/api/schema/admin/mongodb/shop/products/save-single-or-multiple" \
-H "Content-Type: application/json" -H "x-am-authorization: $TOKEN" \
-d '{ "name": "M", "currency": "EUR", "price_cents": -5, "category": "66fa1c2d9b1e4a0012a3c001", "discount_pct": 10 }'
{
"success": false,
"statusCode": 400,
"errors": [
{ "type": "minLength", "field": "name", "message": "Property 'name' should have minimum length of '2'.", "code": 400 },
{ "type": "enumValidation", "field": "currency", "message": "Property 'currency' should have any value from [IN, US, GB].", "code": 400 },
{ "type": "min", "field": "price_cents", "message": "Please provide minimum '0' for 'price_cents' field.", "code": 400 },
{ "type": "invalidValue", "field": "discount_pct", "message": "A discount requires approved_by.", "code": 400 }
]
}
Every problem is reported in one reply, including the message thrown by the validatorFun of discount_pct, and nothing was saved. The messages can be translated per caller with internationalization.
6. Try the rest of the sample¶
- API testing page (
API Info → API Testing) : pick the instance, the table and the API, get a sample payload, send it and read the response, then copy the call as code in 21 languages. - Custom APIs under
API Info → Custom API:/default/deep-populate-orders,/default/find-join-products,/default/caching-example,/default/ws-notify,/default/login… Open one to read a complete, commented example of the feature. They have the access typeNO_ACCESS, so they run from the testing page and from other code, not from outside, except the login and captcha ones. - Hooks : the instance, database and collection hooks of the sample show how a person is kept to their own rows.
- Schemas of the five collections show every schema feature in use.