Exchange a plugin secret for a session token
const url = 'https://example.com/api/plugins/sessions';const options = { method: 'POST', headers: { 'X-MacroDeck-Plugin-Secret': '<X-MacroDeck-Plugin-Secret>', 'Content-Type': 'application/json' }, body: '{"requestedVersion":{"minimum":1,"maximum":1},"capabilities":[{"kind":"example","localId":"example","versionRange":{"minimum":1,"maximum":1},"displayName":"example"}],"declaredName":"example","declaredVersion":"example","sdk":{"sdkVersion":"example","deprecatedApis":["example"],"truncated":true}}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://example.com/api/plugins/sessions \ --header 'Content-Type: application/json' \ --header 'X-MacroDeck-Plugin-Secret: <X-MacroDeck-Plugin-Secret>' \ --data '{ "requestedVersion": { "minimum": 1, "maximum": 1 }, "capabilities": [ { "kind": "example", "localId": "example", "versionRange": { "minimum": 1, "maximum": 1 }, "displayName": "example" } ], "declaredName": "example", "declaredVersion": "example", "sdk": { "sdkVersion": "example", "deprecatedApis": [ "example" ], "truncated": true } }'Authenticated by the plugin id and secret headers. Negotiation happens here, once, and is authoritative - the subsequent session.hello over the WebSocket only asserts the outcome, it never re-negotiates.
Authorizations
Section titled “Authorizations”Request Bodyrequired
Section titled “Request Bodyrequired”Mirrors MacroDeck.Plugin.Protocol.Handshake.PluginSessionRequest.
object
Mirrors MacroDeck.Plugin.Protocol.Versioning.ProtocolVersionRange.
object
Mirrors MacroDeck.Plugin.Protocol.Handshake.DeclaredCapability.
object
One of x-macrodeck-capability-kinds.
Mirrors MacroDeck.Plugin.Protocol.Versioning.CapabilityVersionRange.
object
The plugin’s own display name for this session, as declared by the plugin process itself. Optional and additive - names the current session only, never the plugin’s enrollment record.
The plugin’s own version, from its manifest’s “version”. Optional and additive - sent on every session so a self-updating plugin reports its new version without re-enrolling.
Mirrors MacroDeck.Plugin.Protocol.Handshake.PluginSdkUsage. What the plugin was built against, and which deprecated APIs it actually uses. Optional and additive - a plugin that omits it still negotiates normally and is reported as compatibility source “unknown”.
object
The version of MacroDeck.Sdk the plugin was compiled against.
Documentation comment ids of the deprecated APIs the plugin references, captured at build time by the SDK’s usage-manifest generator. Null and empty mean different things and must never be conflated - null is “not reported”, so the host can only infer from sdkVersion; empty is “reported, and none are used”, which the host treats as confirmed.
True when the generator hit its cap, so the list is a floor rather than the complete set.
Examplegenerated
{ "requestedVersion": { "minimum": 1, "maximum": 1 }, "capabilities": [ { "kind": "example", "localId": "example", "versionRange": { "minimum": 1, "maximum": 1 }, "displayName": "example" } ], "declaredName": "example", "declaredVersion": "example", "sdk": { "sdkVersion": "example", "deprecatedApis": [ "example" ], "truncated": true }}Responses
Section titled “Responses”The session was created.
Mirrors MacroDeck.Plugin.Protocol.Handshake.PluginSessionResponse.
object
Mirrors MacroDeck.Plugin.Protocol.Versioning.CapabilityNegotiationResult.
object
Mirrors MacroDeck.Plugin.Protocol.Handshake.PluginProtocolLimitsDescriptor.
object
Mirrors MacroDeck.Plugin.Protocol.Handshake.PluginProtocolTimeoutsDescriptor. Each field is a .NET TimeSpan serialized in its default “c” format (e.g. “00:00:10” for ten seconds).
object
Mirrors MacroDeck.Plugin.Protocol.Compatibility.PluginCompatibilityReport.
object
Mirrors MacroDeck.Plugin.Protocol.Compatibility.CompatibilityFinding.
object
The analyzer id this corresponds to, e.g. MDP5002.
The evidence behind the finding. An “inferred” finding says the plugin may be affected.
A deprecated API’s display name, a capability kind, or “protocol”.
Example
{ "compatibility": { "state": "compatible", "usageSource": "confirmed", "findings": [ { "source": "confirmed", "severity": "info" } ] }}The request body does not match the expected shape.
Mirrors MacroDeck.Plugin.Protocol.Errors.ProtocolError.
object
One of the codes v1 speaks. Drift anchor - see x-macrodeck-error-codes above.
Default English text keyed by code (MacroDeck.Plugin.Protocol.Errors.ProtocolErrorMessages). The UI localises from the code, not this string.
object
Example
{ "code": "PROTOCOL_VERSION_UNSUPPORTED"}Authentication failed. An unknown id and a wrong secret are indistinguishable in the response, the same oracle argument as device login.
Mirrors MacroDeck.Plugin.Protocol.Errors.ProtocolError.
object
One of the codes v1 speaks. Drift anchor - see x-macrodeck-error-codes above.
Default English text keyed by code (MacroDeck.Plugin.Protocol.Errors.ProtocolErrorMessages). The UI localises from the code, not this string.
object
Example
{ "code": "PROTOCOL_VERSION_UNSUPPORTED"}The caller did not arrive on a loopback remote address. Plugin endpoints are served on both the public and private listeners, but only local processes may reach them. On the pairing endpoints, on POST /api/plugins/registration, and on POST /api/plugins/sessions for a plugin holding a development credential, this status also means Developer Mode is switched off in the desktop app - such a refusal carries “reason”: “developer_mode_disabled” in the error’s details, and GET /api/plugins/protocol reports the switch ahead of time.
Mirrors MacroDeck.Plugin.Protocol.Errors.ProtocolError.
object
One of the codes v1 speaks. Drift anchor - see x-macrodeck-error-codes above.
Default English text keyed by code (MacroDeck.Plugin.Protocol.Errors.ProtocolErrorMessages). The UI localises from the code, not this string.
object
Example
{ "code": "PROTOCOL_VERSION_UNSUPPORTED"}The requested protocol version is not supported.
Mirrors MacroDeck.Plugin.Protocol.Errors.ProtocolError.
object
One of the codes v1 speaks. Drift anchor - see x-macrodeck-error-codes above.
Default English text keyed by code (MacroDeck.Plugin.Protocol.Errors.ProtocolErrorMessages). The UI localises from the code, not this string.
object
Example
{ "code": "PROTOCOL_VERSION_UNSUPPORTED"}Too many requests.
Mirrors MacroDeck.Plugin.Protocol.Errors.ProtocolError.
object
One of the codes v1 speaks. Drift anchor - see x-macrodeck-error-codes above.
Default English text keyed by code (MacroDeck.Plugin.Protocol.Errors.ProtocolErrorMessages). The UI localises from the code, not this string.
object
Example
{ "code": "PROTOCOL_VERSION_UNSUPPORTED"}