S
Core Concepts

Responses

The shape of success responses, pagination metadata and how fields are kept out of the output

Every handler that StarkForge provides answers in the same JSON shape. A client reads success to see the outcome, shows message to a person and takes the result from data, without learning a new format for each route. This page describes that shape, how lists are paginated, which fields never appear in a response and which headers come with it. Failures have a shape of their own, described in Errors.

The Response Envelope

A request for one product shows every part of the shape:

Text
GET /api/v1/products/665f1c2e8b3a4d0012a10001
Text
HTTP/1.1 200 OK
Content-Type: application/json

{
  "success": true,
  "message": "Product fetched successfully.",
  "data": {
    "name": "Mechanical keyboard",
    "price": 89.9,
    "sku": "KB-001",
    "_id": "665f1c2e8b3a4d0012a10001",
    "createdAt": "2026-01-15T10:30:00.000Z",
    "updatedAt": "2026-01-15T10:30:00.000Z"
  }
}
KeyPresentMeaning
successAlwaystrue for every success response. Error responses use false
messageAlwaysOne sentence for people, such as Product fetched successfully.
dataWhen the handler has a resultA document, a list of documents, or a small object such as { deleted: 2 }
metaLists onlyThe pagination numbers described below
Other keysSome sign-in responsesaccessToken and refreshToken when you turn them on, mfaRequired and mfaToken when a second factor is needed, resetToken after a password reset code is verified

A response has no data key when the handler has nothing to return. Signing out is the example, and it also clears both session cookies:

Text
POST /api/v1/auth/logout
Text
HTTP/1.1 200 OK
Content-Type: application/json

{
  "success": true,
  "message": "Logged out successfully."
}
Messages Are for People

Show message to a person if you like, but make decisions in code from success, the HTTP status and, for failures, the error code. Only error codes are documented as stable.

Status and Message by Handler

A handler always answers with the same status and message pattern. Product in the messages is the model name of the collection, and the numbers are counts:

HandlerStatusMessagedata
read200Product fetched successfully.The document
readAll200Product list fetched successfully.A list of documents, with meta
create201Product created successfully.The new document
createBulk2012 Product items created successfully.A list of the new documents
update200Product updated successfully.The document after the change
remove200Product deleted successfully.The deleted document
removeMultiple, removeAll2002 Product items deleted.{ deleted: 2 }
addFile, updateFile, deleteFile200File added successfully., File updated successfully., File deleted successfully.The document with its file list

The account and sign-in handlers follow the same shape with messages of their own.

Lists and Pagination

readAll returns one page at a time. This request asks for the first page of two products, most expensive first:

Text
GET /api/v1/products?page=1&limit=2&sort=-price
Text
HTTP/1.1 200 OK
Content-Type: application/json

{
  "success": true,
  "message": "Product list fetched successfully.",
  "data": [
    {
      "name": "Mechanical keyboard",
      "price": 89.9,
      "sku": "KB-001",
      "_id": "665f1c2e8b3a4d0012a10001",
      "createdAt": "2026-01-15T10:30:00.000Z",
      "updatedAt": "2026-01-15T10:30:00.000Z"
    },
    {
      "name": "Desk lamp",
      "price": 34,
      "sku": "LP-003",
      "_id": "665f1c2e8b3a4d0012a10003",
      "createdAt": "2026-01-15T10:30:00.000Z",
      "updatedAt": "2026-01-15T10:30:00.000Z"
    }
  ],
  "meta": {
    "page": 1,
    "limit": 2,
    "total": 3,
    "pages": 2
  }
}

Three query parameters control the page. All of them are optional:

ParameterDefaultRule
page1A whole number from 1 up, written with digits only
limit50A whole number from 1 up. A value above 100 is lowered to 100 without an error
sort-createdAt,-_idA comma-separated list of up to five fields. A leading - sorts in descending order

The two limits are the options defaultPageSize and maxPageSize, described in Configuration. You can sort by _id, createdAt, updatedAt and every field of the schema, except fields that a client could not read: secret, hashed, encrypted and hidden fields. Read All covers sorting in full.

The meta object describes the whole list, not only the page:

KeyMeaning
pageThe page that this response holds
limitThe page size in effect, after the maximum is applied
totalHow many documents match, across all pages
pagesHow many pages there are. It is never less than 1

A broken query answers 400 with the code INVALID_QUERY:

RequestMessage
?page=0'page' must be a positive integer.
?limit=2e3'limit' must be a positive integer.
?sort=secretFieldCannot sort by 'secretField'. The hint lists the fields that can be sorted
Stop at the End

A page past the end is not an error. It answers 200 with an empty data list and the same meta, and an empty collection answers with total 0 and pages 1. Compare meta.page with meta.pages to know when to stop.

What a Response Never Contains

StarkForge cleans every document before it writes the response. These fields are removed, whatever the client asks for:

RemovedWhy
password, tokenHash, codeHash and resetTokenHashCredentials and token digests never leave the server, and a route cannot opt back in
Any text that starts with $argon2Password hashes are dropped wherever they appear, including inside nested objects
Fields with select: falseThe database does not load them, and a response never includes them
Hashed fieldsA field that a route lists in hashedFields is hidden for the whole collection
Encrypted valuesA sealed value is removed unless the route lists the field in decryptedFields. Sealed values inside nested objects, such as a populated document, are always removed
__vThe Mongoose version key is hidden unless a route opts back in with "!__v" in hiddenFields

A route can hide more. Add config: { hiddenFields: ["internalNotes"] } to remove a field from the responses of that route only, and put "_id" in the list to drop the id too. A reference field normally holds an id. With config: { populate: "owner" } the response holds the referenced document instead, limited to the fields in populateSelect, which defaults to _id so that personal data does not leak by accident. Relations and Hidden and Encrypted Fields cover both in depth.

An after action can also replace data before the response is sent. Actions explains how.

Headers

Every response carries headers that help with debugging and with clients that retry. This is the start of the response to a list request under the default limits:

Text
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
X-Request-Id: ad7a9c50-3964-49ef-a597-cda43ad4317f
RateLimit: limit=100, remaining=99, reset=900
RateLimit-Policy: 100;w=900
HeaderWhenMeaning
X-Request-IdEvery responseIdentifies the request in the logs. StarkForge reuses the id that a client sends when it is 8 to 64 letters, digits, underscores or dashes, and makes a UUID otherwise. Error bodies repeat it as requestId
RateLimit and RateLimit-PolicyEvery responseThe allowed requests, the requests left and the seconds until the window resets, in the format of the IETF rate limit draft. The example shows the default of 100 requests per 15 minutes for each IP address
Retry-After429 responsesThe seconds to wait before trying again
Set-CookieSession responsesSets or clears the accessToken and refreshToken cookies
Cache-Control: no-storeSocial sign-in, magic link redemption and the two-factor routes that set up, enable, verify or replace codesKeeps browsers and proxies from storing a response that carries sign-in material

StarkForge also sets the standard secure headers of helmet, such as X-Content-Type-Options and Strict-Transport-Security.

Field Formats

An _id is a string of 24 hexadecimal characters. Dates such as createdAt and updatedAt are ISO 8601 text in UTC, like 2026-01-15T10:30:00.000Z. Numbers, booleans and arrays keep their JSON types.

Where to Go Next

Read All

List documents with pages, sorting and ownership rules.

Hidden and Encrypted Fields

Control which fields leave the server and encrypt secrets at rest.

:::