Skip to content

HTTP API reference

This is the reference for the Port OS REST API, for controlling and managing devices and groups.

The Port OS API is designed around REST. Our API has resource-based URLs, accepts JSON request bodies, returns JSON-encoded responses, and uses standard HTTP status codes, authentication, and verbs.

You can use Port OS with your account from anywhere, whether you're working in the cloud or on your computer.

Just getting started? Please see API quick start, or Guide for agents for more. See Simulators to create a test device or Tokens to create a test token.

Prefer a small compact index? See the compact guide.

Want to integrate devices with AI agents? Please see the Port OS MCP guide, or agent-specific guides.

OAuth

Port OS uses authentication tokens to access APIs. Customers that want to access Port OS can either create one-off access tokens or use OAuth 2.0.

Customers that want to use Port OS for services like AI or websites should use OAuth 2.0 to connect to Port OS. See the official OAuth 2.0 guide for how OAuth works. To use the Port OS APIs, you must register an OAuth client.

Authentication is how a client gets a token.

Port OS supports these OAuth flows:

  1. website auth: authorization code flow with PKCE
  2. device auth: device code flow
  3. cloud AI agent auth: CIMD (Client ID Metadata Documents)
  4. legacy cloud AI agent auth: DCR (Dynamic Client Registration) — prefer CIMD, DCR is deprecated.

Every flow uses the OAuth endpoints listed beside this text: discover the server from its metadata, obtain a token from the token endpoint, then send it on each API call in the Authorization header as a bearer token.

Authorization is separate from authentication: it decides what a token may do once the client has one. Port OS has a two-layer authorization system:

  1. each token has a set of scopes (see OAuth permission scopes) that set which APIs it can use
  2. each resource has access control rules that govern who can use it.

Access controls let customers write granular rules, such as:

  1. only bob may see this light
  2. only claude may see the battery level of my devices

See Access control for more.

OAuth permission scopes

RESTful APIs on Port OS require permission scopes. When performing an OAuth exchange with the Port OS OAuth endpoints, include the scopes your requests need.

Each endpoint in the Port OS RESTful interface lists the scope it requires.

Port OS uses a two-layer authorization mechanism: the first layer is the scope permissions on the token, and the second is a series of granular access control rules. See Access control for more.

Pagination

Error Handling

Versioning

Devices

Device APIs read and control the devices and groups in your account.

Endpoints

v1.0

Enumerate Endpoints

View source specification ↗
GET /endpoints

List the endpoints that a customer has access to. For example, you enumerate to list the customer's lights, vacuums, or similar devices.

Endpoints contain information such as:

  1. The endpoint's name, description, and other top-level data.
  2. The capabilities the endpoint has, like power, camera, etc.
  3. The state of the endpoint.

Usage of the API is controlled by the query parameters. By default it lists enabled endpoints owned by the authenticated user. Type and serialNumber filters stay within that scope. An explicit owner can select another owner's endpoints when the caller can read them.

An exact id lookup takes precedence over the owner, type, serialNumber, and enablement filters. It can return a readable shared endpoint, including a disabled one, but still requires endpoint-read permission.

To retrieve the state of a specific endpoint, send id=<endpoint-id> together with expand=interfaces.attributes. Add forceDeviceAttributeQuery=true to refresh that state from the device before the response is returned.

Required scope

endpoint:read

Query parameters

enablementstring

Filter the results by enablement. Enablement is a customer setting that stops Port OS from using a resource without deleting it. Port OS uses it in place of deletion because it cannot delete a device on the provider's side. Defaults to ENABLED. Use DISABLED to list only disabled resources, or '*' to include both enabled and disabled resources. Looking up a resource by its exact id ignores this filter.

Default: ENABLED

Allowed values: ENABLED, DISABLED, *.

ownerstring

Filter the results by the owner of the resource. Defaults to the authenticated caller's resources when omitted. Use '~caller' to make that scope explicit. Another owner can be selected only for resources the caller can read.

idstring

The unique identifier of a specific endpoint to retrieve. When provided, this exact-ID filter takes precedence over owner, type, serialNumber and enablement filters. It can return a shared or disabled endpoint when the caller has endpoint-read permission.

typestring

Filter endpoints by their primary type

serialNumberstring

Filter endpoints by their serial number

nextTokenstring

Opaque server-issued continuation token. Repeat the same selection, page size, expansion, force-refresh setting and authenticated grant. Modified, expired or differently bound tokens return 400; restart without nextToken.

minLength: 1

maxResultsinteger

The maximum number of results to return, from 1 through 100.

minimum: 1

maximum: 100

expandarray<string>

Expand determines what data we retrieve for each endpoint. Use `interfaces.attributes` to populate each endpoint's `attributes` array so you can, for example, find their states. When omitted, the response returns only a limited set of data.

uniqueItems: true

includeChildEndpointsboolean

A list returns root endpoints only: an endpoint that is part of another endpoint (for example an oven cavity of its range, which reports `parentEndpointId`) is left out so one physical device is one entry, and the parent lists its parts in `childEndpointIds`. Send `true` to list those parts too. An exact `id` lookup always returns the endpoint it names, part or not. A part whose parent the caller cannot read is still listed.

Default: false

forceDeviceAttributeQueryboolean

Forces a live device-backed attribute refresh for endpoint-state queries. This makes Port OS call into the device to get its data, if the device provider does not update the state automatically. This flag is only applied when `expand` includes `interfaces.attributes`. Send `true` to force the refresh; absent or `false` values use stored state. Invalid values, or `true` without the required expansion, return 400. A forced read asks the provider; it cannot make a provider's old sample newer. Each returned attribute carries `sampledAt` and `freshness`: treat a `STALE` value as the provider's last known reading, not the present state. When the provider answers a forced read but gives no value for a declared, requested attribute, that attribute is returned with no `value` and an `error` whose code is `PROVIDER_NO_STATE`. It is not omitted and the request does not fail; treat the state as unknown.

Returns

200

Endpoints retrieved successfully. Responses without expand=interfaces.attributes return the default shallow endpoint shape. Responses with that expansion populate deep attribute state in each endpoint's attributes array. If endpoint enumeration succeeds but one or more forced deep-query items fail, the response can include an errors array describing those partial state-refresh failures; request-level failures still use HTTP error responses.

Fields
resultsarray<Endpoint>Required
paginationContextPaginationContext
errorsarray<EndpointQueryResponseError>

Partial deep-query failures collected while building expanded endpoint state. This field is present only when endpoint enumeration succeeded but one or more live attribute refresh items failed; request-level failures still use HTTP error responses.

Errors

400 BAD_REQUEST

Missing or malformed endpoint query parameters

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Unauthorized - invalid or missing authentication token

Obtain a valid access token, then retry.

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Upsert Endpoint

View source specification ↗
POST /endpoints

Creates or updates an endpoint.

Required scope

endpoint:write

Request body

Fields
idstringRequired

The endpoint ID

nameTypeValue
typestring

The endpoint type

Returns

200

Endpoint upserted successfully

No response body.

Errors

400

Invalid request payload

Check the request fields and any validation details, then correct the payload.

500

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Modify Endpoint

View source specification ↗
PATCH /endpoints

Apply endpoint partial metadata, enablement or merge changes in one SQLite transaction. At least one field besides id is required. An empty 202 is returned only after commit; clients may requery metadata. Endpoint updated notifications are best effort. A merge cannot cross owners or silently rewrite unsupported dependencies; conflicts roll back all changes.

Required scope

endpoint:write

Request body

Fields
idstringRequired

Endpoint to modify; merge source when mergeInto is provided.

namestring

minLength: 1

maxLength: 64

pattern: "^[a-zA-Z0-9 \\-_]+$"

typestring

A supported endpoint ontological type, such as light or plug.

enablementstring

Whether Port OS uses an endpoint or group. A disabled one is hidden from collections by default and cannot be sent device messages or targeted by them; exact authorized reads still return it. Rediscovery never changes it, so disabling is how a user hides a discovered device or room for good.

Default: ENABLED

Allowed values: ENABLED, DISABLED.

mergeIntostring

Same-owner surviving endpoint. Routes and supported dependencies transfer atomically; the source remains disabled. Other supplied fields modify the survivor. No redirect from the source ID is created.

Returns

202

Endpoint modification committed; empty response.

No response body.

Errors

400

Invalid partial update or incompatible merge.

Check the request fields and any validation details, then correct the payload.

401

Authentication required.

Obtain a valid access token, then retry.

403

Endpoint management or dependency permission denied.

Check the linked account and its permissions for the device or resource.

404

Endpoint not found.

Verify the target identifier and that its endpoint or plugin route still exists.

409

Dependent state prevents merge; nothing changed.

Check the device’s current mode or state. Retry only after the conflict is resolved.

500

Modification failed before commit.

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

503

ENDPOINT_COMMITTED_CLEANUP_PENDING. The modification committed, but required active-work cleanup is pending. Re-read source and target before retrying.

Wait for the provider or bridge to recover, then retry safely with backoff.

Delete Endpoint

View source specification ↗
DELETE /endpoints

Deletes an endpoint.

Required scope

endpoint:write

Request body

Fields
idstringRequired

The endpoint ID to delete

Returns

200

Endpoint deleted successfully

No response body.

Errors

400

Invalid request payload

Check the request fields and any validation details, then correct the payload.

500

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Endpoint Query

View source specification ↗
POST /endpoint-query

Return a bounded page of authorized endpoints matching the shared Query expression. An empty query and filters such as type or interfaces default to enabled endpoints owned by the caller. An explicit ownerId, groupId, or required exact id selector can include readable endpoints owned by others; endpoint-read permission is still required for each result. Collections exclude disabled endpoints unless enablement is filtered, while a query that requires specific exact endpoint IDs can return disabled endpoint metadata without an enablement filter. See the request schema for supported fields and operators. Use groupId to select members of a readable room/group, then intersect type or declared interfaces to select lights. Group predicates additionally require group:read for delegated OAuth. Repeat the complete query settings and grant when following nextToken; cursors expire after fifteen minutes. Device attributes are returned only when expanded. Report per-target command acceptance and observed state separately; querying a group does not grant permission to control its members.

Required scope

endpoint:read

When using groupId: group:read

Request body

Fields
queryQueryRequired

A bounded shared Query expression. By default, an empty object and filters such as type or interfaces select enabled endpoints owned by the caller. An explicit ownerId, groupId, or required exact id selector can include readable endpoints owned by others; endpoint-read permission is still required for every result. This endpoint supports match, and, or, and not. Scalar match keys are id, name, type, ownerId, manufacturer, model, serialNumber, and enablement. interfaces matches membership in the endpoint's declared interface names; groupId matches membership in a readable endpoint group. Comparisons, patterns, freeform search, unknown keys, ambiguous nodes, expressions deeper than eight levels, or more than 64 nodes return 400. Values are exact strings. Collections exclude disabled endpoints unless the expression filters enablement. A query that requires specific exact endpoint IDs can also return disabled endpoint metadata without an enablement filter, subject to endpoint-read permission. A groupId predicate additionally requires group:read for delegated OAuth and read permission on that group.

paginationContextPaging
expandarray<string>

Optional reported state expansion; only interfaces.attributes is supported.

uniqueItems: true

includeChildEndpointsboolean

A query returns root endpoints only: an endpoint that is part of another endpoint (for example an oven cavity of its range, which reports `parentEndpointId`) is left out, and the parent lists its parts in `childEndpointIds`. Send true to match those parts too. A query that selects endpoints by exact id or by groupId returns them either way. Repeat the same setting when following nextToken. A part whose parent the caller cannot read is still returned.

Default: false

forceDeviceQueryboolean

Refresh reported device attributes for the selected page. Requires expand to contain interfaces.attributes. An accepted command is not proof of device state; inspect each attribute's sampledAt and freshness and the partial errors. A provider can answer with its own last known sample, which is returned as STALE. Disabled endpoints cannot be forcibly refreshed.

Default: false

Returns

200

Endpoints retrieved successfully

Fields
resultsarray<Endpoint>Required
paginationContextPaginationContext
errorsarray<EndpointQueryResponseError>

Partial deep-query failures collected while building expanded endpoint state. This field is present only when endpoint enumeration succeeded but one or more live attribute refresh items failed; request-level failures still use HTTP error responses.

Errors

400 BAD_REQUEST

Invalid query, unsupported expansion, or invalid/expired/mismatched cursor.

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Unauthorized - invalid or missing authentication token

Obtain a valid access token, then retry.

403 FORBIDDEN

Missing conditional OAuth scope or permission to read a referenced group.

Check the linked account and its permissions for the device or resource.

404 NOT_FOUND

A referenced group does not exist.

Verify the target identifier and that its endpoint or plugin route still exists.

409 ENDPOINT_DISABLED

A selected disabled endpoint cannot be forcibly refreshed.

Check the device’s current mode or state. Retry only after the conflict is resolved.

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Messages

v1.0

Port OS allows you to send messages to things. By sending messages to endpoints, customers can turn off lights, play music, etc. A message is an object that is sent around in port OS between different endpoints.

Send Message

View source specification ↗
POST /messages

Sends a message to a recipient.

