Skip to content

Plugins

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.

List 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<PluginExpansion>

Space-delimited unique projection tokens. metadata expands the public provider declaration; oauth.clientSecret requests the protected OAuth credential projection under its existing authorization rules. Omit this parameter for the default catalog representation.

uniqueItems: true

Itemstring

A public plugin projection token. Credential expansion retains its existing authorization and no-store rules.

Allowed values

  • metadata
  • oauth.clientSecret
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

discriminator: type

WebsocketPluginWebsocketPlugin

Selected when type is WEBSOCKET

HttpPluginHttpPlugin

Selected when type is HTTP

WebservicePluginWebservicePlugin

Selected when type is WEBSERVICE

ApplePushNotificationPluginApplePushNotificationPlugin

Selected when type is APPLE_PUSH_NOTIFICATION

HostedComputePluginHostedComputePlugin

Selected when type is HOSTED_COMPUTE

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.

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

Unknown, repeated or malformed query parameter, out-of-range page size, or unsupported expansion 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.

Upsert Plugin

View source specification ↗
POST /plugins

Creates a server-assigned plugin or fully replaces an existing registration named by id. Every write requires Idempotency-Key; replacement requires the last observed strong If-Match.

A connection identity is host-assigned from authenticated principal, client and transport; an occupied scope cannot be created again without naming its existing id and etag. Replaying a committed write returns the retained entity without readmitting, disconnecting or altering its live transport connection. Credentials are never returned.

External WEBSOCKET and HTTP providers submit the connection branch with a public V2 manifest before connecting or discovering routes. The connection branch is mutually exclusive with plugin and credential fields; its identity is derived from the authenticated principal, client identity and transport. An absent or invalid declaration is a 400 INVALID_PLUGIN_MANIFEST and writes nothing.

Custom webservice and Apple push registrations use the plugin branch and also require manifestDocument. Their existing routing URL and credential fields remain authoritative; the public declaration cannot override deployment routing or credential values.

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

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

connectionobject

Admits an external connection provider before it connects or reports routes. The plugin identity is derived from the authenticated principal, client identity and transport. The server assigns the scoped identity. An existing id selects replacement with If-Match. A caller cannot set an owner, connection ID, active state, deployment configuration or executable handlers. This host requires auth.type NONE and no application, authorizationVariants or regionalizations for connection providers; unsupported hosted authorization declarations return 400 INVALID_PLUGIN_MANIFEST.

manifestDocumentstring

One public V2 plugin manifest document, encoded as strict YAML or JSON. The canonical declaration model and validation are owned by the public plugin-contract package. Unknown fields, extra documents, undeclared canonical identities, executable handlers, host deployment fields and credential values are rejected with INVALID_PLUGIN_MANIFEST. Capability support lists and profiles must be explicit, including empty lists.

minLength: 1

maxLength: 262144

pluginobject

Complete writable custom plugin registration. Omit id to create a server-owned identity; an existing id selects full replacement protected by If-Match. Runtime, owner and presentation fields are never writable.

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)

(payload) · option 1any
(payload) · option 2any

Returns

200

Canonical plugin stored atomically with its public declaration and credentials

Fields
(payload)any

Canonical stored plugin, including its server-assigned id, current strong etag and admitted public declaration. Credentials and executable handlers are never returned.

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

Authentication is required

Obtain a valid access token, then retry.

403 FORBIDDEN

The caller may not mutate this plugin

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

404 NOT_FOUND

The existing plugin was not found

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

409 CONFLICT

The key is in flight or the connection scope already exists

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

412 PRECONDITION_FAILED

The observed plugin revision is stale

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

422 IDEMPOTENCY_KEY_REUSED

The key was used for a different request

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

428 PRECONDITION_REQUIRED

If-Match is required for replacement

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 Plugin

View source specification ↗
GET /{namespace}/{principalType}/{principalId}/plugins/{pluginId}

Return the exact authorized canonical plugin through the query service, including its strong etag and public declaration. Credentials are never expanded by this item read.

Required scope

Any authenticated access token

Path parameters

namespacestringRequired

Resource namespace

principalTypestringRequired

Principal type

principalIdstringRequired

Principal identifier

pluginIdstringRequired

Plugin resource identifier

Returns

200

Canonical plugin resource

Fields
(payload)object

discriminator: type

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 plugin identifier

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

401 UNAUTHORIZED

Authentication is required

Obtain a valid access token, then retry.

404 NOT_FOUND

No authorized plugin has this identity

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

500 INTERNAL

The plugin query failed

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 /{namespace}/{principalType}/{principalId}/plugins/{pluginId}

Delete an existing plugin with its observed strong etag. A committed key replays its deletion; a new deletion intent after removal returns 404. No body is accepted and replay never re-admits a transport.

Required scope

Any authenticated access token

Path parameters

namespacestringRequired

Resource namespace

principalTypestringRequired

Principal type

principalIdstringRequired

Principal identifier

pluginIdstringRequired

Plugin resource identifier

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

Plugin deleted

No response body.

Errors

400 BAD_REQUEST

Invalid mutation request or unexpected body

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 may not mutate this plugin

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

404 NOT_FOUND

The existing plugin was not found

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

409 CONFLICT

The key is in flight or the connection scope already exists

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

412 PRECONDITION_FAILED

The observed plugin revision is stale

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

422 IDEMPOTENCY_KEY_REUSED

The key was used for a different request

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

428 PRECONDITION_REQUIRED

If-Match is required for replacement

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

500 INTERNAL

Plugin persistence failed

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