Aerovy Platform logo

Resource filters

How to restrict which resources an API key can touch.

To control what an API key can do, you give it scopes. Each scope has two parts:

  • action: read, write, admin, or * (any action).
  • resourceFilter: a path that says which resources the action applies to.

The resource filter is the part you tune to limit a key. A scope of write on PLACE/Site/<siteId>/THING/#/# lets the key write to any Thing in that one site, and nothing else.

Filter syntax

A filter is a /-separated path of resource segments, from the outside in:

TYPE/qualifier/id/TYPE/qualifier/id/…
  • Each resource is a type token (uppercase) followed by its qualifier and id segments.
  • # is the wildcard. It matches any value in that segment.
  • The path is always scoped to your organization. A key can't reach another org's data, so you don't write the org into the filter.

For example, PLACE/Site/<siteId>/THING/Battery/# reads as: any Battery Thing, in the site <siteId>.

Resource types

TypeSegmentsExample
PLACEPLACE/{placeType}/{placeId}PLACE/Site/<siteId>
THINGTHING/{thingType}/{thingId}THING/Battery/<thingId>
TRANSACTIONTRANSACTION/{transactionType}/{transactionId}TRANSACTION/CommerceInvoice/#
MONITORMONITOR/{monitorId}MONITOR/#
INTEGRATIONINTEGRATION/{direction}/{type}/{integrationId}INTEGRATION/INGRESS/#/#
SIMULATIONSIMULATION/{simulationId}SIMULATION/#
DEFINITIONDEFINITION/{definitionType}/{definitionId}DEFINITION/Metric/#
COMMERCECOMMERCECOMMERCE
ORGANIZATIONORGANIZATION/{orgId}ORGANIZATION/#
TENANTTENANTTENANT

Some segments only accept a fixed set of values, checked when you create the key:

  • placeType: Site or Fleet.
  • definitionType: Metric, ThingType, or ThingTypeVersion.
  • direction: INGRESS or EGRESS.
  • transactionType: a known transaction type (e.g. CommerceInvoice, BatterySwapReservation).

An unknown value is rejected. Use # when you don't want to pin a value.

Wildcards

# in a scope matches any value in the request. A specific value must match exactly (case-insensitive). Use # to widen a scope and specific ids to narrow it.

FilterCovers
PLACE/#/#Every place (any type, any id)
PLACE/Site/#Every site
PLACE/Site/<siteId>One site
THING/#/#Every Thing
THING/Battery/#Every Battery
THING/#/<thingId>One Thing, whatever its type

Nesting

Filters can nest a child resource under its parent. Only these parent → child pairs are valid:

ParentChild
PLACETHING
PLACE or THINGMONITOR
any type (except TRANSACTION)TRANSACTION
ORGANIZATIONORGANIZATION

So these are valid composite filters:

  • PLACE/Site/<siteId>/THING/#/#: all Things in one site.
  • PLACE/Site/#/THING/Battery/#/MONITOR/#: monitors on any Battery in any site.
  • PLACE/Fleet/<fleetId>/THING/#/#/TRANSACTION/#/#: all transactions on Things in a fleet.

A Thing can also stand on its own (THING/Battery/<thingId>) when you don't need to pin the place.

How matching works

Each protected endpoint declares the action it needs and the resource it touches. At request time, the platform fills the resource ids in from the request, then checks your key:

  1. The scope's action must match the endpoint's action, or be *.
  2. The scope's resource filter must cover the endpoint's resource: every segment is either # or an exact match, and the hierarchy lines up.

A key is allowed if any one of its scopes covers the request. Otherwise the request gets 403 Forbidden. Scopes are additive: list several to grant several areas.

Configuring filters on a key

You set filters when you mint a key, in the scopes list:

{
  "keyType": "External",
  "name": "depot-ingest-bot",
  "scopes": [
    { "action": "write", "resourceFilter": "PLACE/Site/<siteId>/THING/#/#" },
    { "action": "read",  "resourceFilter": "PLACE/Site/<siteId>/THING/#/#" }
  ],
  "allowedIpCidrs": [],
  "expiresAt": null
}

This key can read and write any Thing in <siteId>, and nothing else. Each filter is validated for shape and type tokens when the key is created or updated; an invalid filter is rejected. See API fundamentals for the rest of the API key fields (key type, IP allow-list, expiry).

Limitations

  • The wildcard is #. The * wildcard is for the action, not the path.
  • A filter must name a resource type. There is no bare global wildcard.
  • DEFINITION/#/# is rejected: name a definitionType (e.g. DEFINITION/Metric/#).
  • Type tokens (placeType, definitionType, direction, transactionType) are validated against known values. Ids are not: a filter can name an id that doesn't exist.
  • Only the parent → child pairs above can nest.
  • Every filter is bound to your organization. A key can't grant access to another org.