Plugin-originated dispatch errors use the canonical plugin dispatch error contract: type, family, code, message, and optional typed details. Fire-and-forget requests can only return plugin errors detected before the request is accepted. Synchronous requests can also map a correlated portos/errorResponse plugin response into the HTTP error statuses below.

Required scope

message:send

Request body

Fields
targetCreateMessageTargetRequired

The endpoint, system, plugin or group a message is addressed to.

message151 variantsRequired

A capability message to send to an endpoint: exactly one of the inbound capability messages. The header namespace, name and version select the variant and the body schema.

headerMessageHeaderRequired

Identifies this capability message.

bodyobjectRequired

Ask the device to report its current air quality reading.

correlationTokenstring

Token used for correlating related messages

responseTypestring

How to handle the request. AUTO resolves the actual selected route's current plugin declaration: synchronous operations wait for a correlated response; asynchronous and fire-and-forget operations return dispatch acceptance without claiming device execution. Legacy integrations retain synchronous behavior in AUTO mode. Omission retains the existing FIRE_FORGET default.

POST /messages: application/json request body: possible enum values for responseType
ValueMeaning
SYNC—
FIRE_FORGET—
AUTOSelect the operating mode automatically.

Returns

200

Request accepted; an asynchronous acknowledgment may have an empty messageId and no message. Verify device state separately.

Fields
messageIdstringRequired

Identifies the unary response message when one is returned. An accepted asynchronous request can return an empty string with no message. This field does not provide a durable dispatch receipt, retry deduplication or proof of observed device state.

message56 variants

The message that was responded with when there was a unary message response, exactly one of the outbound capability messages. A synchronous send can return one; an acknowledgment with no message back leaves this empty. The header namespace, name and version select the variant and the body schema.

headerMessageHeaderRequired

Identifies this capability message.

bodyAuthorizationInterfaceAuthorizationEstablishedMessageRequired

The authorization established message is sent to a plugin to indicate that the plugin has been installed and authorized for a principal

correlationTokenstring

Token used for correlating related messages

Errors

400 INVALID_VALUE

Invalid request payload or plugin dispatch request error

Check the request fields and any validation details, then correct the payload.

Example details
Example details
{
  "providerCode": "provider-invalid-speed",
  "parameter": "speed",
  "actual": "storm"
}
401 AUTHORIZATION_CREDENTIAL_EXPIRED

Plugin authorization credential is invalid or expired

Re-link the plugin to renew its provider credentials, then retry.

Example details
Example details
{
  "providerCode": "provider-token-expired"
}
403 INSUFFICIENT_PERMISSIONS

Plugin provider denied the requested operation

Check the linked account and its permissions for the device or resource.

Example details
Example details
{
  "providerCode": "provider-scope-missing"
}
404 NOT_FOUND

Target endpoint or plugin route was not found

Verify the target identifier and that its endpoint or plugin route still exists.

409 NOT_SUPPORTED_IN_CURRENT_MODE

Endpoint state conflicts with the requested message

Check the device’s current mode or state. Retry only after the conflict is resolved.

Example details
Example details
{
  "providerCode": "device-mode-conflict",
  "currentMode": "eco"
}
422 VALUE_OUT_OF_RANGE

Plugin rejected a semantically invalid message value

Correct the rejected value using the constraints in the error details or request schema.

Example details
Example details
{
  "providerCode": "brightness-out-of-range",
  "parameter": "brightness",
  "minimum": 1,
  "maximum": 100,
  "actual": "150"
}
423 ENDPOINT_UNREACHABLE

Endpoint is unavailable, unreachable, locked, or low power

Check device connectivity, power, and lock state before retrying.

Example details
Example details
{
  "providerCode": "device-offline",
  "pluginId": "port1.plugin.hue",
  "pluginRouteId": "hue-device-42"
}
429 RATE_LIMIT_EXCEEDED

Plugin provider rate limit exceeded

Wait for Retry-After or details.retryAfterSeconds when supplied; otherwise use backoff.

Example details
Example details
{
  "providerCode": "provider-rate-limit",
  "retryAfterSeconds": 60
}
500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

502 PROVIDER_INTERNAL_ERROR

Plugin provider returned an invalid or internal error response

Check provider availability. Retry with backoff only when the operation is safe to repeat.

Example details
Example details
{
  "providerCode": "provider-internal-error"
}
503 PROVIDER_SERVICE_UNAVAILABLE

Plugin provider or bridge is unavailable

Wait for the provider or bridge to recover, then retry safely with backoff.

Example details
Example details
{
  "providerCode": "vendor-outage"
}
504 PROVIDER_TIMEOUT

Plugin provider timed out

Check whether the command completed before resending it; a timeout can leave the result uncertain.

Example details
Example details
{
  "providerCode": "provider-timeout"
}
All documented plugin error types
Plugin error familyRepresentative typesHTTP status
REQUEST_INVALIDINVALID_DIRECTIVE, INVALID_VALUE400
REQUEST_INVALIDVALUE_OUT_OF_RANGE422
AUTHENTICATIONAUTHORIZATION_CREDENTIAL_INVALID, AUTHORIZATION_CREDENTIAL_EXPIRED401
PERMISSIONINSUFFICIENT_PERMISSIONS, CLOUD_CONTROL_DISABLED403
ENDPOINT_NOT_FOUNDno such endpoint or route404
ENDPOINT_STATE_CONFLICTENDPOINT_BUSY, NOT_SUPPORTED_IN_CURRENT_MODE409
ENDPOINT_UNAVAILABLEENDPOINT_UNREACHABLE, ENDPOINT_LOW_POWER423
RATE_LIMITRATE_LIMIT_EXCEEDED429
PROVIDER_BAD_RESPONSEPROVIDER_INTERNAL_ERROR502
PROVIDER_UNAVAILABLEBRIDGE_UNREACHABLE, PROVIDER_SERVICE_UNAVAILABLE503
PROVIDER_TIMEOUTPROVIDER_TIMEOUT504

Endpoint Groups

v1.0

List endpoint groups

View source specification ↗
GET /endpoint-groups

Lists all available endpoint groups for the authenticated user.

Required scope

group:read

Query parameters

enablementstring

Filter the results by enablement. Enablement is a customer setting that stops Port OS from using a resource without deleting it. Port OS uses it in place of deletion because it cannot delete a device on the provider's side. Defaults to ENABLED. Use DISABLED to list only disabled resources, or '*' to include both enabled and disabled resources. Looking up a resource by its exact id ignores this filter.

Default: ENABLED

Allowed values: ENABLED, DISABLED, *.

ownerstring

Filter the results by the owner of the resource. Defaults to the authenticated caller's resources when omitted. Use '~caller' to make that scope explicit. Another owner can be selected only for resources the caller can read.

nextTokenstring

Opaque token for the next page of results. Pass the continuation token returned by the previous response, unchanged. Omit it to start from the first page.

maxResultsinteger

Maximum number of results to return in one page. Defaults to 100. Values from 1 through 100 are accepted.

minimum: 1

maximum: 100

Default: 100

expandarray<string>

Expansion tokens that request related or computed fields for each result. Use `interfaces.attributes` to populate each group's `attributes` array with the stored values of its group routes.

forceDeviceAttributeQueryboolean

Asks each provider for fresh values of the group routes before the response is returned. Only applied when `expand` includes `interfaces.attributes`. Absent, invalid or `false` values return the stored values.

Returns

200

Endpoint groups retrieved successfully

Fields
resultsarray<EndpointGroup>Required
paginationContextPaginationContext
errorsarray<Error>

Partial query errors collected while returning available results.

Errors

400 BAD_REQUEST

Bad request - missing required parameters

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Unauthorized - invalid or missing authentication token

Obtain a valid access token, then retry.

403 FORBIDDEN

Forbidden - insufficient permissions

Check the linked account and its permissions for the device or resource.

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Create an endpoint group

View source specification ↗
POST /endpoint-groups

Creates a new endpoint group.

Required scope

group:manage

Request body

Fields
itemCreateEndpointGroupItemRequired

The client-supplied fields of a new endpoint group. Members are added afterwards with `add-members` or created together through `/endpoint-groups-manage` `CREATE_GROUP`. A user group name is `{"type": "PLAIN", "value": ...}` whose value is non-blank UTF-8 text of at most 256 bytes with no control characters; anything else is rejected with BAD_REQUEST.

Returns

200

Endpoint group created successfully

Fields
idstringRequired

The created endpoint group ID

Response headers
ETagstring

Opaque strong entity tag of the returned resource version. Send it back in `If-Match` on the next mutation of the same resource.

Errors

400 BAD_REQUEST

Bad request - invalid request payload

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Unauthorized - invalid or missing authentication token

Obtain a valid access token, then retry.

403 FORBIDDEN

Forbidden - insufficient permissions

Check the linked account and its permissions for the device or resource.

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Manage endpoint groups atomically

View source specification ↗
POST /endpoint-groups-manage

Applies a bounded list (max 20) of endpoint group management operations atomically in one transaction. The operations are CREATE_GROUP, DELETE_GROUP, SET_NAME, ADD_MEMBERS, REMOVE_MEMBERS and MERGE_INTO. Every operation that modifies an existing group carries the group's etag, which is compared inside the transaction. Item outcomes are returned with HTTP 200 in a status/results/errors envelope correlated by requestId; non-200 statuses are reserved for request-level failures. Idempotency-Key is required unless validateOnly is true; a committed response is replayed for 24 hours for the same principal, key and payload. Physical control is never part of this request; use POST /messages.

Required scope

group:manage

Header parameters

Idempotency-KeystringRequired

Client-chosen key that makes a non-idempotent request retry-safe, following draft-ietf-httpapi-idempotency-key-header. A committed response is stored for 24 hours and replayed for the same principal, operation, key and payload. Missing key returns 400 IDEMPOTENCY_KEY_REQUIRED, a key longer than 255 characters returns 400 IDEMPOTENCY_KEY_INVALID, the same key with a different payload returns 422, and the same key while the first request is still in flight returns 409. Failed (rolled-back) requests do not consume the key.

minLength: 1

maxLength: 255

Request body

Fields
validateOnlyboolean

When true, runs authorization and validation and returns what would happen, writing nothing. A validate-only request neither requires nor consumes an `Idempotency-Key`.

Default: false

operationsarray<EndpointGroupsManageOperation>Required

Returns

200

Batch evaluated. status is COMMITTED when every operation was applied (or would be, for validateOnly), otherwise FAILED with every failing operation in errors and nothing written.

Fields
statusstringRequired

Outcome of an atomic batch. `COMMITTED` means every operation was applied (or, for a validate-only request, would be applied); `FAILED` means nothing was written and `errors` lists every failing operation.

Allowed values: COMMITTED, FAILED.

resultsarray<EndpointGroupsManageResult>Required
errorsarray<BatchItemError>Required

Errors

400 IDEMPOTENCY_KEY_REQUIRED

Malformed request, unknown operation, duplicate `requestId`, or missing (`IDEMPOTENCY_KEY_REQUIRED`) or over-long (`IDEMPOTENCY_KEY_INVALID`) `Idempotency-Key`

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Unauthorized - invalid or missing authentication token

Obtain a valid access token, then retry.

403 FORBIDDEN

Forbidden - token lacks the group:manage scope

Check the linked account and its permissions for the device or resource.

409 IDEMPOTENCY_KEY_IN_FLIGHT

A request with the same `Idempotency-Key` is still in flight

Check the device’s current mode or state. Retry only after the conflict is resolved.

422 IDEMPOTENCY_KEY_REUSED

The `Idempotency-Key` was already used with a different payload

Correct the rejected value using the constraints in the error details or request schema.

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Set endpoint group name

View source specification ↗
POST /{namespace}/{principalType}/{principalId}/endpoint-groups/{groupId}/set-name

Sets the name of an endpoint group.

Required scope

group:manage

Path parameters

namespacestringRequired

The namespace of the principal

principalTypestringRequired

The type of principal

principalIdstringRequired

The ID of the principal

groupIdstringRequired

The ID of the endpoint group

Header parameters

If-MatchstringRequired

The quoted strong entity tag of the resource the client last read (its `etag` field or `ETag` response header). The mutation is applied only when it still matches: a stale value returns 412 PRECONDITION_FAILED and a missing header returns 428 PRECONDITION_REQUIRED. `*` matches any current version of an existing group (RFC 9110), for a deliberate last-writer-wins change.

minLength: 1

Request body

Fields
nameTypeValueRequired

The new name for the endpoint group as a human readable string or a localizable asset

Returns

202

Endpoint group name update accepted

No response body.

Response headers
ETagstring

Opaque strong entity tag of the returned resource version. Send it back in `If-Match` on the next mutation of the same resource.

Errors

400 BAD_REQUEST

Invalid request payload

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Unauthorized - invalid or missing authentication token

Obtain a valid access token, then retry.

403 FORBIDDEN

Forbidden - insufficient permissions

Check the linked account and its permissions for the device or resource.

404 NOT_FOUND

Endpoint group not found

Verify the target identifier and that its endpoint or plugin route still exists.

412 PRECONDITION_FAILED

The If-Match etag does not match the current group version; re-read the group and retry

Inspect the returned code and family and follow the error handling guide.

428 PRECONDITION_REQUIRED

The If-Match header is missing

Inspect the returned code and family and follow the error handling guide.

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Get an endpoint group

