> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sandywp.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Rotate the Demo Launches webhook secret

> Replaces the workspace webhook's HMAC secret and returns the new plaintext value once.



## OpenAPI

````yaml /openapi.yaml post /api/account/webhooks/demo-launches/rotate
openapi: 3.1.0
info:
  title: SandyWP API
  version: 0.1.0
  summary: Complete supported customer API for SandyWP automation.
  description: >
    This is the complete supported customer API for automating SandyWP
    sandboxes, reusable

    Templates and Blueprints, Imports, Workspaces, account credentials,
    demo-launch webhooks, and

    OAuth connection setup.

    It is the stable HTTP contract for developer integrations; browser,
    provider, and operations

    routes on the same host are deliberately not part of this document.


    **Exclusions ledger.** The specification excludes guest/launcher creation
    (`POST /api/sites`),

    account profile/avatar/password/support and GitHub UI handlers, billing
    checkout/portal/sync,

    public launch routes, plugin/theme search proxies, storage, activity
    telemetry, newsletter,

    health, metrics, impersonation, Slack/GitHub callbacks, Git/Polar webhooks,
    all `/api/admin/**`,

    and all `/api/internal/**` worker or SSH-control routes. Those endpoints are
    browser backends,

    provider callbacks, or operational control-plane interfaces rather than
    supported developer APIs.


    ## Conventions


    - Requests and responses are JSON. Send `Content-Type: application/json` on
    writes (the file
      upload and plugin-ZIP-upload endpoints instead use `multipart/form-data`, as noted on those
      operations).
    - Sandboxes and Templates are addressed by their opaque `id` in the API (for
    example
      `site_abc123`, `tpl_xyz789`).
    - Errors use a consistent envelope — see the `Error` schema. Some actions
    require a paid plan
      and fail with HTTP `402` and a specific error code (for example
      `template_sharing_requires_paid_plan`); each is called out on the operation that returns it.
    - **Async by default.** Provisioning and other slow sandbox mutations happen
    on a worker, not
      inline in the HTTP request. An endpoint that starts one either returns a `jobId` to poll (see
      the `Job` / `JobSummary` schemas and each operation's description), returns the resource in a
      non-terminal state (a site `"creating"`, a Template `"building"`) to re-fetch until it settles,
      or both.
    - A personal bearer token can call the authenticated operations below. A
    scoped OAuth token is
      accepted only by `GET /api/account/me` and the Imports family; it needs `import:read` or
      `import:write` for the matching import operation. Other REST operations treat scoped tokens
      as unauthenticated.
  contact:
    name: SandyWP
    url: https://app.sandywp.com/docs/api
servers:
  - url: https://app.sandywp.com
security:
  - bearerAuth: []
tags:
  - name: Templates
    description: >-
      A Template is a snapshot of a finished sandbox — WordPress/PHP versions,
      plugins, themes, content, and database — ready to restore in seconds.
      Templates come from saving a ready sandbox, and can optionally be
      published as a public "launch this demo" link.
  - name: Sites
    description: >-
      A Site is a disposable WordPress sandbox: its lifecycle
      (create/restore/reset/delete) and the per-sandbox tools built on top of it
      (PHP runtime & ini config, WordPress debug settings, database access,
      outgoing-email capture, plugin deploys, the file manager, Git deployment,
      and SSH access).
  - name: Blueprints
    description: >-
      Reviewable WordPress build recipes that can be validated, saved, run on a
      sandbox, or baked into a Template.
  - name: Imports
    description: >-
      Archive-upload workflows for cloning a live WordPress site or pushing a
      local installation. Scoped OAuth tokens may use only this family, with
      `import:read` for reads and `import:write` for mutations.
  - name: Workspaces
    description: Workspace selection plus member and custom-role administration.
  - name: Account
    description: >-
      Identity, usage, personal API tokens, demo-launch webhooks, and account
      SSH public keys.
  - name: OAuth
    description: >-
      Public-client registration and PKCE authorization-code token exchange for
      supported connectors.
paths:
  /api/account/webhooks/demo-launches/rotate:
    post:
      tags:
        - Account
      summary: Rotate the Demo Launches webhook secret
      description: >-
        Replaces the workspace webhook's HMAC secret and returns the new
        plaintext value once.
      operationId: rotateDemoLaunchWebhookSecret
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeaderParam'
      responses:
        '200':
          description: The updated webhook and one-time plaintext secret.
          content:
            application/json:
              schema:
                type: object
                required:
                  - webhook
                  - secret
                properties:
                  webhook:
                    $ref: '#/components/schemas/DemoLaunchWebhook'
                  secret:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: >-
            webhook_not_configured — configure the webhook before rotating its
            secret.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  parameters:
    WorkspaceHeaderParam:
      name: X-SandyWP-Workspace
      in: header
      required: false
      description: >-
        Selects which of the caller's workspaces to act in, for accounts
        belonging to more than one (legacy alias: `X-SandyWP-Organization`).
        Defaults to the caller's own personal workspace when omitted. Every id
        in this API (sandboxes, Templates, repositories) is scoped to a single
        workspace, so this header changes which set of resources is visible.
      schema:
        type: string
  schemas:
    DemoLaunchWebhook:
      type: object
      description: >-
        Workspace-scoped Demo Launches webhook configuration. Secret material is
        never included.
      required:
        - id
        - url
        - enabled
        - secretConfigured
        - createdAt
        - updatedAt
        - lastDelivery
      properties:
        id:
          type: string
        url:
          type: string
          format: uri
        enabled:
          type: boolean
        secretConfigured:
          type: boolean
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        lastDelivery:
          type:
            - object
            - 'null'
          required:
            - status
            - attempts
            - lastError
            - responseStatus
            - deliveredAt
            - createdAt
          properties:
            status:
              type: string
              enum:
                - pending
                - processing
                - succeeded
                - failed
                - exhausted
            attempts:
              type: integer
              minimum: 0
            lastError:
              type:
                - string
                - 'null'
            responseStatus:
              type:
                - integer
                - 'null'
            deliveredAt:
              type:
                - string
                - 'null'
              format: date-time
            createdAt:
              type: string
              format: date-time
    Error:
      type: object
      description: >-
        The standard error envelope returned by every endpoint on a non-2xx
        response.
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: >-
                A stable, machine-readable error code (e.g. `invalid_request`,
                `site_not_found`, `plan_limit_reached`). See each operation for
                the codes it can return.
              example: invalid_request
            message:
              type: string
              description: A human-readable message. Safe to display to an end user.
            details:
              type: object
              description: >-
                Optional structured context (e.g. `{"plan": "free", "limit": 2}`
                for a plan-limit error). Omitted entirely on the generic
                internal-error fallback; `{}` when an error has no extra
                context.
              additionalProperties: true
  responses:
    Unauthorized:
      description: >-
        No valid bearer token was presented, or a scoped OAuth token was used
        outside its allowed Imports and account-identity routes.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: auth_required
              message: A logged-in user is required.
              details: {}
    Forbidden:
      description: >-
        The caller's current workspace Role does not grant the capability this
        action requires.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: capability_required
              message: Your role does not allow this.
              details:
                capability: internals
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        Personal API token, sent as `Authorization: Bearer <SANDYWP_API_KEY>`.
        Obtain one from the dashboard account menu (API keys), `sandywp auth
        login`, or `POST /api/account/tokens`. A missing or invalid token
        returns `401 auth_required`. Scoped OAuth tokens are limited to the
        Imports family and `GET /api/account/me`; see the top-level conventions.

````