> ## 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.

# Upload a Blueprint ZIP bundle

> Uploads one ZIP bundle containing `blueprint.json`. Set `preview=1` to inspect compatibility and adaptations without saving; otherwise incompatible or unaccepted review-required changes are rejected.



## OpenAPI

````yaml /openapi.yaml post /api/app/blueprints/upload
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, 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, and account SSH public keys.
  - name: OAuth
    description: >-
      Public-client registration and PKCE authorization-code token exchange for
      supported connectors.
paths:
  /api/app/blueprints/upload:
    post:
      tags:
        - Blueprints
      summary: Upload a Blueprint ZIP bundle
      description: >-
        Uploads one ZIP bundle containing `blueprint.json`. Set `preview=1` to
        inspect compatibility and adaptations without saving; otherwise
        incompatible or unaccepted review-required changes are rejected.
      operationId: uploadBlueprintBundle
      parameters:
        - name: preview
          in: query
          required: false
          description: Set to `1` to inspect the bundle without saving it.
          schema:
            type: string
            enum:
              - '1'
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                bundle:
                  type: string
                  format: binary
                  description: ZIP bundle to upload. Provide this or `bundleUrl`.
                bundleUrl:
                  type: string
                  format: uri
                  description: URL of a ZIP bundle to fetch. Provide this or `bundle`.
                name:
                  type: string
                description:
                  type: string
                adaptationsAccepted:
                  type: string
                  enum:
                    - 'true'
                  description: >-
                    Required when the compatibility review reports changes that
                    need acceptance.
      responses:
        '200':
          description: A saved Blueprint, or a bundle preview when `preview=1`.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/BlueprintResponse'
                  - $ref: '#/components/schemas/BlueprintValidationResult'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '409':
          description: >-
            `blueprint_review_required` — review and accept the reported
            adaptations before saving.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '413':
          description: '`blueprint_bundle_too_large` — ZIP bundles are limited to 50 MiB.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '503':
          description: >-
            `blueprint_bundle_storage_unavailable` — private object storage is
            unavailable.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  schemas:
    BlueprintResponse:
      type: object
      required:
        - blueprint
      properties:
        blueprint:
          $ref: '#/components/schemas/Blueprint'
    BlueprintValidationResult:
      type: object
      description: >-
        Validation output. `source` and `changes` are present only for
        adaptation responses or bundle previews.
      required:
        - valid
        - schemaVersion
        - stepCount
        - hoisted
        - findings
      properties:
        valid:
          type: boolean
          description: >-
            False when one or more compatibility findings have `severity:
            error`.
        schemaVersion:
          type: integer
          enum:
            - 1
            - 2
        stepCount:
          type: integer
          minimum: 0
        hoisted:
          $ref: '#/components/schemas/BlueprintHoistedEnvironment'
        findings:
          type: array
          items:
            $ref: '#/components/schemas/BlueprintCompatibilityFinding'
        source:
          $ref: '#/components/schemas/BlueprintDocument'
        changes:
          type: array
          items:
            $ref: '#/components/schemas/BlueprintAdaptationChange'
        manifestDirectory:
          type: string
          description: Present for a ZIP bundle preview.
    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
    Blueprint:
      type: object
      description: A saved Blueprint and its current compatibility report.
      required:
        - id
        - userId
        - orgId
        - createdByUserId
        - name
        - slug
        - description
        - sourceJson
        - schemaVersion
        - revision
        - compatReport
        - hoistedPhpVersion
        - hoistedWordpressVersion
        - hoistedMultisite
        - bundleSizeBytes
        - bundleManifestDirectory
        - createdAt
        - updatedAt
      properties:
        id:
          type: string
          example: bp_abc123
        userId:
          type: string
        orgId:
          type: string
        createdByUserId:
          type:
            - string
            - 'null'
        name:
          type: string
        slug:
          type: string
        description:
          type:
            - string
            - 'null'
        sourceJson:
          $ref: '#/components/schemas/BlueprintDocument'
        schemaVersion:
          type: integer
          enum:
            - 1
            - 2
        revision:
          type: integer
          minimum: 1
        compatReport:
          type: array
          items:
            $ref: '#/components/schemas/BlueprintCompatibilityFinding'
        hoistedPhpVersion:
          type:
            - string
            - 'null'
        hoistedWordpressVersion:
          type:
            - string
            - 'null'
        hoistedMultisite:
          type: boolean
        bundleSizeBytes:
          type:
            - integer
            - 'null'
          description: >-
            Size of an attached ZIP bundle, if this Blueprint was saved from
            one.
        bundleManifestDirectory:
          type:
            - string
            - 'null'
          description: >-
            Root directory containing `blueprint.json` in an attached ZIP
            bundle.
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    BlueprintHoistedEnvironment:
      type: object
      required:
        - phpVersion
        - requestedPhpVersion
        - wordpressVersion
        - requestedWordpressVersion
        - multisite
      properties:
        phpVersion:
          type:
            - string
            - 'null'
          description: Supported PHP version inferred from the source, if any.
        requestedPhpVersion:
          type:
            - string
            - 'null'
        wordpressVersion:
          type:
            - string
            - 'null'
          description: Supported WordPress version inferred from the source, if any.
        requestedWordpressVersion:
          type:
            - string
            - 'null'
        multisite:
          type: boolean
    BlueprintCompatibilityFinding:
      type: object
      required:
        - severity
        - path
        - code
        - message
      properties:
        severity:
          type: string
          enum:
            - error
            - warning
            - info
        path:
          type: string
          description: JSON-path-like location in the source document.
        code:
          type: string
        message:
          type: string
    BlueprintDocument:
      type: object
      description: >-
        A WordPress Playground Blueprint document. SandyWP accepts schema
        version 1 or 2 and validates its supported steps and resources before
        saving or running it.
      additionalProperties: true
      example:
        preferredVersions:
          php: '8.3'
          wp: latest
        steps:
          - step: setSiteOptions
            options:
              blogname: My Sandbox
    BlueprintAdaptationChange:
      type: object
      required:
        - path
        - code
        - message
      properties:
        path:
          type: string
        code:
          type: string
          enum:
            - field_removed
            - step_removed
            - step_transformed
            - resource_transformed
        message:
          type: string
        subject:
          type: string
          description: Optional affected step name.
  responses:
    BadRequest:
      description: >-
        The request body, parameters, or resource state is invalid for this
        operation.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    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: {}
  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.

````