View source specification ↗
GET /{namespace}/{principalType}/{principalId}/endpoint-groups/{groupId}

Get an endpoint group by ID.

Required scope

group:read

Path parameters

namespacestringRequired

The namespace of the principal

principalTypestringRequired

The type of principal

principalIdstringRequired

The ID of the principal

groupIdstringRequired

The ID of the endpoint group to retrieve

Query parameters

expandarray<string>

Expansion tokens that request related or computed fields for the returned resource. Use `interfaces.attributes` to populate the group's `attributes` array with the stored values of its group routes.

forceDeviceAttributeQueryboolean

Asks each provider for fresh values of the group routes before the response is returned. Only applied when `expand` includes `interfaces.attributes`. Absent, invalid or `false` values return the stored values. A forced read includes only attributes refreshed by that request. If a provider cannot be reached or rejects the request, the request returns `500 DEEP_QUERY_FAILED` instead of presenting stored values as fresh. If a provider answers but gives no value for a declared attribute, that attribute is returned without a `value` and with an `error` whose code is `PROVIDER_NO_STATE`; the request still succeeds.

Returns

200

Endpoint group retrieved successfully

Fields
idstringRequired

The unique identifier for the endpoint group

pattern: "^port1/[^/]+/[^/]+/endpoint-groups/[^/]+$"

nameTypeValueRequired

The name of the endpoint group

ownerIdstringRequired

The ID of the owner of the endpoint group

enablementstringRequired

Whether Port OS uses an endpoint or group. A disabled one is hidden from collections by default and cannot be sent device messages or targeted by them; exact authorized reads still return it. Rediscovery never changes it, so disabling is how a user hides a discovered device or room for good.

Default: ENABLED

Allowed values: ENABLED, DISABLED.

memberEndpointIdsarray<string>

List of member endpoint IDs of the endpoint group

interfacesarray<ApplicationInterface>Required

List of interfaces supported by the endpoint group

etagstringRequired

Opaque strong entity tag of this group version, for example `"12"`. It changes on any committed write to the group, its group routes or its relationships. Send it as `If-Match` (or as the operation `etag` in `/endpoint-groups-manage`) when mutating the group.

redirectedFromstring

Set when the group was read through a merged-away ID: the ID that was requested, which now redirects to this group. Mutations must use this group's `id`.

parentGroupIdstring

The canonical parent group derived from `IS_PART_OF` relationships, when the group has one.

childGroupIdsarray<string>

Canonical child groups derived from `IS_PART_OF` relationships.

controllersarray<EndpointGroupController>

Endpoints that declare `CAN_CONTROL` on one of this group's group routes, with the messages they support on it.

attributesarray<GroupRouteAttributeState>

The group's state: every attribute value stored for its group routes, one entry per group route and attribute, tagged with the group route and provider. Populated only when the read is called with `expand=interfaces.attributes`.

Response headers
ETagstring

Opaque strong entity tag of the returned resource version. Send it back in `If-Match` on the next mutation of the same resource.

Errors

400 BAD_REQUEST

Invalid request payload

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Unauthorized - invalid or missing authentication token

Obtain a valid access token, then retry.

403 FORBIDDEN

Forbidden - insufficient permissions

Check the linked account and its permissions for the device or resource.

404 NOT_FOUND

Endpoint group not found

Verify the target identifier and that its endpoint or plugin route still exists.

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Delete an endpoint group

View source specification ↗
DELETE /{namespace}/{principalType}/{principalId}/endpoint-groups/{groupId}

Delete an endpoint group by ID.

Required scope

group:manage

Path parameters

namespacestringRequired

The namespace of the principal

principalTypestringRequired

The type of principal

principalIdstringRequired

The ID of the principal

groupIdstringRequired

The ID of the endpoint group to delete

Header parameters

If-MatchstringRequired

The quoted strong entity tag of the resource the client last read (its `etag` field or `ETag` response header). The mutation is applied only when it still matches: a stale value returns 412 PRECONDITION_FAILED and a missing header returns 428 PRECONDITION_REQUIRED. `*` matches any current version of an existing group (RFC 9110), for a deliberate last-writer-wins change.

minLength: 1

Returns

202

Endpoint group deletion accepted

No response body.

Errors

400 BAD_REQUEST

Invalid request payload

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Unauthorized - invalid or missing authentication token

Obtain a valid access token, then retry.

403 FORBIDDEN

Forbidden - insufficient permissions

Check the linked account and its permissions for the device or resource.

404 NOT_FOUND

Endpoint group not found

Verify the target identifier and that its endpoint or plugin route still exists.

412 PRECONDITION_FAILED

The If-Match etag does not match the current group version; re-read the group and retry

Inspect the returned code and family and follow the error handling guide.

428 PRECONDITION_REQUIRED

The If-Match header is missing

Inspect the returned code and family and follow the error handling guide.

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Add members to an endpoint group

View source specification ↗
POST /{namespace}/{principalType}/{principalId}/endpoint-groups/{groupId}/add-members

Adds one or more endpoint members to an existing endpoint group.

Required scope

group:manage

Path parameters

namespacestringRequired

The namespace of the principal

principalTypestringRequired

The type of principal

principalIdstringRequired

The ID of the principal

groupIdstringRequired

The ID of the endpoint group

Header parameters

If-MatchstringRequired

The quoted strong entity tag of the resource the client last read (its `etag` field or `ETag` response header). The mutation is applied only when it still matches: a stale value returns 412 PRECONDITION_FAILED and a missing header returns 428 PRECONDITION_REQUIRED. `*` matches any current version of an existing group (RFC 9110), for a deliberate last-writer-wins change.

minLength: 1

Request body

Fields
memberEndpointIdsarray<string>Required

List of member IDs to add to the group

Returns

202

Members addition accepted

No response body.

Response headers
ETagstring

Opaque strong entity tag of the returned resource version. Send it back in `If-Match` on the next mutation of the same resource.

Errors

400 BAD_REQUEST

Invalid request payload

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Unauthorized - invalid or missing authentication token

Obtain a valid access token, then retry.

403 FORBIDDEN

Forbidden - insufficient permissions

Check the linked account and its permissions for the device or resource.

404 NOT_FOUND

Endpoint group not found

Verify the target identifier and that its endpoint or plugin route still exists.

412 PRECONDITION_FAILED

The If-Match etag does not match the current group version; re-read the group and retry

Inspect the returned code and family and follow the error handling guide.

428 PRECONDITION_REQUIRED

The If-Match header is missing

Inspect the returned code and family and follow the error handling guide.

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Remove members from an endpoint group

View source specification ↗
POST /{namespace}/{principalType}/{principalId}/endpoint-groups/{groupId}/remove-members

Removes one or more endpoint members from an existing endpoint group.

Required scope

group:manage

Path parameters

namespacestringRequired

The namespace of the principal

principalTypestringRequired

The type of principal

principalIdstringRequired

The ID of the principal

groupIdstringRequired

The ID of the endpoint group

Header parameters

If-MatchstringRequired

The quoted strong entity tag of the resource the client last read (its `etag` field or `ETag` response header). The mutation is applied only when it still matches: a stale value returns 412 PRECONDITION_FAILED and a missing header returns 428 PRECONDITION_REQUIRED. `*` matches any current version of an existing group (RFC 9110), for a deliberate last-writer-wins change.

minLength: 1

Request body

Fields
memberEndpointIdsarray<string>Required

List of member IDs to remove from the group

Returns

202

Members removal accepted

No response body.

Response headers
ETagstring

Opaque strong entity tag of the returned resource version. Send it back in `If-Match` on the next mutation of the same resource.

Errors

400 BAD_REQUEST

Invalid request payload

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Unauthorized - invalid or missing authentication token

Obtain a valid access token, then retry.

403 FORBIDDEN

Forbidden - insufficient permissions

Check the linked account and its permissions for the device or resource.

404 NOT_FOUND

Endpoint group not found

Verify the target identifier and that its endpoint or plugin route still exists.

412 PRECONDITION_FAILED

The If-Match etag does not match the current group version; re-read the group and retry

Inspect the returned code and family and follow the error handling guide.

428 PRECONDITION_REQUIRED

The If-Match header is missing

Inspect the returned code and family and follow the error handling guide.

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Relationships

v1.0

Typed relationships between port resources.

List relationships

View source specification ↗
GET /relationships

Read-only enumeration of typed relationships between endpoints, routes, groups and group routes. Both vertices must be readable by the caller. Defaults to caller-owned relationships with a bounded page. Provider discovery and group membership operations manage the edges.

Required scope

group:read

Query parameters

ownerstring

Filter the results by the owner of the resource. Defaults to the authenticated caller's resources when omitted. Use '~caller' to make that scope explicit. Another owner can be selected only for resources the caller can read.

groupIdstring

Relationships touching this group or a group route belonging to it.

routeIdstring

Only relationships with this route or group route ID as a vertex

endpointIdstring

Relationships touching this endpoint or a route belonging to it.

vertexIdstring

Relationships touching this exact resource ID.

parentIdstring

Relationships with a route or group-route vertex belonging to this resource ID.

typestring

Only relationships of this type.

Allowed values: IS_PART_OF, CAN_CONTROL, LOCATED_IN, MEMBER_OF.

nextTokenstring

Opaque token for the next page of results. Pass the continuation token returned by the previous response, unchanged. Omit it to start from the first page.

maxResultsinteger

Maximum number of results to return in one page. Defaults to 100. Values from 1 through 100 are accepted.

minimum: 1

maximum: 100

Default: 100

expandarray<string>

Expansion tokens that request related or computed fields for each result. When omitted, the response contains only the default, shallower set of fields for each result.

Returns

200

Relationships retrieved successfully

Fields
resultsarray<Relationship>Required
paginationContextPaginationContext
errorsarray<Error>

Partial query errors collected while returning available results.

Errors

400 BAD_REQUEST

Bad request - missing or invalid parameters

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Unauthorized - invalid or missing authentication token

Obtain a valid access token, then retry.

403 FORBIDDEN

Forbidden - insufficient permissions

Check the linked account and its permissions for the device or resource.

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Device plugins

Device plugin APIs connect providers and route their devices into Port OS.

Routes

v1.0

A route is a part of an endpoint that denotes what types of interfaces the endpoint can support from a specific plugin. Additionally, a route may describe the endpoint with metadata such as names, manufacturer name, model data, etc.

Get Routes

View source specification ↗
GET /routes

Lists routes owned by the authenticated caller by default. Supplying an owner selects that owner's routes, subject to the caller's route-read permissions. The default page size is 10 and the maximum is 100. The returned route id is the persisted Port OS route identifier. For routes created through synchronization, use associatedPluginRouteId to match the stable plugin-owned or fixture route identity from the discovery payload.

Required scope

endpoint:read

Query parameters

ownerstring

Owner whose routes to list. Defaults to the authenticated caller when omitted. A different owner is permitted only for routes the caller can read.

expandarray<string>

Expansion tokens that request related or computed fields for each result. When omitted, the response contains only the default, shallower set of fields for each result.

nextTokenstring

Opaque token for the next page of results. Pass the continuation token returned by the previous response, unchanged. Omit it to start from the first page.

maxResultsinteger

Maximum number of results to return in one page. Defaults to 100. Values from 1 through 100 are accepted.

minimum: 1

maximum: 100

Default: 100

Returns

200

OK

Fields
resultsarray<Route>Required
paginationContextPaginationContext
errorsarray<Error>

Partial query errors collected while returning available results.

Errors

400 BAD_REQUEST

Invalid query parameter, including an invalid maxResults value or pagination token.

Check the request fields and any validation details, then correct the payload.

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Delete Route

View source specification ↗
DELETE /routes

Deletes a route.

Required scope

endpoint:write

Request body

Fields
idstringRequired

The route ID to delete

Returns

200

Route deleted successfully

No response body.

Errors

400

Invalid request payload

Check the request fields and any validation details, then correct the payload.

500

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Upsert Route

View source specification ↗
POST /routes

Creates or updates a route.

Required scope

endpoint:write

Request body

Fields
idstringRequired

The route ID

endpointIdstringRequired

The endpoint ID

pluginIdstringRequired

The plugin ID

interfacesarray<ApplicationInterface>

List of interfaces to support

metadataRouteMetadata

Additional metadata about the route

Returns

200

Route upserted successfully

No response body.

Errors

400

Invalid request payload

Check the request fields and any validation details, then correct the payload.

500

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Synchronize Plugin Routes via Discovery

View source specification ↗
POST /discovery

