Auth API · stations

What an enrolled device shows on its lock screen

POST /api/auth/station/roster

What an enrolled device shows on its lock screen: the station as enrolled, and the people who may unlock it — the organization's active members with a station PIN whose roles open its view.

401 StationCredentialInvalid for an unknown credential or a revoked station, 400 InvalidStation for a malformed body. Appends nothing: a read that carries the device's credential in its body, which a GET could not. No idempotency key: a retry reads the roster again and appends nothing.

Access

Public: The enrolled device's own credential, verified by the route before anything is read: a station signs in as itself, and nobody is signed in on it yet

No token: the link, the claim or the first message is the credential, as the description says.

How scopes come from roles: Scopes and roles. Getting a token: Authentication and app tokens.

Retries

No idempotency key: a retry reads the roster again and appends nothing.

Why every write carries a key: Idempotency and retries.

Facts appended

None. This call records nothing in a journal.

What a fact is: Facts and the journal.

AI agent tool

No agent tool. A station's lock screen, read by the enrolled device under its own credential; no person or agent holds that credential, and an agent works no station.

Connecting an agent: AI agents.

Example

From Set up a station and unlock it with a PIN, step 6: Show the lock screen.

curl
curl -X POST 'https://auth.getmanifold.io/api/auth/station/roster' \
  -H 'Content-Type: application/json' \
  -d '{
  "credential": "stc_Qm9vdGgtMi1pbi10aGUtd2FyZWhvdXNl"
}'
JavaScript (fetch)
const response = await fetch("https://auth.getmanifold.io/api/auth/station/roster", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    "credential": "stc_Qm9vdGgtMi1pbi10aGUtd2FyZWhvdXNl"
  }),
});
if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);
const answer = await response.json();
Request body · application/json
{
  "credential": "stc_Qm9vdGgtMi1pbi10aGUtd2FyZWhvdXNl"
}
Response · 200 · application/json
{
  "station": {
    "stationId": "stn_01a1586e-f9f6-7a8b-9c7d-6e5f4a3b2c1d",
    "view": "pick-pack",
    "locationId": "loc_01a15852-46d1-7a3b-9c0d-1e2f3a4b5c6d",
    "name": "Packing bench 2",
    "enrolledAt": "2026-08-17T09:00:00.000Z",
    "enrolledBy": "usr_01a15869-1d2e-7f3a-8b4c-5d6e7f8a9b0c"
  },
  "people": [
    {
      "userId": "usr_01a15869-1d2e-7f3a-8b4c-5d6e7f8a9b0c",
      "name": "Avery Lin"
    }
  ]
}

The panel writes this call in other languages. It does not send it: Manifold's APIs do not take calls from a web page on another site, so run the call from your own code or terminal. The whole API as OpenAPI: auth-service.openapi.json. Base URL https://auth.getmanifold.io.

Errors

Every refusal is a status and a JSON body whose _tag names it. A refused call changes nothing.

400

RefusalWhat it meansWhat to do
InvalidStation reason The request was refused. reason says why.Fix the request. Sending it again unchanged gets the same answer.

401

RefusalWhat it meansWhat to do
StationCredentialInvalid reason The request was refused. reason says why.Nothing changed.

How refusals work everywhere: Errors.

Used in