Resource names
Every resource on SPEKTRA Edge has one canonical name, and that name is the
only identifier you need. It is the path in a REST URL, the name field in a
gRPC request, and the argument you pass to cuttle. Learn to construct one and
most of the API stops needing to be looked up.
The shape of a name
A name is an alternating sequence of collection and identifier segments, reading left to right from the outermost scope inward:
projects/acme-retail/regions/us-west2/devices/till-004
which is to say: the device till-004, in region us-west2, of project
acme-retail. Collections are plural and lowerCamelCase; identifiers are
yours.
Because the structure is regular, you can read the parent of any resource by
dropping the last two segments — the parent of that device is
projects/acme-retail/regions/us-west2.
Name scopes
How many segments a name has depends on the resource, and this is the single
most common cause of a confusing NOT_FOUND. There are four patterns.
| Pattern | Example | Notes |
|---|---|---|
| Global | projects/acme-retail |
Projects, organizations, and read-only catalogs such as device types and OS versions. |
| Project | projects/acme-retail/distributions/pos-app |
Project-wide, not tied to a region. |
| Project and region | projects/acme-retail/regions/us-west2/devices/till-004 |
Most operational resources. |
| Nested under another resource | projects/acme-retail/regions/us-west2/serviceAccounts/automation/serviceAccountKeys/ci |
The parent is itself a full name. |
Some resources nest more deeply than you might expect. An alerting condition lives under a policy, and an alert lives under a condition:
projects/{project}/regions/{region}/alertingPolicies/{policy}/alertingConditions/{condition}/alerts/{alert}
A few resources accept more than one kind of parent, though any single instance has exactly one. A role binding can be scoped to a project, an organization, or a service:
projects/{project}/roleBindings/{roleBinding}
organizations/{organization}/roleBindings/{roleBinding}
services/{service}/roleBindings/{roleBinding}
When in doubt, the per-resource entry under Service APIs lists the name patterns it accepts.
Names are permanent
A name identifies a resource for its whole life and cannot be changed. Anything
you might want to edit later — a human-readable label, a location, ownership —
belongs in a field such as displayName, not in the name.
On create you may either supply the final identifier or omit it and let the platform generate one. Supply it when the name should be predictable from something you already know, such as a store number; omit it when the resource is one of many and you will find it by filtering on labels instead.
Identifier segments are constrained. For most resources the last segment must match:
[a-z][a-z0-9\-]{0,28}[a-z0-9]
Lower case, starting with a letter, ending alphanumeric, at most 30 characters. Some resources differ — service accounts also allow underscores and permit longer names — so check the resource’s reference entry before generating identifiers programmatically.
Wildcards in collection requests
When reading a collection you can substitute - for an identifier to mean
“across all of them”. This is how you query a whole project without knowing its
regions:
# Devices in one region
cuttle devices list devices --parent projects/$PROJECT/regions/us-west2
# Devices in every region of the project
cuttle devices list devices --parent projects/$PROJECT/regions/-
It works at any level, which matters most for the deeply nested resources. Listing alerts across every policy and condition in a project would otherwise require enumerating both:
cuttle monitoring list alerts \
--parent "projects/$PROJECT/regions/-/alertingPolicies/-/alertingConditions/-"
Wildcards apply to reads. Creating, updating, or deleting requires a fully specified name.
From a name to a REST URL
REST paths are the resource name with a version prefix, so once you can build a
name you can build a URL. Every service answers on its own host, shaped
{service}.apis.edgelq.com.
The version prefix belongs to the service, not to the platform, so do not
assume v1 everywhere. Most services are on v1, but Monitoring is on v4
(https://monitoring.apis.edgelq.com/v4/...). Check the service’s page under
API reference before building URLs by hand.
| Operation | Method and path |
|---|---|
| Get | GET /v1/projects/{project}/regions/{region}/devices/{device} |
| List | GET /v1/projects/{project}/regions/{region}/devices |
| Create | POST /v1/projects/{project}/regions/{region}/devices |
| Update | PUT /v1/projects/{project}/regions/{region}/devices/{device} |
| Delete | DELETE /v1/projects/{project}/regions/{region}/devices/{device} |
Anything that is not plain CRUD is a verb appended after a colon, which is why these URLs look unusual at first:
GET /v1/projects/{project}/regions/{region}/devices:search
GET /v1/devices:batchGet
POST /v1/projects/{project}/regions/{region}/devices:watch
POST /v1/projects/{project}/regions/{region}/devices/{device}:getDedicatedEndpoints
Two consequences follow. batchGet is not scoped to a parent —
it takes the names you want as parameters, so it can span regions in one call.
And some read-only operations are POST, because their request does not fit in
a URL; projects:listMy is the one you are most likely to meet.
Regions
A project belongs to a region, and most operational resources are created within one. The region in a name is not a routing hint you may omit — it is part of the resource’s identity, and the same identifier in two regions is two different resources.
Practically:
- Use the region your project reports. It is shown in the dashboard and in the project resource itself.
- To search across regions, use the
-wildcard instead of looping. - Secrets do not replicate across regions, so a multi-region fleet needs the secret created in each region its devices occupy. See Secrets.
Next steps
- Reading resources — filters, field masks, and pagination.
- Errors and limits — including why a name problem usually
surfaces as
NOT_FOUND.