Triggers route synchronization for a plugin. When a plugin connected to Port OS wants to report the routes available on it, it dispatches a discovery payload. The server reconciles the reported routes with its internal state. For newly persisted synchronized routes, the server can assign a backend-generated, owner-scoped Port OS route id; a client-supplied route id in the discovery payload is advisory and is not the stable lookup surface for plugin capability parity. Consumers that need to match synchronized plugin or fixture routes after enumeration should use associatedPluginRouteId, which preserves the plugin-owned route identity. Every route and group-route interface must name a capability interface and exact version from the capability-interface library, its configuration must conform to that interface's configuration schema (an omitted configuration is validated as an empty object), and any declared attribute must exist on the interface with a value that conforms to its attribute schema. Any nonconforming item rejects the whole request with 400; errors lists every rejected item keyed by pluginRouteId. Nothing is persisted. Group routes and relationships are keyed by plugin-owned identity within the plugin and auth link and are created or updated, never removed because they are omitted. A pluginRouteId must be unique across routes and group routes (PLUGIN_ROUTE_ID_CONFLICT). Group-route members and relationship vertices must resolve to routes or group routes of the same plugin and auth link, committed or in the same request (UNRESOLVED_REFERENCE). IS_PART_OF joins two group routes and is acyclic (RELATIONSHIP_CYCLE) with at most one parent per group route (MULTIPLE_PARENTS); CAN_CONTROL and LOCATED_IN join a route to a group route; self-edges and other shapes are INVALID_RELATIONSHIP. Only CAN_CONTROL carries interfaces, which must name interfaces and inbound messages the source route declares (MESSAGE_UNSUPPORTED). Relationship items are keyed by relationshipExternalId. A newly reported group route creates its own endpoint group named after it; rediscovery keeps group IDs, merges and user renames. Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Request body

Fields
pluginIdentityClientIdentity

Identifies a plugin client by its type and unique identifier.

authLinkIdentitystring

The ID of the auth link

routesarray<ProviderDiscoveredRoute>Required

List of routes to synchronize. Route `id` values supplied here are not the stable plugin capability lookup surface after synchronization; match enumerated routes by `associatedPluginRouteId`.

groupRoutesarray<GroupRoute>

Group routes (maps, rooms, provider groups) to create or update, keyed by `pluginRouteId` within the plugin and auth link.

relationshipsarray<PluginDiscoveryRelationship>

Typed relationships between the reported routes and group routes.

Returns

200

Routes synchronized successfully

No response body.

Errors

400 BAD_REQUEST

Bad request — invalid payload, or one or more routes or group routes do not conform to the capability-interface library

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Unauthorized — missing or invalid bearer token

Obtain a valid access token, then retry.

403 FORBIDDEN

Forbidden — insufficient permissions

Check the linked account and its permissions for the device or resource.

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Endpoint Group Routes

v1.0

An endpoint group route is a way for a gropu of devices to be controlled at the same time.

List group routes

View source specification ↗
GET /group-routes

API to enumerate the group routes that a principal has permissions to.

Required scope

group:read

Query parameters

ownerstring

Filter the results by the owner of the resource. Defaults to the authenticated caller's resources when omitted. Use '~caller' to make that scope explicit. Another owner can be selected only for resources the caller can read.

nextTokenstring

Opaque token for the next page of results. Pass the continuation token returned by the previous response, unchanged. Omit it to start from the first page.

maxResultsinteger

Maximum number of results to return in one page. Defaults to 100. Values from 1 through 100 are accepted.

minimum: 1

maximum: 100

Default: 100

expandarray<string>

Expansion tokens that request related or computed fields for each result. When omitted, the response contains only the default, shallower set of fields for each result.

Returns

200

Group routes retrieved successfully

Fields
resultsarray<EndpointGroupRoute>Required
paginationContextPaginationContext
errorsarray<Error>

Partial query errors collected while returning available results.

Errors

400 BAD_REQUEST

Bad request - missing required parameters

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Unauthorized - invalid or missing authentication token

Obtain a valid access token, then retry.

403 FORBIDDEN

Forbidden - insufficient permissions

Check the linked account and its permissions for the device or resource.

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Delete a group route

View source specification ↗
DELETE /{namespace}/{principalType}/{principalId}/group-routes/{groupId}

Deletes a group route by ID.

Required scope

group:manage

Path parameters

namespacestringRequired

The namespace of the principal

principalTypestringRequired

The type of principal

principalIdstringRequired

The ID of the principal

groupIdstringRequired

The ID of the group route to delete

Returns

200

Group route deleted successfully

No response body.

Errors

400 BAD_REQUEST

Invalid request payload

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Unauthorized - invalid or missing authentication token

Obtain a valid access token, then retry.

403 FORBIDDEN

Forbidden - insufficient permissions

Check the linked account and its permissions for the device or resource.

404 NOT_FOUND

Group route not found

Verify the target identifier and that its endpoint or plugin route still exists.

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Plugins

v1.0

A plugin is a receiver of messages. A plugin could be an HTTP connection, android device messenger, an MQTT connection, or anything else. Messages sent to endpoints are propagated through plugins.

Enumerate Plugins

View source specification ↗
GET /plugins

Lists all available plugins

Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Query parameters

expandarray<string>

Space-delimited list of fields to expand (metadata)

idstring

Full path ID of a specific plugin to retrieve (e.g. port1/systems/zero/plugins/{uuid})

nextTokenstring

Opaque token for the next page of results. Pass the continuation token returned by the previous response, unchanged. Omit it to start from the first page.

maxResultsinteger

Maximum number of results to return.

minimum: 1

maximum: 100

Returns

200

Plugins retrieved successfully

Fields
resultsarray<Plugin>Required
paginationContextPaginationContext
errorsarray<Error>

Partial query errors collected while returning available results.

Errors

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Upsert Plugin Request

View source specification ↗
POST /plugins

Creates a new plugin

Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Request body

Fields
pluginWebsocketPlugin | HttpPlugin | WebservicePlugin | ApplePushNotificationPlugin | HostedComputePlugin

discriminator: type

applePushNotificationSecretApplePushNotificationSecret

APNS authentication token secret (required when creating an APPLE_PUSH_NOTIFICATION plugin with new credentials)

secretReferenceIdstring

Reference to an existing secret in the secret store (use instead of inline credentials when the secret already exists)

Returns

200

Plugin created successfully

Fields
idstringRequired

The created plugin ID

pattern: "^port1/[^/]+/[^/]+/plugins/[^/]+$"

Errors

400

Invalid request payload

Check the request fields and any validation details, then correct the payload.

500

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Delete Plugin

View source specification ↗
DELETE /plugins

Deletes a plugin

Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Request body

Fields
idstringRequired

The plugin ID to delete

Returns

200

Plugin deleted successfully

No response body.

Errors

400

Invalid request payload

Check the request fields and any validation details, then correct the payload.

500

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Testing

Testing APIs create simulated devices for development.

Endpoint Simulators

v1.0

Endpoint Simulators lets customers simulate endpoints to test out their flows and integrations.

Create or update a simulator

View source specification ↗
POST /endpoint-simulators

Creates a new endpoint simulator or updates an existing one. When an id is provided in the request body, the simulator with that ID is updated. When no id is provided, a new simulator is created along with its associated endpoint, auth link, and route. Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Request body

Fields
(payload)any

Creates or updates an endpoint simulator.

Returns

200

Simulator upserted successfully

Fields
(payload)any

An endpoint simulator.

Errors

400 BAD_REQUEST

Invalid request payload

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Unauthorized - invalid or missing authentication token

Obtain a valid access token, then retry.

403 FORBIDDEN

Forbidden - insufficient permissions

Check the linked account and its permissions for the device or resource.

415 BAD_REQUEST

Unsupported request media type.

Inspect the returned code and family and follow the error handling guide.

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Delete a simulator

View source specification ↗
DELETE /endpoint-simulators

Deletes an endpoint simulator and its associated endpoint, auth link, and route.

Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Request body

Fields
idstringRequired

The simulator identifier.

pattern: "^(port1/principals/[^/]+/endpoint-simulators/[^/]+|port1\\.simulator\\..+)$"

Returns

200

Simulator deleted successfully

No response body.

Errors

400 BAD_REQUEST

Invalid request payload

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Unauthorized - invalid or missing authentication token

Obtain a valid access token, then retry.

403 FORBIDDEN

Forbidden - insufficient permissions

Check the linked account and its permissions for the device or resource.

404 NOT_FOUND

Simulator not found

Verify the target identifier and that its endpoint or plugin route still exists.

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

List all simulators

View source specification ↗
GET /endpoint-simulators

Lists endpoint simulators for the authenticated user. Supports pagination via maxResults and nextToken query parameters. When owner is not specified, defaults to the authenticated caller. Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Query parameters

ownerstring

Filter the results by the owner of the resource. Defaults to the authenticated caller's resources when omitted. Use '~caller' to make that scope explicit. Another owner can be selected only for resources the caller can read.

maxResultsinteger

The maximum number of results to return

minimum: 1

maximum: 100

nextTokenstring

Opaque token for the next page of results. Pass the continuation token returned by the previous response, unchanged. Omit it to start from the first page.

expandarray<string>

Expansion tokens that request related or computed fields for each result. When omitted, the response contains only the default, shallower set of fields for each result.

Returns

200

Simulators retrieved successfully

Fields
resultsarray<Simulator>Required

List of simulators

paginationContextPaginationContext
errorsarray<Error>

Partial query errors collected while returning available results.

Errors

400 BAD_REQUEST

Invalid request parameters

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Unauthorized - invalid or missing authentication token

Obtain a valid access token, then retry.

403 FORBIDDEN

Forbidden - insufficient permissions

Check the linked account and its permissions for the device or resource.

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Tokens and OAuth

Token and OAuth APIs get and use access tokens.

Tokens

v1.0

Use tokens when you already have credentials and need an access token, or when you want to manage the long-lived tokens you hand to a CLI, device automation or agent.

OAuth2 Token Endpoint

View source specification ↗
POST /auth/token

This API is used to generate OAuth2 tokens.

The current OAuth token endpoint supports:

  1. Refresh token grants.
  2. Authorization code token grants.

Public DCR/CIMD clients exchange authorization_code with client_id, redirect_uri, code_verifier and the same resource as the consent request. No client_secret is issued. Refresh these grants with grant_type refresh_token, client_id, rotating refresh_token and the original resource. Store the replacement securely.

Required scope

Not required

Request body

Fields
grant_typestringRequired

The OAuth grant type. Use authorization_code for code exchange, or refresh_token to exchange a refresh token for an access token.

client_idstringRequired

The client ID.

client_secretstring

Required for confidential clients. Public DCR/CIMD clients omit this field and use PKCE.

subject_tokenstring

Identity token to exchange; required for urn:ietf:params:oauth:grant-type:token-exchange.

subject_token_typestring

Subject token type; use urn:ietf:params:oauth:token-type:id_token for identity token exchange.

requested_token_typestring

Requested token type for identity token exchange.

audiencestring

Target audience for identity token exchange.

device_codestring

Device code; required for urn:ietf:params:oauth:grant-type:device_code.

codestring

Authorization code; required when grant_type is authorization_code.

refresh_tokenstring

The refresh token; required when grant_type is refresh_token.

redirect_uristring

Redirect URI; required when grant_type is authorization_code.

code_verifierstring

Original PKCE verifier; required for public-client code exchange.

resourcestring

Exact resource from authorization; canonical issuer for REST or issuer/mcp for MCP. Required for DCR and CIMD.

format: "uri"

scopestring

Optional narrower subset during refresh; cannot add scopes.

client_assertionstring

Signed JWT proving client identity (RFC 7523); required with client_assertion_type for private_key_jwt clients using the client_credentials grant.

maxLength: 8192

client_assertion_typestring

Must be urn:ietf:params:oauth:client-assertion-type:jwt-bearer when client_assertion is set.

Allowed values: urn:ietf:params:oauth:client-assertion-type:jwt-bearer.

Returns

200

Token generated successfully

Fields
access_tokenstringRequired

The access token

token_typestringRequired

The token type

expires_inintegerRequired

The token expiration time in seconds

refresh_tokenstring

Rotating refresh credential for resource-bound grants; store privately.

scopestring

Granted space-separated scopes.

Errors

400

Invalid request payload

Check the request fields and any validation details, then correct the payload.

500

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Revoke a delegated REST or MCP grant

View source specification ↗
POST /auth/revoke

Possession of the matching refresh token proves revocation authority. The endpoint invalidates the grant family; it does not delete the client or other users' grants.

Required scope

Not required

Request body

Fields
tokenstringRequired
client_idstringRequired

Returns

200

Grant revoked or token was already invalid.

No response body.

Errors

400

Invalid request or client mismatch.

Check the request fields and any validation details, then correct the payload.

503

Revocation storage unavailable; do not claim success.

Wait for the provider or bridge to recover, then retry safely with backoff.

Enumerate Tokens

View source specification ↗
GET /tokens

Lists tokens owned by the authenticated principal. A principal may only list tokens they own.

Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Query parameters

nextTokenstring

Opaque token for the next page of results. Pass the continuation token returned by the previous response, unchanged. Omit it to start from the first page.

maxResultsinteger

Maximum number of results to return

minimum: 1

maximum: 100

expandarray<string>

Expansion tokens that request related or computed fields for each result. When omitted, the response contains only the default, shallower set of fields for each result.

Returns

200

Tokens retrieved successfully

Fields
resultsarray<TokenListItem>Required
paginationContextPaginationContext
errorsarray<Error>

Partial query errors collected while returning available results.

Errors

400 BAD_REQUEST

Bad request

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Unauthorized

Obtain a valid access token, then retry.

403 INSUFFICIENT_PERMISSIONS

Forbidden - not allowed to list tokens

Check the linked account and its permissions for the device or resource.

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Create Token

View source specification ↗
POST /tokens

