Skip to content

Subscriptions

When a message gets sent to port OS, you may want to listen to it.

Customers can enable a subscription for a customer's events, and have the subscription published to a flow, a plugin, or endpoint.

This makes it so that subscriptions can trigger events.

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

A subscription is a way to listen to events

etagstringRequired

Opaque strong entity tag of the stored subscription version.

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.

paginationContextPaginationContext
errorsarray<Error>

Partial query errors collected while returning available results.

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.

familystringRequired

The broad class of an error. The family decides the HTTP status of a REST error, so clients can handle every code of a family alike.

codestringRequired

The specific error, one of a closed set of Port OS codes. Every REST error body, MCP tool error, batch item error and discovery item error uses this enum; each code belongs to an `ErrorFamily` that decides its HTTP status. Provider-specific codes are never codes: they travel in `details.providerCode`. New failure kinds are added here, never as free strings.

messagestringRequired

Plain-language description of the failure and the suggested next action.

detailsErrorDetails

Optional typed context for an error. Fields are additive and only populated when the error can safely expose that context to API clients.

errorsarray<SynchronizationItemError>

Every rejected item when a request that is validated item by item and applied atomically fails, such as a discovery `SynchronizationRequest` whose routes, group routes or relationships are rejected. Omitted for single-item failures.

One rejected discovery item of a `SynchronizationRequest`, keyed by the plugin-owned identity of the rejected item: `pluginRouteId` for a route or group route, or `relationshipExternalId` for a relationship. Exactly one of the two is set. It shares the `code`, `family`, `status` and `message` fields of `BatchItemError`; discovery items are keyed by plugin-owned identity because they carry no `requestId`. A request with any rejected item is rejected as a whole and lists every rejected item.

pluginRouteIdstring

Plugin-owned identifier of the rejected route or group route. Set unless the item is a relationship.

relationshipExternalIdstring

Plugin-owned `externalId` of the rejected relationship. Set only for relationship items.

interfacestring

Canonical capability interface name the failure applies to, when the failure is interface-specific.

versionstring

Declared capability interface version the failure applies to, when the failure is interface-specific.

codestringRequired

The specific error, one of a closed set of Port OS codes. Every REST error body, MCP tool error, batch item error and discovery item error uses this enum; each code belongs to an `ErrorFamily` that decides its HTTP status. Provider-specific codes are never codes: they travel in `details.providerCode`. New failure kinds are added here, never as free strings.

familystringRequired

The broad class of an error. The family decides the HTTP status of a REST error, so clients can handle every code of a family alike.

statusintegerRequired

HTTP-equivalent status code of the item failure.

minimum: 400

maximum: 599

messagestringRequired

Plain-language description of the failure and the suggested fix.

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

Creates a subscription with a server-assigned ID when id is omitted, or fully replaces an existing subscription. Replacements require If-Match (428 when missing, 412 when stale); an unknown supplied id returns 404. Verified event monitoring identity is immutable: replace its full writable projection to edit the label. Idempotency-Key is mandatory. Committed responses are retained for 24 hours, scoped to principal and operation. The same key and payload replay the original response; differing payloads return 422 and an in-flight request returns 409.

Required scope

subscription:write

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. Requests rolled back before external provider attempts do not consume the key. Group mutations retain terminal failed responses after provider attempts together with received provider truth; their operation contract defines these replayable outcomes.

minLength: 1

maxLength: 255

If-Matchstring

Required for a full replacement when the request identifies an existing resource. Send that resource's quoted strong etag from its last GET. A missing condition on a replacement returns 428 PRECONDITION_REQUIRED; a stale condition returns 412 PRECONDITION_FAILED. Omit this header when creating a new resource without an id. Wildcards are accepted only where the operation explicitly permits them.

minLength: 1

Request body

Required

Fields

subscriptionSubscriptionInputRequired

Complete writable subscription. Omit id to create with a server-assigned ID; include an existing id to replace with If-Match. Verified event monitors retain their original query, context and target; only their label may change.

Returns

200

Stored subscription including its new strong etag.

Fields
etagstringRequired

Opaque strong entity tag of the stored subscription version.

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.

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 writable payload or missing Idempotency-Key.

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

401

Authentication required.

Obtain a valid access token, then retry.

403

Subscription or delivery authorization denied.

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

404

Supplied subscription id does not exist.

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

409

Immutable event identity change or request still in flight.

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

412

If-Match does not match the current version.

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

422

Idempotency-Key was already used with a different payload.

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

428

Replacement requires If-Match.

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.

Delete Subscription

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

Deletes an existing subscription with If-Match and Idempotency-Key. Committed responses replay for 24 hours before target lookup; first deletes of unknown ids return 404.

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

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. Requests rolled back before external provider attempts do not consume the key. Group mutations retain terminal failed responses after provider attempts together with received provider truth; their operation contract defines these replayable outcomes.

minLength: 1

maxLength: 255

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. Wildcards are accepted only where the operation explicitly permits them.

minLength: 1

Returns

200

Subscription deleted successfully

No response body.

Errors

400

Invalid request or missing Idempotency-Key.

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

404

Subscription does not exist.

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

409

Request with this key is still in flight.

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

412

If-Match does not match the current version.

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

422

Idempotency-Key was used with a different payload.

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

428

If-Match is required.

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.

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
etagstringRequired

Opaque strong entity tag of the stored subscription version.

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.

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; 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.