Organizations & Device Groups

Structure your fleet: use organizations as sub-accounts and device groups to cluster trackers by route, terminal, or customer.

Organizations & device groups

As a fleet grows from a handful of trackers to hundreds of reefers across several terminals, two concepts keep it organized:

  • Organizations — sub-accounts that isolate devices and their data (e.g. one per customer or region).
  • Device groups — lightweight clusters of devices within an organization (e.g. one per route or cold-storage terminal).

Both are managed through the Platform API (https://api.surfact.com/api/v2.0/).

GoalEndpointMethod
Retrieve an organization (account-scoped token only — see below)/organizations/{organization_id}/GET
List an organization's devices/organizations/{organization_id}/devices/GET
List / create device groups/device_groups/GET / POST
Retrieve / update / delete a device group/device_groups/{device_group_id}/GET / PATCH / DELETE
List devices in a group/device_groups/{device_group_id}/devices/GET
Add devices to a group/device_groups/{device_group_id}/_/assign_devices/POST
Remove devices from a group/device_groups/{device_group_id}/_/remove_devices/POST

Look inside an organization

List everything that belongs to an organization — this works with an ordinary API token:

curl -X GET 'https://api.surfact.com/api/v2.0/organizations/~nordic-cold-chain/devices/' \
  -H 'X-Auth-Token: your_token_here'

The same pattern works for the organization's dashboards (/organizations/{organization_id}/dashboards/).

Reading the organization object itself is a separate matter:

curl -X GET 'https://api.surfact.com/api/v2.0/organizations/~nordic-cold-chain/' \
  -H 'X-Auth-Token: your_token_here'
🚧

Permission denied on the organization object

With an ordinary API token, both GET /organizations/ and GET /organizations/{organization_id}/ return 403, regardless of whether you address the organization by id or by ~label:

{ "detail": "You do not have permission to perform this action." }

Note that this body carries a detail field rather than the code / message pair the other errors use. Reading the organization object requires an organization- or account-scoped token. The sub-resources above (/devices/, /dashboards/) are unaffected and return 200 for every reader, so use those when you only need the organization's contents.

Group devices by route or terminal

Device groups make it easy to monitor a slice of the fleet together — say, every reefer running frozen routes:

curl -X POST 'https://api.surfact.com/api/v2.0/device_groups/' \
  -H 'Content-Type: application/json' \
  -H 'X-Auth-Token: your_token_here' \
  -d '{
    "label": "nordic-frozen-fleet",
    "name": "Nordic Frozen Fleet",
    "organization": "~nordic-cold-chain",
    "tags": ["frozen"]
  }'

A new group starts empty. Membership is not set through the group's devices field — that field is read-only, and a PATCH containing it is silently ignored. Use the dedicated assignment endpoint instead:

curl -X POST 'https://api.surfact.com/api/v2.0/device_groups/~nordic-frozen-fleet/_/assign_devices/' \
  -H 'Content-Type: application/json' \
  -H 'X-Auth-Token: your_token_here' \
  -d '[
    "~reefer-trailer-21",
    "~reefer-trailer-22",
    { "id": "6865acef80bcac000f4ca5db" }
  ]'

Each entry may be a device id, a ~label, or an object with an id — you can mix all three in one call. The response is a paginated list of the devices now in the group:

{
  "count": 3,
  "next": null,
  "previous": null,
  "results": [
    {
      "url": "https://api.surfact.com/api/v2.0/devices/6865acf980bcac000f4ca5ec",
      "id": "6865acf980bcac000f4ca5ec",
      "label": "reefer-trailer-21",
      "name": "Reefer Trailer 21",
      "createdAt": "2026-01-15T08:30:00Z"
    }
  ]
}

By default the devices you send are appended to the group. Pass ?clear=true to replace the whole membership with exactly the devices in the request:

curl -X POST 'https://api.surfact.com/api/v2.0/device_groups/~nordic-frozen-fleet/_/assign_devices/?clear=true' \
  -H 'Content-Type: application/json' \
  -H 'X-Auth-Token: your_token_here' \
  -d '["~reefer-trailer-21"]'

Take devices back out with remove_devices, which accepts the same three identifier forms and returns an empty result set:

curl -X POST 'https://api.surfact.com/api/v2.0/device_groups/~nordic-frozen-fleet/_/remove_devices/' \
  -H 'Content-Type: application/json' \
  -H 'X-Auth-Token: your_token_here' \
  -d '["~reefer-trailer-22"]'

List the members of a group at any time:

curl -X GET 'https://api.surfact.com/api/v2.0/device_groups/~nordic-frozen-fleet/devices/' \
  -H 'X-Auth-Token: your_token_here'
📘

Device groups are also the cleanest target for fleet-wide alerts — an event can watch a whole group's temperature variable instead of each device individually.

Organizations vs. device groups

OrganizationDevice group
PurposeIsolation (a separate account boundary)Convenience clustering within an account
Hard access boundaryYesNo
Typical cold-chain useOne per customer or countryOne per route, terminal, or temperature class

Use an organization when you need a hard boundary (a customer shouldn't see another customer's reefers); use a device group when you just want to slice your own fleet for monitoring and alerts.


Did this page help you?