# Your First API in 10 Minutes

> A hands-on start with the sample shop every new API Maker account has - connect MongoDB, get a token, save a category and a product through the schema APIs, read them back with filters and deep populate, and see a validation error.

Source: https://docs.apimaker.dev/v1/docs/getting-started/first-api.html

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.

> **Tip : Nothing installed yet ?**
>
> [Install on a server](https://docs.apimaker.dev/v1/docs/getting-started/install-on-server.html) with one command, or [run API Maker on your computer](https://docs.apimaker.dev/v1/docs/getting-started/local-run.html) with the desktop app. Both print the URL of the admin panel and the sign-in details. The defaults of the install script are `admin@admin.com` / `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

1. **Open the default secret** Admin panel → **API Security → Secret Management** → the secret named `Default`. It is TypeScript : a `common` object with keys, connection strings and the passwords of API users.
2. **Set `common.connectionString.mongodb`** The 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.

    ```typescript
    connectionString: {
        mongodb: 'mongodb://user:password@127.0.0.1:27017/?authSource=admin&replicaSet=rs0&directConnection=true',
        // ...
    },
    ```
3. **Check the instance** **API Info → Instance API (DB API)** → instance `mongodb` → **Test Instance**. The database `shop` appears 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.

```bash
curl -s -X POST "$AM/api/system-api/admin/token" \
  -H "Content-Type: application/json" \
  -d '{ "u": "default", "p": "12345" }'
```

```json
{
    "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](https://docs.apimaker.dev/v1/docs/authorization/handle-role-based-permissions.html).

## 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.

```bash
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" }'
```

```json
{
    "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 :

```bash
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" }'
```

```json
{
    "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](https://docs.apimaker.dev/v1/docs/schema/schema.html) ; 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 :

```bash
curl -s "$AM/api/schema/admin/mongodb/shop/products?select=name,slug,price_cents,category&deep=[{s_key:'category'}]" \
  -H "x-am-authorization: $TOKEN"
```

```json
{
    "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 :

```bash
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 :

```bash
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 }'
```

```json
{
    "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](https://docs.apimaker.dev/v1/docs/i18/i18.html).

## 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 type `NO_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.

## Where to go next

- [All APIs at a glance](https://docs.apimaker.dev/v1/docs/apis-all/overview.html) : Every operation of a table, with its method and URL.
- [Table schema](https://docs.apimaker.dev/v1/docs/schema/schema.html) : Write the schema of your own tables.
- [Custom APIs](https://docs.apimaker.dev/v1/docs/apis-all/custom-apis/user-created-custom-api.html) : Your first TypeScript function behind a URL.
- [Role based permissions](https://docs.apimaker.dev/v1/docs/authorization/handle-role-based-permissions.html) : Replace the Default group before going live.
