Errors and pagination
Errors
Failures return a JSON envelope:
{
"defined": false,
"code": "NOT_FOUND",
"status": 404,
"message": "factory not found"
}
code is the stable, machine-readable part — branch on it rather than on message, which is
prose and may be reworded.
| Status | code |
What it means |
|---|---|---|
400 |
BAD_REQUEST |
The request did not satisfy the schema — a missing required parameter, an unknown enum value, a pageSize above the maximum. |
401 |
UNAUTHORIZED |
Missing, malformed, expired, revoked or IP-refused token. See Authentication. |
403 |
FORBIDDEN |
The token is valid, but this caller may not read this resource — or may not use the view they asked for. |
404 |
NOT_FOUND |
No such resource. Also returned for a malformed id, rather than 400. |
500 |
INTERNAL_SERVER_ERROR |
A fault on our side. The details are scrubbed from the response and reported internally. |
Two behaviours worth knowing:
- Some resources answer
404where you might expect403.GET /v1/users/{id}andGET /v1/roles/{id}return "not found" for a record in another organisation, identically to an id that exists nowhere — neither endpoint is usable to probe whether an id names something elsewhere on the platform. - A refused FILTER is a
403, not an empty page. AskingGET /v1/users?roleId=…without organisation administration fails outright rather than quietly returning nothing, because silence would read as "nobody holds that role". - A malformed id is a
404, not a400.GET /v1/factories/not-a-uuidanswers "no such factory", because whether a given string could have been an id is not worth distinguishing from whether it names one. 403and404are chosen deliberately. Where an id exists but is not yours to read, you get403; where it does not exist,404. Do not infer more from the difference than that.
Pagination
Collection endpoints take page (1-based, default 1) and pageSize (default 10, maximum
50). A pageSize above the maximum is a 400, not a silent clamp.
curl "https://api.fieldnode.app/v1/factories?view=CONSUMER&page=2&pageSize=25" \
-H "Authorization: Bearer $FIELDNODE_TOKEN"
Responses carry the page and a hasMore flag:
{
"items": [{ "id": "…", "name": "…" }],
"hasMore": true
}
There is no total count. hasMore is resolved by reading one row past the page, which is cheap
where an exact COUNT(*) over a filtered, permission-scoped set is not. Page until hasMore is
false.
:batch-get endpoints are not paginated — you supply the ids, so you already know how many
there are. They also silently drop ids that are malformed or that you may not read, so a response
may be shorter than the list you sent.
The view parameter
Several collections take a view, naming which side of a record you are looking from — the same
record can be yours as a consumer and someone else's as a manufacturer, and the two answers are
different sets.
| View | Means |
|---|---|
CONSUMER |
Records where your organisation is buying. |
IP_OWNER |
Records where your organisation owns the design. |
MANUFACTURER |
Records where your organisation is producing. |
Two things follow:
- A
viewyou do not hold is a403. Each view is gated on the corresponding permission on the token's owning user. Holding one view says nothing about the others. - A
viewnever widens what you can see beyond your own organisation's relationships — with one deliberate exception.GET /v1/factories?view=CONSUMERis a sourcing catalog: it returns active, non-internal factories belonging to organisations you have no relationship with, because finding them is the point. It never includes another organisation's internal factories.
Where view is optional, omitting it means "any role I hold". Where it is required — factories —
the views are different catalogs rather than two orderings of one, so there is no sensible default.