{"openapi":"3.1.0","info":{"title":"plsk.org API","version":"1.0.0","description":"A subscription key gives access to exactly one subscription. Everything under /api/plesk/v2 (the same as /api/v2) is the Plesk REST API of that subscription, forwarded unchanged; the REST APIs of Plesk extensions are under /api/modules/<extension>/<version>/ (today: wp-toolkit, for example /api/modules/wp-toolkit/v1/installations). For the Plesk API: paths, queries, bodies, status codes and error messages are Plesk's, and what you may do is what a Plesk customer of the laboratory plan may do (Plesk refuses the rest). Plesk's own specification is public at GET /plesk-openapi.json (no key needed; its `servers` entry already names this server); the MCP tool plesk_api_reference lists the operations. The gateway adds only its own checks: the key must be valid and unexpired, the request must stay under /api/plesk/v2, /api/v2 or an offered extension under /api/modules (otherwise 400 bad_path or 403 blocked_path), /auth (creating Plesk keys) is not available (403 blocked_path), and size, time and rate limits apply. A key expires no later than its subscription and can be revoked at any time."},"externalDocs":{"description":"Documentation","url":"https://docs.plsk.org/api"},"servers":[{"url":"https://api.plsk.org"}],"security":[{"ApiKey":[]},{"Bearer":[]}],"paths":{"/plesk-openapi.json":{"get":{"summary":"Plesk's own OpenAPI specification: every /api/v2 operation is described there. Public, no key needed.","security":[],"responses":{"200":{"description":"Plesk's OpenAPI document with the servers entry pointed at this gateway and the blocked /auth operations removed. Cached for an hour."},"503":{"description":"The specification could not be obtained right now. Try again later."}}}},"/v1/subscriptions":{"get":{"operationId":"listSubscriptions","summary":"List your subscriptions","x-required-scope":"read","security":[{"AccountKey":[]},{"AccountBearer":[]}],"responses":{"200":{"description":"Your subscriptions.","content":{"application/json":{"schema":{"type":"object","properties":{"subscriptions":{"type":"array","items":{"$ref":"#/components/schemas/Subscription"}}},"required":["subscriptions"]}}}},"401":{"description":"The key is missing, malformed, unknown, revoked or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown, or not yours.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key, or (feedback) 20 reports in the last 24 hours. See Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createSubscription","summary":"Create a subscription (idempotent)","x-required-scope":"manage","security":[{"AccountKey":[]},{"AccountBearer":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":true,"description":"1 to 64 characters from A-Z a-z 0-9 _ -. The same key with the same body returns the same subscription; a different body is a conflict.","schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSubscriptionRequest"}}}},"responses":{"200":{"description":"The same request was made before; the existing subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Subscription"}}}},"201":{"description":"Created; provisioning starts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Subscription"}}}},"400":{"description":"Invalid input; the error names the field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The key is missing, malformed, unknown, revoked or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key scope is not enough, or the request needs a step done in the browser.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown, or not yours.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict with the current state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"The body is larger than 16 KiB (48 KiB for feedback).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key, or (feedback) 20 reports in the last 24 hours. See Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/subscriptions/{id}":{"get":{"operationId":"getSubscription","summary":"Read one subscription","x-required-scope":"read","security":[{"AccountKey":[]},{"AccountBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Opaque subscription id.","schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"}}],"responses":{"200":{"description":"The subscription.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Subscription"}}}},"400":{"description":"Invalid input; the error names the field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The key is missing, malformed, unknown, revoked or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown, or not yours.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key, or (feedback) 20 reports in the last 24 hours. See Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"deleteSubscription","summary":"Delete a ready subscription or remove a failed one","x-required-scope":"manage","security":[{"AccountKey":[]},{"AccountBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Opaque subscription id.","schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"}}],"responses":{"202":{"description":"Deletion accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Subscription"}}}},"400":{"description":"Invalid input; the error names the field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The key is missing, malformed, unknown, revoked or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key scope is not enough, or the request needs a step done in the browser.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown, or not yours.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict with the current state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key, or (feedback) 20 reports in the last 24 hours. See Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/subscriptions/{id}/retry":{"post":{"operationId":"retrySubscription","summary":"Retry a failed subscription","x-required-scope":"manage","security":[{"AccountKey":[]},{"AccountBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Opaque subscription id.","schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"}}],"responses":{"202":{"description":"Retry accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Subscription"}}}},"400":{"description":"Invalid input; the error names the field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The key is missing, malformed, unknown, revoked or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key scope is not enough, or the request needs a step done in the browser.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown, or not yours.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict with the current state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key, or (feedback) 20 reports in the last 24 hours. See Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/subscriptions/{id}/keys":{"get":{"operationId":"listSubscriptionKeys","summary":"List the keys of a subscription (no secrets)","x-required-scope":"read","security":[{"AccountKey":[]},{"AccountBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Opaque subscription id.","schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"}}],"responses":{"200":{"description":"Keys of the subscription, without secrets.","content":{"application/json":{"schema":{"type":"object","properties":{"keys":{"type":"array","items":{"$ref":"#/components/schemas/ApiKey"}}},"required":["keys"]}}}},"400":{"description":"Invalid input; the error names the field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The key is missing, malformed, unknown, revoked or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown, or not yours.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key, or (feedback) 20 reports in the last 24 hours. See Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createSubscriptionKey","summary":"Issue the subscription key for the Plesk API (secret shown once)","x-required-scope":"manage","security":[{"AccountKey":[]},{"AccountBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Opaque subscription id.","schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKeyRequest"}}}},"responses":{"201":{"description":"Issued. The token is shown once.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssuedApiKey"}}}},"400":{"description":"Invalid input; the error names the field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The key is missing, malformed, unknown, revoked or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key scope is not enough, or the request needs a step done in the browser.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown, or not yours.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflict with the current state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"The body is larger than 16 KiB (48 KiB for feedback).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key, or (feedback) 20 reports in the last 24 hours. See Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/subscriptions/{id}/keys/{keyId}":{"delete":{"operationId":"revokeSubscriptionKey","summary":"Revoke a subscription key","x-required-scope":"manage","security":[{"AccountKey":[]},{"AccountBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Opaque subscription id.","schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"}},{"name":"keyId","in":"path","required":true,"description":"Opaque key id.","schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"}}],"responses":{"204":{"description":"Revoked."},"400":{"description":"Invalid input; the error names the field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The key is missing, malformed, unknown, revoked or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key scope is not enough, or the request needs a step done in the browser.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown, or not yours.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key, or (feedback) 20 reports in the last 24 hours. See Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/feedback":{"post":{"operationId":"submitFeedback","summary":"Send a bug report or feedback (any key scope)","description":"Send a bug report (kind \"bug\") or feedback (kind \"feedback\"). Plain text only; do not include credentials, personal data or private content (keys are removed). For a bug, write:\nWhat happened: <one or two sentences>\nSteps to reproduce:\n1. <exact call or action, with the path and the input>\n2. <next step>\nExpected result: <what you expected>\nActual result: <what happened, with the status and the error text>\nEnvironment: <client or agent, time (UTC), request id if you have one>\nFor feedback, write:\nProblem: <what is hard, slow, unclear or missing>\nScenarios: <situations in which it appears, one per line>\n- <who is doing what, and where it goes wrong>\nProposal (optional): <what would help>\nTitle: 5 to 120 characters, one line. Message: 20 to 8000 characters. At most 20 reports per account per day; sending the same text again returns the same id. Missing sections do not reject the report; the answer lists them in hints.","x-required-scope":"read","security":[{"AccountKey":[]},{"AccountBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackRequest"}}}},"responses":{"200":{"description":"The same report was already stored; its id is returned.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackReceipt"}}}},"201":{"description":"Stored.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackReceipt"}}}},"400":{"description":"Invalid input; the error names the field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The key is missing, malformed, unknown, revoked or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown, or not yours.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"The body is larger than 16 KiB (48 KiB for feedback).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests for this key, or (feedback) 20 reports in the last 24 hours. See Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"ApiKey":{"type":"apiKey","in":"header","name":"X-API-Key"},"Bearer":{"type":"http","scheme":"bearer"},"AccountKey":{"type":"apiKey","in":"header","name":"X-API-Key","description":"An account key. Tokens start with plsa_. Scope read allows reading; scope manage also allows changes."},"AccountBearer":{"type":"http","scheme":"bearer","description":"The same account key as Authorization: Bearer plsa_..."}},"responses":{"Unauthorized":{"description":"The key is missing, malformed, unknown, revoked or expired.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}},"required":["error"]}}}},"Forbidden":{"description":"The key is valid but the subscription or account is not available, or the gateway blocks the call (code blocked_path, for /api/v2/auth). A 403 with a Plesk body (`{\"code\":0,\"message\":...}`) comes from Plesk itself. The code bad_path (status 400) means the target is not acceptable (outside /api/v2, dot segments, unsafe characters).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}},"required":["error"]}}}},"RateLimited":{"description":"Too many requests for this key. See the Retry-After header.","headers":{"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}},"required":["error"]}}}}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"field":{"type":"string","description":"The offending field, for validation errors."}},"required":["code","message"]}},"required":["error"]},"Subscription":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"hostname":{"type":"string"},"status":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"readyAt":{"type":["string","null"],"format":"date-time"},"expiresAt":{"type":["string","null"],"format":"date-time"},"access":{"type":"string","enum":["allowed","provisioning","expired","unavailable"]},"failure":{"type":["string","null"]},"hasCredential":{"type":"boolean","description":"Whether a subscription key can be issued. The credential itself is never returned."}},"required":["id","name","hostname","status","createdAt","readyAt","expiresAt","access","failure","hasCredential"],"additionalProperties":false},"ApiKey":{"type":"object","properties":{"id":{"type":"string"},"subscriptionId":{"type":"string"},"selector":{"type":"string","description":"Non-secret identifier embedded in the token."},"createdAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"},"revokedAt":{"type":["string","null"],"format":"date-time"},"lastUsedAt":{"type":["string","null"],"format":"date-time","description":"Time of the last successful use, or null if never used."},"status":{"type":"string","enum":["active","revoked","expired"]}},"required":["id","subscriptionId","selector","createdAt","expiresAt","revokedAt","lastUsedAt","status"],"additionalProperties":false},"IssuedApiKey":{"type":"object","properties":{"token":{"type":"string","description":"Shown once, in this response only."},"key":{"$ref":"#/components/schemas/ApiKey"}},"required":["token","key"],"additionalProperties":false},"CreateSubscriptionRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":40,"description":"No control characters."}},"required":["name"],"additionalProperties":false},"FeedbackRequest":{"type":"object","properties":{"kind":{"type":"string","enum":["bug","feedback"],"description":"bug for something that does not work as documented; feedback for a missing, slow or unclear thing."},"title":{"type":"string","minLength":5,"maxLength":120,"description":"One line."},"message":{"type":"string","minLength":20,"maxLength":8000,"description":"Plain text following the template in the operation description. Never rendered as HTML or Markdown."}},"required":["kind","title","message"],"additionalProperties":false},"FeedbackReceipt":{"type":"object","properties":{"id":{"type":"string","description":"Stable feedback id."},"duplicate":{"type":"boolean","description":"True when the same report was already stored in the last 24 hours; no second record was created."},"hints":{"type":"array","items":{"type":"string","enum":["missing_steps_to_reproduce","missing_expected_and_actual","missing_problem","missing_scenarios"]},"description":"Template sections that appear to be missing. The report was accepted anyway."},"redacted":{"type":"boolean","description":"True when something that looked like a credential was replaced with [redacted]."}},"required":["id","duplicate","hints","redacted"],"additionalProperties":false},"CreateKeyRequest":{"type":"object","properties":{"lifetime":{"type":"string","enum":["1d","7d","subscription"]}},"required":["lifetime"],"additionalProperties":false}}}}