Creates an expiring, revocable bearer access key for the caller. The raw JWT is returned only once. Use purpose WEBSITE_LOGIN for full-account website sign-in and explicit OAuth consent, or API for automation (the default). Subject must be ~self or the authenticated principal's own identifier. Website keys cannot have restricted scopes, expire within seven days and require an existing Google account session to create. Vended and delegated credentials cannot create independent replacement keys. Website keys cannot be refreshed or exchanged for identity sessions. OAuth connections approved with a website key are independently revocable.

Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Request body

Fields
purposestring

API keys authenticate automation. WEBSITE_LOGIN keys grant full account website sign-in and explicit OAuth consent, cannot have restricted scopes, and must be created through an existing account sign-in. Keys expire and can be revoked; OAuth connections approved with a website key are revoked separately.

Default: API

Allowed values: API, WEBSITE_LOGIN.

subjectstring

Identity for the token. Use ~self for the current user (resolved to the authenticated principal at create time), or that same principal's full path. Other principals are rejected.

expires_ininteger

Lifetime in seconds, default 3600. Website sign-in keys require a positive lifetime of at most 604800 (seven days).

scopestring

Space-separated scopes. Optional; default no scopes. See scopes documentation for allowed values and semantics.

labelstring

Optional human-readable label for the token (e.g. "CLI token").

Returns

200

Token created successfully. The raw JWT is returned only once.

Fields
idstringRequired

Token identifier (same as JWT jti). Use for list/delete and in the DELETE URL.

tokenstringRequired

The raw JWT. Returned only once at creation; cannot be retrieved again.

expires_atstringRequired

When the token expires (ISO 8601).

format: "date-time"

Errors

400

Invalid request (e.g. invalid subject, malformed body)

Check the request fields and any validation details, then correct the payload.

401

Unauthorized

Obtain a valid access token, then retry.

403

Forbidden - not allowed to create a token for the given subject

Check the linked account and its permissions for the device or resource.

500

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Invalidate Token

View source specification ↗
DELETE /{namespace}/{principalType}/{principalId}/tokens/{tokenId}

Revokes the access key's active record so subsequent website and API requests using that bearer are rejected. The token ID is the ID returned by create/list and carried in its JWT jti claim. Only the owner may revoke it. OAuth connections explicitly approved with a website key are independent grants and must be revoked separately.

Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Path parameters

tokenIdstringRequired

The token identifier (partial ID)

namespacestringRequired

The namespace of the principal

principalTypestringRequired

The type of principal

principalIdstringRequired

The ID of the principal

Returns

200

Token invalidated successfully

Fields
messagestringRequired

Confirmation message (e.g. "Token invalidated successfully").

Errors

401

Unauthorized

Obtain a valid access token, then retry.

403

Forbidden - not owner of the token

Check the linked account and its permissions for the device or resource.

404

Token id not found

Verify the target identifier and that its endpoint or plugin route still exists.

500

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

OAuth flows

v1.0

Discover OAuth and DCR endpoints

View source specification ↗
GET /.well-known/oauth-authorization-server

Discover the canonical issuer and endpoints for the deployed environment. Public REST grants use issuer as resource; MCP grants use issuer/mcp. CIMD client IDs must be public HTTPS metadata URLs. Registration is anonymous; device access requires user consent.

Required scope

Not required

Returns

200

Authorization server metadata.

Fields
issuerstringRequired

format: "uri"

authorization_endpointstringRequired

format: "uri"

token_endpointstringRequired

format: "uri"

registration_endpointstring

Advertised when new anonymous registration is enabled; omitted when disabled.

format: "uri"

revocation_endpointstringRequired

format: "uri"

jwks_uristring

format: "uri"

scopes_supportedarray<string>Required
code_challenge_methods_supportedarray<string>
token_endpoint_auth_methods_supportedarray<string>
client_id_metadata_document_supportedboolean
authorization_response_iss_parameter_supportedboolean

JSON Web Key Set

View source specification ↗
GET /.well-known/jwks.json

Returns the JSON Web Key Set (JWKS) containing the public keys used to verify JWT signatures. This endpoint is publicly accessible and does not require authentication. Responses are cached for one hour.

Required scope

Not required

Returns

200

JWKS retrieved successfully

Fields
keysarray<JsonWebKey>

OAuth protected resource metadata

View source specification ↗
GET /.well-known/oauth-protected-resource

Returns OAuth 2.0 Protected Resource Metadata as defined by RFC 9728. This endpoint is publicly accessible and does not require authentication. Responses are cached for one hour.

Required scope

Not required

Returns

200

Protected resource metadata retrieved successfully

Fields
resourcestring

The protected resource identifier

authorization_serversarray<string>

Authorization servers that can issue tokens for this resource

scopes_supportedarray<string>

Scopes supported by this resource

bearer_methods_supportedarray<string>

Methods supported for presenting bearer tokens

MCP OAuth protected resource metadata

View source specification ↗
GET /.well-known/oauth-protected-resource/mcp

Returns OAuth 2.0 Protected Resource Metadata for the MCP endpoint as defined by RFC 9728. This endpoint is publicly accessible and does not require authentication. Responses are cached for one hour.

Required scope

Not required

Returns

200

MCP protected resource metadata retrieved successfully

Fields
resourcestring

The protected resource identifier

authorization_serversarray<string>

Authorization servers that can issue tokens for this resource

scopes_supportedarray<string>

Scopes supported by this resource

bearer_methods_supportedarray<string>

Methods supported for presenting bearer tokens

OAuth2 Device Authorization

View source specification ↗
POST /auth/device-authorization

This API is used by your device to obtain authorization from the resource owner via a device code or QR code that your device can scan.

See the OAuth device authorization docs for more.

Uses the existing managed-client device flow. This endpoint is public, but validates its client and supported device grant; anonymous DCR clients support authorization_code and optional refresh_token, and cannot start the device flow.

Required scope

Not required

Request body

Fields
client_idstringRequired

The OAuth client identifier

scopestring

Space-separated list of scopes requested by the client

Returns

200

Device authorization initiated successfully

Fields
device_codestringRequired

The device verification code used to poll the token endpoint

user_codestringRequired

The user verification code displayed to the user

verification_uristringRequired

The URI where the user should enter the user code

verification_uri_completestring

The complete URI including the user code (optional, for convenience)

expires_inintegerRequired

The lifetime in seconds of the device_code and user_code

intervalintegerRequired

The minimum amount of time in seconds that the client should wait between polling requests

Errors

400

Invalid request parameters

Check the request fields and any validation details, then correct the payload.

500

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Register a public OAuth client

View source specification ↗
POST /oauth/register

RFC 7591 anonymous public-client registration. No Google session is required. This registration gives no user or resource permissions. Public clients must use PKCE S256, resource-bound authorization_code flow and explicit user consent. Client name, software_id and client_uri are unverified claims, not proof of Muse or any other product. Untrusted software_statement is rejected. Remote callbacks require HTTPS. HTTP is allowed for localhost or literal loopback IPs only, and local callbacks cannot be mixed with remote callbacks. SHA-256 of canonical client_name, sorted redirect_uris, sorted grant_types, sorted response_types and token_endpoint_auth_method identifies a registration. A repeated fingerprint returns the original client_id and accepted metadata, including its original scopes; it never overwrites metadata or expands scopes. Reused registrations do not consume new-registration quota. Unknown metadata extensions are ignored as required by RFC 7591. The deployment enforces rolling registration and retained-client quotas.

Required scope

Not required

Request body

Fields
client_namestring

Unverified display name.

maxLength: 200

redirect_urisarray<string>Required

Exact callbacks must form either an entirely localhost/loopback set or an entirely remote HTTPS set. HTTP is allowed only for localhost or literal loopback IPs. Local and remote callbacks cannot be mixed; user information and fragments are forbidden.

token_endpoint_auth_methodstringRequired

Allowed values: none.

grant_typesarray<string>

authorization_code, optionally with refresh_token, each at most once. Omitted, the server registers authorization_code and refresh_token and returns them.

uniqueItems: true

response_typesarray<string>
scopestring

Space-separated OAuthScope values accepted by the deployment DCR allowed_scopes policy. Omission selects endpoint:read (the least-privilege default) when the deployment allows it, and is refused otherwise.

client_uristring

Unverified descriptive URL; never fetched as evidence.

maxLength: 2048

software_idstring

Unverified software claim.

maxLength: 200

software_versionstring

maxLength: 100

software_statementstring

Unsupported; rejected if supplied.

Returns

201

Public client created; no client_secret is issued.

Fields
(payload)any

Errors

400

Invalid metadata, redirect URI, or unapproved software statement.

Check the request fields and any validation details, then correct the payload.

415

Use application/json.

Inspect the returned code and family and follow the error handling guide.

429

Registration quota reached. Wait before retrying; do not loop.

Wait for Retry-After or details.retryAfterSeconds when supplied; otherwise use backoff.

Response headers
Retry-After
See the source specification for this header.
503

Registration storage unavailable.

Wait for the provider or bridge to recover, then retry safely with backoff.

Open user consent for a resource-bound public client

View source specification ↗
GET /oauth/authorize

Browser entry for registered DCR or CIMD clients. Redirects to the sign-in and consent UI. The client must start its registered callback listener first, generate random state and an S256 challenge, and wait for the user. Validate callback state and iss before exchanging the code. A CIMD client_id is an HTTPS, non-loopback URL of a metadata document that the server fetches (size-limited). The document must repeat the URL as client_id, name the client, list HTTPS redirect_uris that pass the server's redirect rules, and declare either public authentication (none) or private_key_jwt with an RS256 or ES256 signing algorithm and an HTTPS jwks_uri. The redirect_uri you send must be one of the listed redirect_uris. Any other metadata is rejected with invalid_client. There is no per-deployment allowlist of CIMD client URLs.

Required scope

Not required

Query parameters

client_idstringRequired

The client_id of the requested resource.

redirect_uristringRequired

The redirect_uri of the requested resource.

format: "uri"

response_typestringRequired

The response_type of the requested resource.

Allowed values: code.

scopestringRequired

The scope of the requested resource.

statestringRequired

The state of the requested resource.

resourcestring

Canonical issuer for REST or issuer/mcp for MCP. Omission defaults to REST.

format: "uri"

code_challengestringRequired

The code_challenge of the requested resource.

code_challenge_methodstringRequired

The code_challenge_method of the requested resource.

Allowed values: S256.

Returns

302

Navigate to sign-in and pending consent.

No response body.

Response headers
Locationstring

format: "uri"

Errors

400

Invalid or unsupported OAuth request.

Check the request fields and any validation details, then correct the payload.

Complete pending consent with a signed user session

View source specification ↗
POST /oauth/authorize

The website uses this endpoint after sign-in. Agents open the authorization URL and wait for the user; they never manufacture the user session.

Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Request body

Fields
request_idstringRequired
approvedbooleanRequired
scopestring

Returns

200

One-time browser continuation URL. Navigate the browser to receive a 302 to the registered callback.

Fields
redirect_urlstringRequired

format: "uri"

Errors

400

Invalid, expired or consumed request.

Check the request fields and any validation details, then correct the payload.

401

User sign-in required.

Obtain a valid access token, then retry.

Read a pending request for the signed-in consent page

View source specification ↗
GET /oauth/authorization-request

Returns server-stored consent details to the authenticated website. Descriptive client metadata is unverified. Agents use the public authorization endpoint and wait for the user; a delegated device token cannot read this session-only endpoint.

Required scope

Any authenticated access token

Query parameters

request_idstringRequired

The request_id of the requested resource.

Returns

200

Pending consent details. Response is not cacheable.

Fields
client_idstringRequired
client_namestringRequired
redirect_uristringRequired

format: "uri"

resourcestringRequired

format: "uri"

scopesarray<string>Required

Errors

400

Invalid, expired or consumed request.

Check the request fields and any validation details, then correct the payload.

401

User sign-in required.

Obtain a valid access token, then retry.

Redirect the browser to the approved OAuth callback

View source specification ↗
GET /oauth/authorization-response

Navigate the browser here using the continuation returned by authenticated consent. The opaque reference expires after two minutes and is consumed once. The server chooses the stored callback; caller-supplied redirect destinations are never used. Approval carries code, original state and issuer; denial carries access_denied, original state and issuer. No bearer token is needed.

Required scope

Not required

Query parameters

request_idstringRequired

Opaque, single-use continuation reference returned by authenticated consent.

Returns

302

Navigate with GET to the exact registered callback.

No response body.

Response headers
Locationstring

format: "uri"

Response headers
Cache-Controlstring

no-store

Response headers
Referrer-Policystring

no-referrer

Errors

400

Missing, wrong-stage, expired or consumed continuation reference.

Check the request fields and any validation details, then correct the payload.

Identity and access

Identity and access APIs manage principals, clients, secrets and permissions.

Principals

v1.0

Enumerate Principals

View source specification ↗
GET /principals

Lists principals owned by the authenticated caller by default. Supplying an owner selects that owner's principals, subject to the caller's principal-read permissions. Supplying an ID selects a single principal, subject to the same permission check. The default page size is 10 and the maximum page size is 100.

Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Query parameters

ownerstring

Owner whose principals to list. Defaults to the authenticated caller when ID is not supplied. A different owner requires principal-read permission for each returned principal.

idstring

