Conventions
This page describes the conventions shared by the Public API and the Devices API: the response envelope, errors, pagination, filtering, dates and identifiers. Read it once before you write a client.
Response envelope
Both APIs wrap every JSON response in an envelope with a status field, in the style of JSend.
Success:
{
"status": "success",
"data": { "id": 42, "name": "pump-01" }
}
An operation that returns no content answers 204 with {"status": "success"}, or no body.
Error:
{
"status": "error",
"message": "Resource not found"
}
With the fun CLI, add --data-only to print only the data field. See The fun CLI.
Errors
| Status | Meaning | What to do |
|---|---|---|
400 |
The request is malformed | Fix the request |
401 |
The credential is missing, invalid or expired | Get a new token, for example with fun login |
403 |
You are authenticated but your role does not allow this action, or the credential is the wrong kind | Check your role, see Roles and permissions |
404 |
The resource does not exist, or is not in this project | Check the identifiers |
409 |
Conflict with the current state (Devices API) | For example, the device is already provisioned |
422 |
Validation failed | Read errors and fix the listed fields |
429 |
Too many requests (Public API v2) | Wait for the number of seconds in Retry-After, then retry |
500 |
Server error | Retry later. Contact support if it persists |
The Public API v2 adds an errors array to validation failures:
{
"status": "error",
"message": "<summary>",
"errors": [
{ "message": "<what is wrong>", "location": "body.name", "value": "<the value you sent>" }
]
}
The Devices API reports 400 problems in data.errors, each with type, msg, path and location, and 422 problems as an object keyed by field name. See Devices API v3.
Rate limits and quotas
- Rate limit. The Public API v2 limits the request rate per user. Over the limit, it returns
429with aRetry-Afterheader. Back off and retry; do not retry immediately in a loop. - Provisioning quotas. Each registry can cap how many devices of each device type may be provisioned into it, and limit provisioning to a time window (
provisioning_start_at,provisioning_end_at). Set them with the v2registriesoperations. See Public API.
Pagination
List operations are paginated with query parameters:
| Parameter | Description | Default |
|---|---|---|
page |
One-based page number | 1 |
item_per_page |
Items per page | 25 |
The Public API v2 returns a pager object next to data:
{
"status": "success",
"data": [],
"pager": {
"current_page": 1,
"from": 1,
"to": 25,
"total": 120,
"last_page": 5,
"per_page": 25,
"first_page_url": "...",
"last_page_url": "...",
"next_page_url": "...",
"prev_page_url": null
}
}
The Public API v1 returns a pagination object with current_page, from, to, total, last_page and per_page.
Filtering, sorting and relations
Many list operations also accept:
| Parameter | Description | Example |
|---|---|---|
wheres |
Filters, all of which must match. Comma-separated field:operator:value expressions |
name:=:pump-01 |
or_wheres |
Filters, any of which may match | name:=:pump-01,name:=:pump-02 |
order_by |
Sort by a field and direction | created_at:desc |
with |
Comma-separated related resources to include | roles |
with_trashed |
Include deleted records when true |
false |
Not every operation supports every parameter. Check the operation in the OpenAPI spec, or run fun api <version> <group> <operation> --help.
Dates and times
- Timestamps in the Public API are ISO 8601 / RFC 3339 strings in UTC, for example
2026-01-01T12:00:00Z. - Device payloads on MQTT use Unix time in seconds (
timestampin states). - Provisioning keys take dates in
YYYY-MM-DDformat, read as midnight UTC. - Durations are given in the field's unit, stated in the spec (for example, function timeouts are in nanoseconds in the v2 spec).
Identifiers
| Identifier | Format |
|---|---|
| Organization, project, registry, device, device type IDs | Integers |
| Device serial number | Lowercase letters, digits, - and _. Unique within a registry |
| Function ID | Opaque string, for example mvtvNUX9oWa9yFpdVLXYuR |
| Provisioning key | UUID |
Path parameter names follow each API version: the Public API v1 uses camelCase ({projectId}), v2 and the Devices API use snake_case ({project_id}). The fun CLI turns both into kebab-case flags (--project-id).
Operations that do something other than create, read, update or delete use a :verb suffix, for example POST /v1/projects/{projectId}/actions/{actionId}:retry or POST /v2/projects/{project_id}/functions/{function_id}:invoke.
Authentication
Every request carries Authorization: Bearer <token>. Which token depends on the API and the endpoint: see Authentication, Public API and Devices API v3.