---
title: "Roll a site back to an earlier version"
method: POST
path: "/sites/{id}/rollback"
tags: ["Sites"]
---

# Roll a site back to an earlier version

`POST /sites/{id}/rollback`

## Request

- Base URL: `https://api.hypamoon.com/api/v1`
- URL: `https://api.hypamoon.com/api/v1/sites/{id}/rollback`
- Auth: one of:
  - HTTP bearer
  - OAuth 2 (authorization code, authorization URL `https://app.hypamoon.com/oauth/authorize`, token URL `https://api.hypamoon.com/oauth/token`, scopes: `sites:write`)

Puts the files of an earlier version back live immediately. The rollback is itself a new version (cause rollback), so the history never loses anything and you can roll forward again. The same checks as for a deploy apply (abuse scan, plan limits, four-eyes approval). If the site already has exactly these files, nothing changes and unchanged is true: safe to retry. Send if_match_version to make sure nobody deployed in between. To restore only a few files, use POST /sites/{id}/restore-files.

## Path parameters

- `id` string, uuid, required

## Request body

- object: Which version to put back live: version_id or number.
  - `version_id` string, uuid: The id of the version to go back to, from list_site_versions.
  - `number` integer: Instead of version_id: the number of the version.
  - `if_match_version` string: Optional. The version of the site you are changing (version from get_site); if the site changed since, you get 409 version_conflict and nothing changes.
  - `message` string: Optional. A short description for the version history, like "Back to the old menu".

## Response `200`

The site as it is now live, with the new version.

- object: The site after the rollback or promote.
  - `site` Site, required: A static site on hypamoon.app.
    - `id` string, uuid, required: The id of the site. Use it to update or delete the site.
    - `slug` string, required: The first part of the address: https://<slug>.hypamoon.app.
    - `name` string, required: Your name for the site.
    - `url` string, required: The public address of the site, live right away.
    - `files` SiteFile[], required: The files of the site, sorted by path, without their content.
      - `path` string, required: The path of the file on the site, like /index.html.
      - `content_type` string, required: The type it is served with, like text/html.
      - `bytes` integer, required: The size of the file in bytes.
      - `updated_at` string, date-time, required: When the file was last written.
    - `created_at` string, date-time, required: When the site was created.
    - `updated_at` string, date-time, required: When the site or its files last changed.
    - `version` string, required: The version that is live now. Changes on every update; every file on the site carries it as its ETag, so you can check that a page shows this version.
    - `password_protected` boolean, required: true when visitors have to enter the site's password first (set with password on POST /sites or PUT /sites/{id}). The password itself is never returned.
    - `test` boolean, required: true for a site of a test project. It is public all the same.
    - `taken_offline` object, nullable, required: null while the site is live. Set when Hypamoon took the site offline because of abuse: visitors get a page that says it is unavailable, the files are kept, and PUT and DELETE return 403 site_offline. To object, the owner replies to the email or writes to hello@hypamoon.com.
      - `at` string, date-time, required: When Hypamoon took the site offline.
      - `reason` string, required: Why, in the words the owner also received by email.
    - `warnings` union[]: Only in the answer of a deploy, and only when there is something to tell: files a deploy without keep_existing removed, and build hints. Warnings never block a deploy.
      - union
        - object
          - `code` 'files_removed', required: A deploy without keep_existing removed files that were on the site.
          - `message` string, required: What happened and what to do if it was not intended.
          - `paths` string[], required: The paths that are gone.
        - object
          - `code` 'build_hint', required: Something on the site looks like it works but does not: a form that saves nowhere, localStorage used as a database, a password checked in JavaScript, a button to # or javascript:, a cart without a checkout, test wording on the live project, or a map from a service that needs a key the site does not have. Advice only: the deploy succeeded.
          - `hint` string, required: Which hint, like form_no_target, local_storage_db or cart_without_checkout.
          - `message` string, required: What does not work, in plain words.
          - `paths` string[], required: The files the hint is about.
          - `next_step` string, required: What to do next, with the tool to use.
  - `version` object, nullable, required: One version of a site: a snapshot of its files.
    - `object` 'site_version', required
    - `id` string, uuid, required: The id of the version: use it for get_site_diff, rollback_site, promote_site_version and label_site_version.
    - `number` integer, required: The number of the version within the site: 1, 2, 3 and so on.
    - `site_id` string, uuid, required
    - `created_at` string, required: When this version was made (ISO 8601).
    - `cause` 'baseline' | 'deploy' | 'partial_deploy' | 'import' | 'approved_deploy' | 'rollback' | 'promote' | 'preview' | 'file_restore', required: What made it: a deploy, a partial deploy (keep_existing), an import, a deploy after four-eyes approval, a rollback, a promoted preview, a preview, a few files restored from an older version (file_restore), or baseline (how the site was when its history started).
    - `message` string, nullable, required: The message sent with the deploy, if any.
    - `author` object, required: Who made it, and through which client.
      - `user_id` string, nullable, required
      - `via` 'portal' | 'api_key' | 'connected_app' | 'system', required
      - `client` 'chatgpt' | 'claude' | 'api' | 'portal' | 'wizard' | 'other', required
      - `client_name` string, nullable, required
    - `changes` object, required: The paths that changed compared to the version before.
      - `added` string[], required
      - `modified` string[], required
      - `removed` string[], required
      - `counts` object, required
        - `added` integer, required
        - `modified` integer, required
        - `removed` integer, required
      - `truncated` boolean, required: true: the lists show the first 50 paths per kind; get_site_diff has all.
    - `files` integer, required
    - `bytes` integer, required
    - `current` boolean, required: true for the version that is live now.
    - `preview` boolean, required: true for a preview that never went live.
    - `preview_url` string, nullable, required: The secret address of a preview (not indexed). Share it only with people who should see it.
    - `label` string, nullable, required
    - `labeled_at` string, nullable, required
    - `restored_from` string, uuid, nullable, required: For a rollback or promote: the version it came from.
    - `expires_at` string, nullable, required: When the retention of the plan removes it; null for the current version, labeled versions and checkpoints.
    - `auto_label` 'before big change' | 'stable' | 'held by guardrail' | 'null', nullable, required: A marker Hypamoon sets itself, apart from label: "before big change" is the version that was live when a deploy hit the guardrail (kept like a labeled version), "stable" a version that stayed live for at least 24 hours and was not rolled back (both good versions to go back to), and "held by guardrail" a preview the guardrail made instead of putting a deploy live.
  - `unchanged` boolean, required: true: the site already had exactly these files, so nothing changed (safe to retry).

## Other responses

- `202`: Four-eyes approval is on: the rollback waits for another owner or builder. Nothing has changed yet.
- `400`: Bad Request: invalid_json.
- `401`: Unauthorized: unauthorized, missing_api_key, invalid_api_key, api_key_revoked, project_deleted.
- `402`: Payment Required: plan_limit_reached.
- `403`: Forbidden: project_not_enabled, key_mode_mismatch, missing_scope, verification_required, site_offline.
- `404`: Not Found: not_found.
- `409`: Conflict: conflict, version_conflict.
- `422`: Unprocessable Content: validation_failed, site_blocked.
- `429`: Too Many Requests: rate_limited, deploy_limit_reached.
- `500`: Internal Server Error: internal_error.
- `503`: Service Unavailable: service_unavailable.

---

[API](https://skmtc.dev/hypamoon/apis/hypamoon-api.md) · [All operations](https://skmtc.dev/hypamoon/apis/hypamoon-api/llms.txt) · [OpenAPI document](https://skmtc.dev/hypamoon/apis/hypamoon-api/revisions/9f0b90004c06?raw)