Exact principal identifier to retrieve. The result is included only when the caller has principal-read permission.

expandarray<string>

Expansion tokens that request related or computed fields for each result. When omitted, the response contains only the default, shallower set of fields for each result.

nextTokenstring

Opaque token for the next page of results. Pass the continuation token returned by the previous response, unchanged. Omit it to start from the first page.

maxResultsinteger

Maximum number of results to return in one page. Defaults to 100. Values from 1 through 100 are accepted.

minimum: 1

maximum: 100

Default: 100

Returns

200

Principals retrieved successfully

Fields
resultsarray<Principal>Required
paginationContextPaginationContext
errorsarray<Error>

Partial query errors collected while returning available results.

Errors

400 BAD_REQUEST

Invalid owner, ID, page size, or pagination token

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Authentication is required

Obtain a valid access token, then retry.

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Upsert Principal

View source specification ↗
POST /principals

Creates a new principal

Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Request body

Fields
itemPrincipal

Returns

200

Principal created successfully

Fields
resultPrincipal

Errors

400

Invalid request payload

Check the request fields and any validation details, then correct the payload.

500

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Delete Principal

View source specification ↗
DELETE /{namespace}/{principalType}/{principalId}

Deletes a principal

Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Path parameters

namespacestringRequired

The namespace of the principal that the flow belongs to.

principalTypestringRequired

The type of principal that the flow belongs to.

principalIdstringRequired

The ID of the principal that the flow belongs to.

Returns

200

Principal deleted successfully

No response body.

Errors

500

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Secrets

v1.0

Use secrets to store a credential that Port OS needs to keep for you, such as a key a plugin uses to call a provider.

Enumerate Secrets

View source specification ↗
GET /secrets

Lists all secrets

Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Query parameters

idstring

The ID of the secret to get

ownerstring

The owner of the secrets to get

nextTokenstring

Opaque token for the next page of results. Pass the continuation token returned by the previous response, unchanged. Omit it to start from the first page.

maxResultsinteger

The maximum number of results to return

minimum: 1

maximum: 100

expandarray<string>

Expansion tokens that request related or computed fields for each result. When omitted, the response contains only the default, shallower set of fields for each result.

Returns

200

Secrets retrieved successfully

Fields
resultsarray<Secret>Required
paginationContextPaginationContext
errorsarray<Error>

Partial query errors collected while returning available results.

Errors

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Upsert Secret

View source specification ↗
POST /secrets

Create a secret, which is a special type of data that is secured. Secrets are special data that can be very dangerous to use, and so is put in a special database.

Some well known types of secrets include: Random secret data, access tokens, passwords, and various others.

Generic secrets

If you want to keep something secret, and have it super safe, you can create a secret. This secret is stored in portos with a unique resource identifier for a storage document.

For example, maybe you have client credentials or something that is a generic json blob.

i.e. https://api.portoperatingsystem.com/storage/secrets/portos1.secret.<UUID>

Tokens

A specialized type of secret is a OAUTH token secret. This secret is often used to access plugins, so there are specialized indexes to make token look up faster.

Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Request body

Fields
secretOauthTokenSecret | OauthClientCredentialSecret | ApplePushNotificationAuthTokenSecret | PersonalAccessTokenSecret | CustomPluginSecret | ApiKeySecretRequired

discriminator: type

Returns

200

Secret created successfully

Fields
idstringRequired

The created secret ID

Errors

400

Invalid request payload

Check the request fields and any validation details, then correct the payload.

500

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Delete Secret

View source specification ↗
DELETE /port1/{principalType}/{principalId}/secrets/{secretId}

Deletes a secret

Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Path parameters

principalTypestringRequired

The type of principal that the secret belongs to.

principalIdstringRequired

The ID of the principal that the secret belongs to.

secretIdstringRequired

The ID of the secret to delete.

Returns

200

Secret deleted successfully

No response body.

Errors

400

Invalid request payload

Check the request fields and any validation details, then correct the payload.

500

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Clients

v1.0

Enumerate OAuth Clients

View source specification ↗
GET /oauth-clients

Lists all OAuth clients for the authenticated user

Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Query parameters

nextTokenstring

Opaque token for the next page of results. Pass the continuation token returned by the previous response, unchanged. Omit it to start from the first page.

maxResultsinteger

The maximum number of results to return

minimum: 1

maximum: 100

expandarray<string>

Expansion tokens that request related or computed fields for each result. When omitted, the response contains only the default, shallower set of fields for each result.

Returns

200

OAuth clients retrieved successfully

Fields
resultsarray<OAuthClient>Required

A list of registered OAuth clients.

paginationContextPaginationContext
errorsarray<Error>

Partial query errors collected while returning available results.

Errors

400 BAD_REQUEST

Invalid request payload

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Unauthorized - invalid or missing authentication token

Obtain a valid access token, then retry.

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Create OAuth Client

View source specification ↗
POST /oauth-clients

Creates a new OAuth client registration. This endpoint allows you to register a new OAuth client with Port OS. The client will be assigned a unique client ID and a client secret that can be used for OAuth authentication flows. The client secret is only returned once during creation, so make sure to store it securely.

Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Request body

Fields
clientNamestringRequired

A human-readable string name of the client to be presented to the end-user during authorization. If omitted, the authorization server may display the raw "client_id" value to the end-user instead. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

clientUristring

A URL string of a web page providing information about the client. If present, the server should display this URL to the end-user in a clickable fashion. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

format: "uri"

clientUriLocalizedobject

Localized versions of the client URI using language tags as keys (BCP 47 format). The keys are language tags and values are the localized URIs. See https://datatracker.ietf.org/doc/html/rfc7591#section-2.2

logoUristring

A URL string that references a logo for the client. If present, the server should display this image to the end-user during approval. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

format: "uri"

logoUriLocalizedobject

Localized versions of the logo URI using language tags as keys (BCP 47 format). The keys are language tags and values are the localized logo URIs. See https://datatracker.ietf.org/doc/html/rfc7591#section-2.2

redirectUrisarray<string>

An array of redirection URI strings for use in redirect-based flows such as the authorization code and implicit flows. Clients using these flows must register their redirection URI values. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

allowedOriginsarray<string>

An array of authorized JavaScript origin strings. When set, the server validates the Origin header on token requests against this list. Origins are scheme + host (+ optional port), with no path.

grantTypesarray<string>

An array of OAuth 2.0 grant type strings that the client can use at the token endpoint, each at most once. The token endpoint refuses any other grant with `unauthorized_client`, and a refresh token is issued only to a client that registered refresh_token. authorization_code requires redirect_uris; client_credentials requires a client_secret_post, client_secret_basic or private_key_jwt client. When omitted, the server registers authorization_code and refresh_token, or client_credentials for a private_key_jwt client, and returns the registered list (RFC 7591 lets the server substitute values). See https://datatracker.ietf.org/doc/html/rfc7591#section-2

uniqueItems: true

Default: ["authorization_code","refresh_token"]

responseTypesarray<string>

An array of OAuth 2.0 response type strings that the client can use at the authorization endpoint. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

tokenEndpointAuthMethodstring

A string indicating the requested authentication method for the token endpoint. Values defined by this specification are "client_secret_post", "client_secret_basic", "client_secret_jwt", "private_key_jwt", and "none". See https://datatracker.ietf.org/doc/html/rfc7591#section-2

Default: client_secret_basic

Allowed values: client_secret_post, client_secret_basic, client_secret_jwt, private_key_jwt, none.

tokenEndpointAuthSigningAlgstring

A string containing a JWS signing algorithm (alg value) that MUST be used for signing the JWT used to authenticate the client at the token endpoint for the "private_key_jwt" and "client_secret_jwt" authentication methods. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

Allowed values: RS256, ES256.

scopesarray<OAuthScope>

List of OAuth scopes that this client can request. This is the primary field for specifying scopes. Scopes are mapped to Cedar permissions (e.g., "endpoint:read" maps to "endpoint.read"). See https://datatracker.ietf.org/doc/html/rfc7591#section-2

scopestring

A string containing a space-separated list of scope values that the client can use when requesting access tokens. This is a convenience field that represents the scopes array as a space-separated string. If both scope and scopes are provided, scopes takes precedence. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

contactsarray<string>

An array of strings representing ways to contact people responsible for this client, typically email addresses. The authorization server may make these contact addresses available to end-users for support requests for the client. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

tosUristring

A URL string that points to a human-readable terms of service document for the client that describes a contractual relationship between the end-user and the client that the end-user accepts when authorizing the client. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

format: "uri"

tosUriLocalizedobject

Localized versions of the terms of service URI using language tags as keys (BCP 47 format). The keys are language tags and values are the localized terms of service URIs. See https://datatracker.ietf.org/doc/html/rfc7591#section-2.2

policyUristring

A URL string that points to a human-readable privacy policy document that describes how the deployment organization collects, uses, retains, and discloses personal data. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

format: "uri"

policyUriLocalizedobject

Localized versions of the privacy policy URI using language tags as keys (BCP 47 format). The keys are language tags and values are the localized privacy policy URIs. See https://datatracker.ietf.org/doc/html/rfc7591#section-2.2

jwksUristring

A URL string referencing the client's JSON Web Key (JWK) Set document, which contains the client's public keys. These keys can be used by higher-level protocols that use signing or encryption. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

format: "uri"

jwksOAuthClientJwks

The client's JSON Web Key Set document value, which contains the client's public keys. This parameter is intended to be used by clients that cannot use the "jwks_uri" parameter, such as native clients that cannot host public URLs. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

softwareIdstring

A unique identifier string assigned by the client developer or software publisher used by registration endpoints to identify the client software to be dynamically registered. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

softwareVersionstring

A version identifier string for the client software identified by "software_id". The value of the "software_version" should change on any update to the client software identified by the same "software_id". See https://datatracker.ietf.org/doc/html/rfc7591#section-2

Returns

200

OAuth client created successfully

Fields
clientIdstringRequired

The created OAuth client ID

clientSecretstringRequired

The OAuth client secret (only returned on creation). This is the secret string known only to the client and the authorization server, used for authenticating the client. See https://datatracker.ietf.org/doc/html/rfc7591#section-2.2

clientSecretExpiresAtinteger

An integer indicating the expiration time of the client secret, represented as the number of seconds since the Unix epoch (1970-01-01T00:00:00Z). A value of 0 indicates that the secret does not expire. See https://datatracker.ietf.org/doc/html/rfc7591#section-2.2

Errors

400

Invalid request payload

Check the request fields and any validation details, then correct the payload.

401

Unauthorized - invalid or missing authentication token

Obtain a valid access token, then retry.

500

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Get OAuth Client

View source specification ↗
GET /port1/{principalType}/{principalId}/oauth-clients/{clientId}

Retrieves details of a specific OAuth client

Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Path parameters

principalTypestringRequired

The type of principal that owns the OAuth client

principalIdstringRequired

The ID of the principal that owns the OAuth client

clientIdstringRequired

The ID of the OAuth client to retrieve

Query parameters

expandarray<string>

Expansion tokens that request related or computed fields for the returned resource.

Returns

200

OAuth client retrieved successfully

Fields
idstring

Stable query result identifier for the OAuth client. Mirrors clientId.

clientIdstringRequired

The unique identifier for the OAuth client

clientNamestringRequired

A human-readable string name of the client to be presented to the end-user during authorization. If omitted, the authorization server may display the raw "client_id" value to the end-user instead. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

clientUristring

A URL string of a web page providing information about the client. If present, the server should display this URL to the end-user in a clickable fashion. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

format: "uri"

logoUristring

A URL string that references a logo for the client. If present, the server should display this image to the end-user during approval. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

format: "uri"

redirectUrisarray<string>

An array of redirection URI strings for use in redirect-based flows such as the authorization code and implicit flows. Clients using these flows must register their redirection URI values. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

allowedOriginsarray<string>

An array of authorized JavaScript origin strings. When set, the server validates the Origin header on token requests against this list. Origins are scheme + host (+ optional port), with no path.

grantTypesarray<string>

An array of OAuth 2.0 grant type strings that the client can use at the token endpoint. The token endpoint refuses any other grant with `unauthorized_client`, and a refresh token is issued only to a client that registered refresh_token. Registration stores authorization_code and refresh_token (client_credentials for a private_key_jwt client) when the request omits grant types; a stored client with an empty list may use only authorization_code (the RFC 7591 default). See https://datatracker.ietf.org/doc/html/rfc7591#section-2

responseTypesarray<string>

An array of OAuth 2.0 response type strings that the client can use at the authorization endpoint. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

tokenEndpointAuthMethodstring

A string indicating the requested authentication method for the token endpoint. Values defined by this specification are "client_secret_post", "client_secret_basic", "client_secret_jwt", "private_key_jwt", and "none". See https://datatracker.ietf.org/doc/html/rfc7591#section-2

Allowed values: client_secret_post, client_secret_basic, client_secret_jwt, private_key_jwt, none.

tokenEndpointAuthSigningAlgstring

A string containing a JWS signing algorithm (alg value) that MUST be used for signing the JWT used to authenticate the client at the token endpoint for the "private_key_jwt" and "client_secret_jwt" authentication methods. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

Allowed values: RS256, ES256.

scopestring

