{
  "openapi": "3.1.0",
  "info": {
    "title": "WPSubscription REST API",
    "version": "1.0.0",
    "summary": "Manage WooCommerce subscriptions created by the WPSubscription plugin.",
    "description": "Manage WooCommerce subscriptions created by the WPSubscription plugin. The API runs on the customer's WordPress site, not on wpsubscription.co — this domain only publishes the spec and documentation.\n\n## Authentication and scopes\n\nEvery request carries a site-scoped API key in the `api_key` field of the JSON request body (OpenAPI cannot express request-body credentials as a `securityScheme`, so it is documented here and enforced by the required `api_key` property of `ActionRequest`). Keys are generated by the site owner in WP Admin → WPSubscription → Settings → API Settings and can be regenerated at any time. A key's permissions are fixed and narrow: it is valid only for the one WordPress site that issued it, and it can only perform the subscription lifecycle actions listed in `x-scoped-permissions` — it grants no access to WordPress users, content, orders, or admin functions. There is no OAuth server and no dynamic client registration; see https://wpsubscription.co/auth.md for the full auth guide.\n\n## Errors\n\nAll errors are structured JSON in the standard WordPress REST error shape (`Error` schema): a machine-readable `code`, a human-readable `message`, and `data.status` mirroring the HTTP status. Agents should branch on `code`, not on message text.\n\n## Rate limits\n\nThe plugin itself does not throttle, but the WordPress host or its WAF/CDN commonly rate-limits `wp-json` traffic. Treat any `429` as authoritative, honor its `Retry-After` header, and self-throttle to roughly 1 request/second per site as a courtesy default.\n\n## Versioning and deprecation\n\nThe API is versioned in the URL path (`/wp-json/wpsubscription/v1/`). Breaking changes ship only under a new version namespace; `v1` request and response shapes stay stable, and only additive changes (new actions, new optional fields) land in `v1`. Deprecations are announced on the changelog (https://wpsubscription.co/changelog/) before removal.",
    "contact": {
      "name": "WPSubscription support",
      "email": "support@wpsubscription.co",
      "url": "https://docs.wpsubscription.co/en/wpsubscription-rest-api-integration"
    }
  },
  "externalDocs": {
    "description": "REST API integration guide",
    "url": "https://docs.wpsubscription.co/en/wpsubscription-rest-api-integration"
  },
  "x-scoped-permissions": {
    "description": "Permissions granted by a WPSubscription API key. Keys are least-privilege by construction: scoped to a single WordPress site and to these subscription lifecycle capabilities only.",
    "scopes": {
      "subscription:cancel": "Cancel an active subscription (action: cancel_subscription)",
      "subscription:pause": "Put a subscription on hold (action: pause_subscription)",
      "subscription:resume": "Reactivate a paused subscription (action: resume_subscription)",
      "subscription:reactivate": "Reactivate a cancelled subscription (action: reactivate_subscription)",
      "subscription:expire": "Mark a subscription as expired (action: expire_subscription)",
      "subscription:change_status": "Set subscription status directly (action: change_status)",
      "subscription:trial_end": "Trigger end-of-trial logic (action: trial_end)",
      "subscription:payment_failed": "Log or react to a failed renewal (action: payment_failed)"
    }
  },
  "servers": [
    {
      "url": "https://{site}/wp-json/wpsubscription/v1",
      "description": "Customer WordPress site",
      "variables": {
        "site": {
          "default": "yoursite.com",
          "description": "The domain of the WordPress site running WPSubscription"
        }
      }
    }
  ],
  "paths": {
    "/action": {
      "post": {
        "operationId": "executeSubscriptionAction",
        "summary": "Execute a subscription action",
        "description": "Single endpoint for all subscription management operations. Pass the operation in the `action` field and authenticate with the site-scoped `api_key` field. All activity is logged to WooCommerce → Status → Logs (source: subscription-pro-api).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ActionRequest"
              },
              "examples": {
                "cancel": {
                  "summary": "Cancel a subscription",
                  "value": {
                    "api_key": "YOUR_API_KEY",
                    "action": "cancel_subscription",
                    "subscription_id": "123",
                    "data": { "reason": "customer requested cancellation" }
                  }
                },
                "pause": {
                  "summary": "Pause a subscription",
                  "value": {
                    "api_key": "YOUR_API_KEY",
                    "action": "pause_subscription",
                    "subscription_id": "123"
                  }
                },
                "change_status": {
                  "summary": "Change subscription status",
                  "value": {
                    "api_key": "YOUR_API_KEY",
                    "action": "change_status",
                    "subscription_id": "123",
                    "data": { "status": "expired" }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Action processed successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActionResponse"
                },
                "example": {
                  "status": "success",
                  "message": "Subscription action \"resume_subscription\" processed successfully",
                  "subscription_id": 168
                }
              }
            }
          },
          "400": {
            "description": "Invalid request — malformed body, unknown action, or invalid status value (error codes: `invalid_status`, `action_failed`)",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" },
                "example": {
                  "code": "invalid_status",
                  "message": "Provided status value is invalid. Allowed values: active, pending, cancelled, expired.",
                  "data": { "status": 400 }
                }
              }
            }
          },
          "401": {
            "description": "Missing API key (error code: `rest_forbidden`)",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" },
                "example": {
                  "code": "rest_forbidden",
                  "message": "Missing API key. Include your site's API key in the api_key field of the request body.",
                  "data": { "status": 401 }
                }
              }
            }
          },
          "403": {
            "description": "Invalid API key (error code: `rest_forbidden`). Regenerate the key in WP Admin → WPSubscription → Settings → API Settings.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" },
                "example": {
                  "code": "rest_forbidden",
                  "message": "Invalid API key.",
                  "data": { "status": 403 }
                }
              }
            }
          },
          "404": {
            "description": "Subscription not found (error code: `not_found`)",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" },
                "example": {
                  "code": "not_found",
                  "message": "Subscription ID not found on this site.",
                  "data": { "status": 404 }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited by the WordPress host, WAF, or CDN (the plugin itself does not throttle). Honor Retry-After and back off.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying, when provided by the host",
                "schema": { "type": "integer" }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          },
          "500": {
            "description": "General action failure (error code: `action_failed`). Check WooCommerce → Status → Logs on the site for details.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" },
                "example": {
                  "code": "action_failed",
                  "message": "The requested action could not be completed.",
                  "data": { "status": 500 }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ActionRequest": {
        "type": "object",
        "required": ["api_key", "action", "subscription_id"],
        "properties": {
          "api_key": {
            "type": "string",
            "description": "Site-scoped API key generated in WP Admin → WPSubscription → Settings → API Settings. This is the credential for every request (there is no OAuth); it is valid only for the issuing site and only for the subscription actions listed in this spec's x-scoped-permissions."
          },
          "action": {
            "type": "string",
            "enum": [
              "cancel_subscription",
              "pause_subscription",
              "resume_subscription",
              "reactivate_subscription",
              "expire_subscription",
              "change_status",
              "trial_end",
              "payment_failed"
            ],
            "description": "The subscription action to perform. cancel_subscription cancels an active subscription; pause_subscription puts it on hold; resume_subscription reactivates a paused one; reactivate_subscription revives a cancelled one; expire_subscription force-expires it; change_status sets an explicit status via data.status; trial_end triggers end-of-trial logic; payment_failed logs a failed renewal attempt."
          },
          "subscription_id": {
            "type": "string",
            "description": "WooCommerce subscription ID to target. Required for every action."
          },
          "data": {
            "type": "object",
            "description": "Optional additional action data (e.g. a cancellation reason)",
            "properties": {
              "status": {
                "type": "string",
                "enum": ["active", "pending", "cancelled", "expired"],
                "description": "Target status for the change_status action"
              },
              "reason": {
                "type": "string",
                "description": "Free-text reason recorded in the subscription log"
              }
            }
          }
        }
      },
      "ActionResponse": {
        "type": "object",
        "required": ["status", "message"],
        "properties": {
          "status": {
            "type": "string",
            "const": "success",
            "description": "Always \"success\" on a 2xx response"
          },
          "message": {
            "type": "string",
            "description": "Human-readable confirmation of the processed action"
          },
          "subscription_id": {
            "type": "integer",
            "description": "ID of the subscription the action was applied to"
          }
        }
      },
      "Error": {
        "type": "object",
        "description": "Standard WordPress REST error object. Branch on `code`; `message` is for humans.",
        "required": ["code", "message"],
        "properties": {
          "code": {
            "type": "string",
            "enum": ["rest_forbidden", "not_found", "invalid_status", "action_failed", "rest_no_route", "rest_invalid_json"],
            "description": "Machine-readable error code. rest_forbidden = invalid or missing API key (regenerate in WP Admin → WPSubscription → Settings); not_found = subscription ID not found on this site; invalid_status = data.status is not one of active/pending/cancelled/expired; action_failed = general action failure (check WooCommerce → Status → Logs); rest_no_route = the plugin's REST API is not enabled on this site or the URL is wrong; rest_invalid_json = request body is not valid JSON."
          },
          "message": {
            "type": "string",
            "description": "Human-readable description of the error"
          },
          "data": {
            "type": "object",
            "properties": {
              "status": {
                "type": "integer",
                "description": "HTTP status code, mirrored in the body"
              }
            }
          }
        }
      }
    }
  }
}