A string containing a space-separated list of scope values that the client can use when requesting access tokens. Valid scopes are: endpoint:read, endpoint:write, message:read, message:send, secret:read, secret:write, principal:read, principal:write, subscription:read, subscription:write, access-control-rule:read, access-control-rule:write. Scopes are mapped to Cedar permissions (e.g., "endpoint:read" maps to "endpoint.read"). See https://datatracker.ietf.org/doc/html/rfc7591#section-2

scopesarray<OAuthScope>

List of OAuth scopes that this client can request (array representation of scope). This is a convenience field that represents the space-separated scope string as an array. Scopes are mapped to Cedar permissions (e.g., "endpoint:read" maps to "endpoint.read").

contactsarray<string>

An array of strings representing ways to contact people responsible for this client, typically email addresses. The authorization server may make these contact addresses available to end-users for support requests for the client. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

tosUristring

A URL string that points to a human-readable terms of service document for the client that describes a contractual relationship between the end-user and the client that the end-user accepts when authorizing the client. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

format: "uri"

tosUriLocalizedobject

Localized versions of the terms of service URI using language tags as keys (BCP 47 format). The keys are language tags and values are the localized terms of service URIs. See https://datatracker.ietf.org/doc/html/rfc7591#section-2.2

policyUristring

A URL string that points to a human-readable privacy policy document that describes how the deployment organization collects, uses, retains, and discloses personal data. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

format: "uri"

policyUriLocalizedobject

Localized versions of the privacy policy URI using language tags as keys (BCP 47 format). The keys are language tags and values are the localized privacy policy URIs. See https://datatracker.ietf.org/doc/html/rfc7591#section-2.2

clientSecretstring

The client secret string known only to the client and the authorization server. This secret is used for authenticating the client to the authorization server. This field is typically only returned during client registration and should not be included in GET responses for security reasons. See https://datatracker.ietf.org/doc/html/rfc7591#section-2.2

clientSecretExpiresAtinteger

An integer indicating the expiration time of the client secret, represented as the number of seconds since the Unix epoch (1970-01-01T00:00:00Z). A value of 0 indicates that the secret does not expire. See https://datatracker.ietf.org/doc/html/rfc7591#section-2.2

jwksUristring

A URL string referencing the client's JSON Web Key (JWK) Set document, which contains the client's public keys. These keys can be used by higher-level protocols that use signing or encryption. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

format: "uri"

jwksOAuthClientJwks

The client's JSON Web Key Set document value, which contains the client's public keys. This parameter is intended to be used by clients that cannot use the "jwks_uri" parameter, such as native clients that cannot host public URLs. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

softwareIdstring

A unique identifier string assigned by the client developer or software publisher used by registration endpoints to identify the client software to be dynamically registered. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

softwareVersionstring

A version identifier string for the client software identified by "software_id". The value of the "software_version" should change on any update to the client software identified by the same "software_id". See https://datatracker.ietf.org/doc/html/rfc7591#section-2

ownerIdstring

The owner ID of the OAuth client (Port OS specific field)

createdAtstring

The timestamp when the OAuth client was created (Port OS specific field)

format: "date-time"

updatedAtstring

The timestamp when the OAuth client was last updated (Port OS specific field)

format: "date-time"

Errors

400 BAD_REQUEST

Invalid request payload

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Unauthorized - invalid or missing authentication token

Obtain a valid access token, then retry.

404 INVALID_VALUE

OAuth client not found

Verify the target identifier and that its endpoint or plugin route still exists.

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Update OAuth Client

View source specification ↗
PUT /port1/{principalType}/{principalId}/oauth-clients/{clientId}

Updates an existing OAuth client. This endpoint allows you to update the configuration of an OAuth client, such as its name, redirect URIs, grant types, and scopes. Note: The client secret cannot be updated through this endpoint. To rotate a secret, generate an additional secret through the client's secrets child collection and revoke the old secret after migrating consumers.

Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Path parameters

principalTypestringRequired

The type of principal that owns the OAuth client

principalIdstringRequired

The ID of the principal that owns the OAuth client

clientIdstringRequired

The ID of the OAuth client to update

Request body

Fields
clientNamestring

A human-readable string name of the client to be presented to the end-user during authorization. If omitted, the authorization server may display the raw "client_id" value to the end-user instead. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

clientUristring

A URL string of a web page providing information about the client. If present, the server should display this URL to the end-user in a clickable fashion. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

format: "uri"

clientUriLocalizedobject

Localized versions of the client URI using language tags as keys (BCP 47 format). The keys are language tags and values are the localized URIs. See https://datatracker.ietf.org/doc/html/rfc7591#section-2.2

logoUristring

A URL string that references a logo for the client. If present, the server should display this image to the end-user during approval. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

format: "uri"

logoUriLocalizedobject

Localized versions of the logo URI using language tags as keys (BCP 47 format). The keys are language tags and values are the localized logo URIs. See https://datatracker.ietf.org/doc/html/rfc7591#section-2.2

redirectUrisarray<string>

An array of redirection URI strings for use in redirect-based flows such as the authorization code and implicit flows. Clients using these flows must register their redirection URI values. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

allowedOriginsarray<string>

An array of authorized JavaScript origin strings. When set, the server validates the Origin header on token requests against this list. Origins are scheme + host (+ optional port), with no path.

grantTypesarray<string>

An array of OAuth 2.0 grant type strings that the client can use at the token endpoint. The token endpoint refuses any other grant with `unauthorized_client`; a client with an empty list may use only authorization_code (the RFC 7591 default). See https://datatracker.ietf.org/doc/html/rfc7591#section-2

uniqueItems: true

responseTypesarray<string>

An array of OAuth 2.0 response type strings that the client can use at the authorization endpoint. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

tokenEndpointAuthMethodstring

A string indicating the requested authentication method for the token endpoint. Values defined by this specification are "client_secret_post", "client_secret_basic", "client_secret_jwt", "private_key_jwt", and "none". See https://datatracker.ietf.org/doc/html/rfc7591#section-2

Allowed values: client_secret_post, client_secret_basic, client_secret_jwt, private_key_jwt, none.

tokenEndpointAuthSigningAlgstring

A string containing a JWS signing algorithm (alg value) that MUST be used for signing the JWT used to authenticate the client at the token endpoint for the "private_key_jwt" and "client_secret_jwt" authentication methods. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

Allowed values: RS256, ES256.

scopesarray<OAuthScope>

List of OAuth scopes that this client can request. This is the primary field for specifying scopes. Scopes are mapped to Cedar permissions (e.g., "endpoint:read" maps to "endpoint.read"). See https://datatracker.ietf.org/doc/html/rfc7591#section-2

scopestring

A string containing a space-separated list of scope values that the client can use when requesting access tokens. This is a convenience field that represents the scopes array as a space-separated string. If both scope and scopes are provided, scopes takes precedence. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

contactsarray<string>

An array of strings representing ways to contact people responsible for this client, typically email addresses. The authorization server may make these contact addresses available to end-users for support requests for the client. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

tosUristring

A URL string that points to a human-readable terms of service document for the client that describes a contractual relationship between the end-user and the client that the end-user accepts when authorizing the client. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

format: "uri"

tosUriLocalizedobject

Localized versions of the terms of service URI using language tags as keys (BCP 47 format). The keys are language tags and values are the localized terms of service URIs. See https://datatracker.ietf.org/doc/html/rfc7591#section-2.2

policyUristring

A URL string that points to a human-readable privacy policy document that describes how the deployment organization collects, uses, retains, and discloses personal data. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

format: "uri"

policyUriLocalizedobject

Localized versions of the privacy policy URI using language tags as keys (BCP 47 format). The keys are language tags and values are the localized privacy policy URIs. See https://datatracker.ietf.org/doc/html/rfc7591#section-2.2

jwksUristring

A URL string referencing the client's JSON Web Key (JWK) Set document, which contains the client's public keys. These keys can be used by higher-level protocols that use signing or encryption. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

format: "uri"

jwksOAuthClientJwks

The client's JSON Web Key Set document value, which contains the client's public keys. This parameter is intended to be used by clients that cannot use the "jwks_uri" parameter, such as native clients that cannot host public URLs. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

softwareIdstring

A unique identifier string assigned by the client developer or software publisher used by registration endpoints to identify the client software to be dynamically registered. See https://datatracker.ietf.org/doc/html/rfc7591#section-2

softwareVersionstring

A version identifier string for the client software identified by "software_id". The value of the "software_version" should change on any update to the client software identified by the same "software_id". See https://datatracker.ietf.org/doc/html/rfc7591#section-2

Returns

200

OAuth client updated successfully

Fields
clientIdstringRequired

The updated OAuth client ID

Errors

400

Invalid request payload

Check the request fields and any validation details, then correct the payload.

401

Unauthorized - invalid or missing authentication token

Obtain a valid access token, then retry.

404

OAuth client not found

Verify the target identifier and that its endpoint or plugin route still exists.

500

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Delete OAuth Client

View source specification ↗
DELETE /port1/{principalType}/{principalId}/oauth-clients/{clientId}

Deletes an OAuth client. This permanently removes the OAuth client and invalidates all associated tokens. This action cannot be undone.

Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Path parameters

principalTypestringRequired

The type of principal that owns the OAuth client

principalIdstringRequired

The ID of the principal that owns the OAuth client

clientIdstringRequired

The ID of the OAuth client to delete

Returns

200

OAuth client deleted successfully

No response body.

Errors

400

Invalid request payload

Check the request fields and any validation details, then correct the payload.

401

Unauthorized - invalid or missing authentication token

Obtain a valid access token, then retry.

404

OAuth client not found

Verify the target identifier and that its endpoint or plugin route still exists.

500

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

List OAuth Client Secrets

View source specification ↗
GET /port1/{principalType}/{principalId}/oauth-clients/{clientId}/secrets

Lists active masked secrets for the selected OAuth client. Plaintext and hashes are never returned.

Required scope

Any authenticated access token

Path parameters

principalTypestringRequired

The type of principal that owns the OAuth client

principalIdstringRequired

The ID of the principal that owns the OAuth client

clientIdstringRequired

The ID of the OAuth client

Returns

200

List OAuth Client Secrets response.

Fields
secretsarray<OAuthClientSecretInfo>Required

Errors

400 BAD_REQUEST

Invalid request path.

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Authentication required.

Obtain a valid access token, then retry.

403 FORBIDDEN

The caller cannot read or manage the selected OAuth client.

Check the linked account and its permissions for the device or resource.

404 NOT_FOUND

OAuth client or secret not found.

Verify the target identifier and that its endpoint or plugin route still exists.

500 INTERNAL

Internal server error.

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Generate OAuth Client Secret

View source specification ↗
POST /port1/{principalType}/{principalId}/oauth-clients/{clientId}/secrets

Creates an additional secret and returns its plaintext once. Existing secrets remain active until explicitly revoked.

Required scope

Any authenticated access token

Path parameters

principalTypestringRequired

The type of principal that owns the OAuth client

principalIdstringRequired

The ID of the principal that owns the OAuth client

clientIdstringRequired

The ID of the OAuth client

Returns

200

Generate OAuth Client Secret response.

Fields
secretIdstringRequired

Opaque child identifier scoped to the selected OAuth client.

clientSecretstringRequired

Plaintext client secret returned once.

Errors

400 BAD_REQUEST

Invalid request path.

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Authentication required.

Obtain a valid access token, then retry.

403 FORBIDDEN

The caller cannot read or manage the selected OAuth client.

Check the linked account and its permissions for the device or resource.

404 NOT_FOUND

OAuth client or secret not found.

Verify the target identifier and that its endpoint or plugin route still exists.

500 INTERNAL

Internal server error.

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Revoke OAuth Client Secret

View source specification ↗
DELETE /port1/{principalType}/{principalId}/oauth-clients/{clientId}/secrets/{secretId}

Permanently revokes one secret belonging to the selected OAuth client. Other secrets remain active.

Required scope

Any authenticated access token

Path parameters

principalTypestringRequired

The type of principal that owns the OAuth client

principalIdstringRequired

The ID of the principal that owns the OAuth client

clientIdstringRequired

The ID of the OAuth client

secretIdstringRequired

The ID of the OAuth client secret

Returns

200

Revoke OAuth Client Secret response.

No response body.

Errors

400 BAD_REQUEST

Invalid request path.

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Authentication required.

Obtain a valid access token, then retry.

403 FORBIDDEN

The caller cannot read or manage the selected OAuth client.

Check the linked account and its permissions for the device or resource.

404 NOT_FOUND

OAuth client or secret not found.

Verify the target identifier and that its endpoint or plugin route still exists.

500 INTERNAL

Internal server error.

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Access control

v1.0

Upsert Access Control Rule

View source specification ↗
POST /access-control-rules

Upsert an access control rule.

Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Header parameters

If-Matchstring

Optional quoted etag of the rule as last read (its `etag` field). When present the upsert applies only if it still matches the rule's current etag, otherwise 412 PRECONDITION_FAILED; `*` requires the rule to exist. Omitted, the upsert is unconditional.

minLength: 1

Request body

Fields
idstring

The ID of the access control rule to upsert on.

effectstringRequired

Allowed values: ALLOW, DENY.

operationstringRequired

The operation to grant access to. This could be a read, write, delete, etc. Please see the access controls list specification for all operations and their descriptions.

resourcestringRequired

The resource to grant access to. This could be an endpoint, a flow, a secret, etc. You can define this as either a class of resources, or a specific resource. Examples: - port1/principals/alice/endpoints/thermostat-zero grants access to that thermostat - port1/principals/alice/flows/* grants access to all flows owned by alice

identitystringRequired

The identity to grant access to. This could be a user, a role, a group, etc. You can define this as either a class of identities, or a specific identity. Examples: - port1/principals/bob grants access to bob - * just grants access to all identities

conditionsarray<AccessControlRuleCondition>

Conditions on the operation context that must all match for the rule to apply. Omitting conditions means the rule has none.

reasonstring

Optional operator-supplied reason recorded in the audit log for this change.

maxLength: 500

Returns

200

Access control rule upserted successfully

Fields
idstringRequired

The ID of the access control rule

Response headers
ETagstring

Opaque strong entity tag of the returned resource version. Send it back in `If-Match` on the next mutation of the same resource.

Errors

400

Invalid request payload

Check the request fields and any validation details, then correct the payload.

412 PRECONDITION_FAILED

The If-Match etag does not match the current access control rule; re-read the rule and retry

Inspect the returned code and family and follow the error handling guide.

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Get Access Control Rules

View source specification ↗
GET /access-control-rules

Get access-control rules owned by the authenticated caller by default. Supplying an owner selects that owner's rules, and an ID selects one rule; results remain subject to the caller's access-control-rule-read permissions. The default page size is 10 and the maximum page size is 100.

Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Query parameters

ownerstring

Owner whose access-control rules to get. Defaults to the authenticated caller unless an ID is supplied. A different owner requires read permission for each returned rule.

idstring

Exact access-control rule identifier to retrieve. The result is included only when the caller has read permission.

operationstring

Exact operation to match. Only rules whose operation equals this value are returned.

resourcestring

Exact resource to match. Only rules whose resource equals this value are returned.

identitystring

Exact identity to match. Only rules whose identity equals this value are returned.

nextTokenstring

Opaque token for the next page of results. Pass the continuation token returned by the previous response, unchanged. Omit it to start from the first page.

maxResultsinteger

Maximum number of results to return in one page. Defaults to 100. Values from 1 through 100 are accepted.

minimum: 1

maximum: 100

Default: 100

expandarray<string>

Expansion tokens that request related or computed fields for each result. When omitted, the response contains only the default, shallower set of fields for each result.

Returns

200

Access control rules retrieved successfully

Fields
resultsarray<AccessControlRule>Required
paginationContextPaginationContext
errorsarray<Error>

Partial query errors collected while returning available results.

Errors

400 BAD_REQUEST

Invalid owner, ID, page size, or pagination token

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Authentication is required

Obtain a valid access token, then retry.

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Get Access Control Rule Audit

View source specification ↗
GET /access-control-rules/audit

Read the audit of access-control rule changes, newest first. Every rule upsert and delete records who made it, through which client, why, and under which request, plus the rule as it was written. Entries hold identifiers and the rule's shape only, never token text. Entries older than the configured retention (auth.audit.retentionDays, default 365) are pruned at server start.

Only operator callers (operational tokens) and system zero may read the audit; any other caller receives 403. The default page size is 50 and the maximum is 200.

Required scope

Any authenticated access token

Query parameters

ruleIdstring

Only entries about this access-control rule.

actorPrincipalstring

Only entries made by this principal.

resourcestring

Exact resource of the audited rule.

operationstring

Exact operation of the audited rule.

sincestring

Only entries recorded at or after this time (RFC 3339).

format: "date-time"

untilstring

Only entries recorded before this time (RFC 3339).

format: "date-time"

nextTokenstring

Opaque token for the next page of results. Pass the continuation token returned by the previous response, unchanged. Omit it to start from the first page.

maxResultsinteger

Maximum number of entries to return in one page. Defaults to 50. Values from 1 through 200 are accepted.

minimum: 1

maximum: 200

Default: 50

Returns

200

Audit entries retrieved successfully

Fields
resultsarray<AccessControlRuleAuditEntry>Required

Audit entries, newest first.

paginationContextPaginationContext

Errors

400 BAD_REQUEST

Invalid filter, page size, time or pagination token

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Authentication is required

Obtain a valid access token, then retry.

403 FORBIDDEN

The caller is not an operator

Check the linked account and its permissions for the device or resource.

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Evaluate Access Control Rule

View source specification ↗
POST /access-control-rules/evaluate

Evaluate an access control rule.

Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Request body

Fields
requesterContextAccessControlRequesterContextRequired
resourceContextAccessControlResourceContextRequired
entitiesarray<AccessControlEntity>Required
operationstringRequired
operationContextAccessControlOperationContext

Attributes of the requested operation that rule conditions are evaluated against.

Returns

200

Access control rule evaluated successfully

Fields
resultstring

Allowed values: ALLOW, DENY.

errorError

The one Port OS error shape, returned by every REST error response and every MCP tool error. `code` names the specific failure and `family` its broad class; both are closed enums, so clients branch on them and show `message`, which says what failed and what to do next.

Errors

400

Invalid request payload

Check the request fields and any validation details, then correct the payload.

500

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Delete Access Control Rule

View source specification ↗
DELETE /{namespace}/{principalType}/{principalId}/access-control-rules/{ruleId}

Delete an access control rule.

Requires a signed user/session or the existing authenticated client flow. The anonymous DCR delegated device profile cannot invoke this operation.

Required scope

Any authenticated access token

Path parameters

namespacestringRequired

The namespace of the principal

principalTypestringRequired

The type of principal

principalIdstringRequired

The ID of the principal

ruleIdstringRequired

The ID of the access control rule to delete

Query parameters

reasonstring

Optional operator-supplied reason recorded in the audit log for this deletion.

maxLength: 500

Header parameters

If-Matchstring

Optional quoted etag of the rule as last read (its `etag` field). When present the deletion applies only if it still matches the rule's current etag, otherwise 412 PRECONDITION_FAILED; `*` requires the rule to exist. Omitted, the deletion is unconditional.

minLength: 1

Returns

200

Access control rule deleted successfully

No response body.

Errors

400

Invalid request payload

Check the request fields and any validation details, then correct the payload.

412 PRECONDITION_FAILED

The If-Match etag does not match the current access control rule; re-read the rule and retry

Inspect the returned code and family and follow the error handling guide.

500

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Automations

Automations APIs are used to automate devices and other things.

Subscriptions

v1.0

Enumerate Subscriptions

View source specification ↗
GET /subscriptions

Lists subscriptions owned by the authenticated caller when owner is omitted. Supplying owner selects that owner's subscriptions, filtered by the caller's SubscriptionRead permissions. Supplying id selects the exact subscription and still applies its read permission. The default page size is 10 and the maximum is 100; results use nextToken pagination.

Required scope

subscription:read

Query parameters

idstring

Exact subscription ID to retrieve, subject to the caller's read permission.

ownerstring

Filter the results by the owner of the resource. Defaults to the authenticated caller's resources when omitted. Use '~caller' to make that scope explicit. Another owner can be selected only for resources the caller can read.

expandarray<string>

Expansion tokens that request related or computed fields for each result. When omitted, the response contains only the default, shallower set of fields for each result.

nextTokenstring

Opaque token for the next page of results. Pass the continuation token returned by the previous response, unchanged. Omit it to start from the first page.

maxResultsinteger

Maximum number of results to return in one page. Defaults to 100. Values from 1 through 100 are accepted.

minimum: 1

maximum: 100

Default: 100

Returns

200

OK

Fields
resultsarray<Subscription>Required
paginationContextPaginationContext
errorsarray<Error>

Partial query errors collected while returning available results.

Errors

400 BAD_REQUEST

Invalid query parameter.

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Unauthorized — invalid or missing authentication token.

Obtain a valid access token, then retry.

403 INSUFFICIENT_PERMISSIONS

Forbidden — insufficient permissions for the requested owner.

Check the linked account and its permissions for the device or resource.

500 INTERNAL

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Upsert Subscription

View source specification ↗
POST /subscriptions

Used to upsert a subscription to an event stream.

Required scope

subscription:write

Request body

Fields
subscriptionSubscription

A subscription is a way to listen to events

Returns

200

OK, this confirms a subscription occurs, this is eventually consistent and is not guarantee

Fields
resultUpsertSubscriptionResult

Errors

400

Invalid request payload

Check the request fields and any validation details, then correct the payload.

500

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Delete Subscription

View source specification ↗
DELETE /{namespace}/{principalType}/{principalId}/subscriptions/{subscriptionId}

Delete a subscription.

Required scope

subscription:write

Path parameters

namespacestringRequired

The namespace of the principal

principalTypestringRequired

The type of principal

principalIdstringRequired

The ID of the principal

subscriptionIdstringRequired

The ID of the subscription to delete

Returns

200

Subscription deleted successfully

No response body.

Errors

400

Invalid request payload

Check the request fields and any validation details, then correct the payload.

500

Internal server error

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Inspect an authorized subscription

View source specification ↗
GET /{namespace}/{principalType}/{principalId}/subscriptions/{subscriptionId}

Returns the authorized canonical subscription. The verified MCP target is a same-ID binding reference; callback credentials and URL are never included.

Required scope

subscription:read

Path parameters

namespacestringRequired

The namespace of the principal

principalTypestringRequired

The type of principal

principalIdstringRequired

The ID of the principal

subscriptionIdstringRequired

The ID of the subscription to delete

Query parameters

expandarray<string>

Expansion tokens. This projection has no expandable relationships; omit or supply an empty array. Non-empty tokens are rejected.

Returns

200

Inspect an authorized subscription

Fields
idstringRequired

The unique identifier for the subscription

ownerstring

The owner of the subscription

nameTypeValue
queryQueryRequired

Shared Port OS query AST modeled as a recursive JSON graph supporting match, comparison, pattern, freeform, and boolean operators.

targetMessageTargetRequired
contextobject

Structured filter criteria for granular device event matching. Keys are dot-notation paths into the message (e.g., "header.namespace", "header.name"). Values are the expected values to match. All context entries must match for the subscription to fire. Omitting context matches all events.

statusstring

Event monitor lifecycle.

Allowed values: ACTIVE, PAUSED, SUSPENDED, EXPIRED, STOPPED.

reasonCodestring

Redacted stable lifecycle reason, when applicable.

expiresAtstring

Finite expiration; null means indefinite.

format: "date-time"

nullable: true

eventQueryProfilestring

Supported typed event query validation profile, when this is an event monitor.

Errors

400 BAD_REQUEST

Invalid request; stable code identifies the validation failure.

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Authentication required.

Obtain a valid access token, then retry.

403 FORBIDDEN

Resource authorization denied.

Check the linked account and its permissions for the device or resource.

404 NOT_FOUND

Resource inaccessible, missing or past retention.

Verify the target identifier and that its endpoint or plugin route still exists.

500 INTERNAL

Internal failure.

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.

Edit an authorized subscription label

View source specification ↗
PATCH /{namespace}/{principalType}/{principalId}/subscriptions/{subscriptionId}

Changes the label only. Preserves the ID, original host arguments, query, target, generation and activation sequence. Refresh and unsubscribe continue to resolve the original host identity.

Required scope

subscription:write

Path parameters

namespacestringRequired

The namespace of the principal

principalTypestringRequired

The type of principal

principalIdstringRequired

The ID of the principal

subscriptionIdstringRequired

The ID of the subscription to delete

Request body

Fields
nameTypeValueRequired

Returns

200

Edit an authorized subscription label

Fields
idstringRequired

The unique identifier for the subscription

ownerstring

The owner of the subscription

nameTypeValue
queryQueryRequired

Shared Port OS query AST modeled as a recursive JSON graph supporting match, comparison, pattern, freeform, and boolean operators.

targetMessageTargetRequired
contextobject

Structured filter criteria for granular device event matching. Keys are dot-notation paths into the message (e.g., "header.namespace", "header.name"). Values are the expected values to match. All context entries must match for the subscription to fire. Omitting context matches all events.

statusstring

Event monitor lifecycle.

Allowed values: ACTIVE, PAUSED, SUSPENDED, EXPIRED, STOPPED.

reasonCodestring

Redacted stable lifecycle reason, when applicable.

expiresAtstring

Finite expiration; null means indefinite.

format: "date-time"

nullable: true

eventQueryProfilestring

Supported typed event query validation profile, when this is an event monitor.

Errors

400 BAD_REQUEST

Invalid request; stable code identifies the validation failure.

Check the request fields and any validation details, then correct the payload.

401 UNAUTHORIZED

Authentication required.

Obtain a valid access token, then retry.

403 FORBIDDEN

Resource authorization denied.

Check the linked account and its permissions for the device or resource.

404 NOT_FOUND

Resource inaccessible, missing or past retention.

Verify the target identifier and that its endpoint or plugin route still exists.

409 CONCURRENT_MODIFICATION

subscription_identity_immutable: request attempts to change monitoring identity. Existing binding and queued jobs are untouched.

Check the device’s current mode or state. Retry only after the conflict is resolved.

500 INTERNAL

Internal failure.

Retry with backoff only when the operation is safe to repeat. Include the error code when reporting persistent failures.