---
title: "Compute a release-to-release diff"
method: GET
path: "/apply/v1/releases/diff"
tags: ["Apply"]
---

# Compute a release-to-release diff

`GET /apply/v1/releases/diff`

## Request

- Base URL: `https://api.run402.com`
- URL: `https://api.run402.com/apply/v1/releases/diff`
- Auth: API key in header `apikey`

Diffs two materialized releases. `from` accepts a release id, the literal `"empty"` (synthetic baseline), or `"active"` (current live). `to` accepts a release id or `"active"`. `from === to` is rejected as 400 DIFF_SAME_RELEASE; `to="empty"` is rejected as 400 INVALID_DIFF_TARGET. Cross-project access returns 404 RESOURCE_NOT_FOUND (NEVER 400 DIFF_PROJECT_MISMATCH — that code does not exist). Migrations in this response are MONOTONIC (`applied_between_releases: string[]`), distinct from the plan response's `{new, noop}` shape.

## Query parameters

- `from` string, required
- `to` string, required
- `limit` integer

## Response `200`

Release-to-release diff

- ReleaseToReleaseDiff: Release-to-release diff envelope (capability agent-deploy-observability). Migrations are MONOTONIC (`applied_between_releases`) — distinct from the plan response's `{new, noop}` shape.
  - `kind` 'release_diff', required
  - `schema_version` 'agent-deploy-observability.v1', required
  - `from_release_id` string, nullable, required
  - `to_release_id` string, nullable, required
  - `is_noop` boolean, required
  - `summary` string, required: Pre-rendered counts in prose. NO user identifiers (those go in warnings.affected[]). NO monetary, storage, tier, or pricing language.
  - `warnings` WarningEntry[], required
    - `code` string, required: Machine-readable warning discriminator. Known values include `MISSING_REQUIRED_SECRET`, `DESTRUCTIVE_FUNCTION_REMOVAL`, `DESTRUCTIVE_SUBDOMAIN_REMOVAL`, `DESTRUCTIVE_SITE_BULK_REMOVAL`, `DESTRUCTIVE_SECRET_REMOVAL`, `MIGRATION_NON_TRANSACTIONAL`, migration heuristic warnings, `ZERO_*`, `SITE_ENTRYPOINT_REMOVED`, `DIFF_TRUNCATED`, `FIRST_DEPLOY`, Web Route warnings such as `PUBLIC_ROUTED_FUNCTION` and `ROUTE_TABLE_NEAR_LIMIT`, and exact static URL alias warnings such as `STATIC_ALIAS_SHADOWS_STATIC_PATH`, `STATIC_ALIAS_RELATIVE_ASSET_RISK`, `STATIC_ALIAS_DUPLICATE_CANONICAL_URL`, `STATIC_ALIAS_EXTENSIONLESS_NON_HTML`, and `STATIC_ALIAS_TABLE_NEAR_LIMIT`. New codes may be added without a wire-version bump; agents should default to surfacing unknown codes verbatim.
    - `severity` 'info' | 'warn' | 'high', required: Suggested UI prominence. Info = informational; warn = recommend review; high = strongly recommend action before commit.
    - `requires_confirmation` boolean, required: When true, agents SHOULD surface to the user and require explicit confirmation before commit. Plan still returns 201 either way.
    - `message` string, required: Human-readable explanation. Safe to show verbatim in UIs.
    - `affected` string[]: Optional list of affected entity identifiers (e.g., secret keys, file paths). Code-specific shape; consult the discriminator before parsing.
    - `details` object: Optional code-specific structured payload. For `MISSING_REQUIRED_SECRET`: `{ missing_keys: string[] }`. For `STATIC_ALIAS_TABLE_NEAR_LIMIT`: `{ static_aliases, limit, limit_scope: "combined_routes_temporary" }`.
    - `confidence` 'heuristic': Optional confidence in the warning. Reserved for heuristic warnings; deterministic warnings like `MISSING_REQUIRED_SECRET` omit this.
  - `migrations` object, required
    - `applied_between_releases` string[], required
  - `site` object, required
    - `added` object[], required
      - `path` string
      - `sha256` string
      - `content_type` string
    - `removed` string[], required
    - `changed` object[], required
      - `path` string
      - `sha256_old` string
      - `sha256_new` string
      - `content_type_old` string
      - `content_type_new` string
  - `functions` object, required
    - `added` string[], required
    - `removed` string[], required
    - `changed` object[], required
      - `name` string
      - `fields_changed` string[]
  - `secrets` object, required: NO `changed` slot (capability secrets-isolation invariant — no value-derived information is observable).
    - `added` string[], required
    - `removed` string[], required
  - `subdomains` object, required: NO `changed` slot (subdomain identity == name).
    - `added` string[], required
    - `removed` string[], required
  - `routes` RoutesDiff, required
    - `added` RouteEntry[], required
      - `pattern` string, required
      - `kind` 'exact' | 'prefix', required
      - `prefix` string, nullable, required
      - `methods` string[], nullable, required: Null means all supported methods.
      - `target` union, required: Web Route target. Function targets invoke a same-release Node 22 function. Static targets are exact static URL aliases that serve a materialized same-release static site file without redirecting or rewriting the browser URL.
        - object
          - `type` 'function', required
          - `name` string, required: Name of a materialized function in the same release.
        - object
          - `type` 'static', required
          - `file` string, required: Relative materialized static-site file path in the same release. No leading slash, query, fragment, backslash, empty segment, . segment, .. segment, or directory shorthand.
      - `pricing` RoutePricingSpec: Fixed-price tenant x402 policy for a public function web route. Supported only when target.type is function; static aliases cannot be priced. A challenge advertises maxTimeoutSeconds=300. After proof verification, Idempotency-Key (1-255 visible ASCII bytes) is scoped by verified payer, project, route pattern, and method, then bound to the normalized request contract. Same-payer/same-request/same-key retry is the only status/recovery operation. Successful routed responses expose platform-owned X-Run402-Payment-* headers and the x402 v2 PAYMENT-RESPONSE settlement header (base64 JSON SettleResponse: success, transaction, network, payer), on a first delivery and on a deduplicated replay alike; pending and conflict responses use a canonical error envelope. Tenant execution is at-least-once, so handlers should deduplicate durable effects by paymentId.
        - `mode` 'always', required: Every matching request must settle x402 before the handler runs.
        - `amount_usd_micros` integer, required: USD micro-units charged per matching request. 250000 means $0.25.
        - `amount_msat` integer: Pins the Lightning price in millisatoshis for the route's lightning / lightning-testnet entries. Valid only when networks names a Lightning value. Absent, each challenge quotes amount_usd_micros into whole satoshis through the platform Lightning quote; amount_usd_micros stays the ledger amount either way.
        - `pay_to` 'org_default_payout', required: Resolve the owning organization default payout wallet at activation and serve time.
        - `networks` RoutePricingNetwork[]: Optional supported network set. Omitted means mainnet only. A Lightning value requires the organization's Lightning receiver on that network (LIGHTNING_RECEIVER_REQUIRED at activation); a Lightning-only route needs no EVM payout wallet. receipt cannot be combined with a Lightning value.
        - `receipt` 'on_fulfillment': Receipt authoring intent from the public ReleaseSpec contract. Run402 Cloud currently rejects this field at routes.replace.<index>.pricing.receipt before mutation until an interoperable delegated-signer authorization carrier is published; ordinary priced routes remain supported.
        - `discovery` RoutePricingDiscovery: Opt-in x402 Bazaar discovery metadata. When present, the route's 402 challenge carries it (resource description, mimeType, serviceName, tags, iconUrl, extensions.bazaar) plus platform attribution (the tag run402 and accepts[].extra.hosted_by), and the first paid call through the CDP facilitator lists the route in the Bazaar. Allowed only on an exact route with exactly one HTTP method (GET may include HEAD). Canonical JSON of this object is at most 4096 bytes.
          - `description` string, required: What the endpoint does and when to call it. Used verbatim.
          - `mime_type` string: Response media type. Default application/json.
          - `service_name` string: Printable ASCII.
          - `tags` string[]: Printable ASCII. The Bazaar keeps five tags; the platform appends run402 as the fifth.
          - `icon_url` string, uri: Absolute https URL on a public host name, without credentials.
          - `input` object: A GET, HEAD, or DELETE route describes query parameters (query_params_schema, object example); a POST, PUT, or PATCH route describes its body (body_type required). Schemas may reference only local # fragments.
            - `query_params_schema` object
            - `body_type` 'json' | 'form-data' | 'text'
            - `body_schema` object
            - `example` unknown
          - `output` object
            - `example` unknown
            - `schema` object
    - `removed` RouteEntry[], required
      - `pattern` string, required
      - `kind` 'exact' | 'prefix', required
      - `prefix` string, nullable, required
      - `methods` string[], nullable, required: Null means all supported methods.
      - `target` union, required: Web Route target. Function targets invoke a same-release Node 22 function. Static targets are exact static URL aliases that serve a materialized same-release static site file without redirecting or rewriting the browser URL.
        - object
          - `type` 'function', required
          - `name` string, required: Name of a materialized function in the same release.
        - object
          - `type` 'static', required
          - `file` string, required: Relative materialized static-site file path in the same release. No leading slash, query, fragment, backslash, empty segment, . segment, .. segment, or directory shorthand.
      - `pricing` RoutePricingSpec: Fixed-price tenant x402 policy for a public function web route. Supported only when target.type is function; static aliases cannot be priced. A challenge advertises maxTimeoutSeconds=300. After proof verification, Idempotency-Key (1-255 visible ASCII bytes) is scoped by verified payer, project, route pattern, and method, then bound to the normalized request contract. Same-payer/same-request/same-key retry is the only status/recovery operation. Successful routed responses expose platform-owned X-Run402-Payment-* headers and the x402 v2 PAYMENT-RESPONSE settlement header (base64 JSON SettleResponse: success, transaction, network, payer), on a first delivery and on a deduplicated replay alike; pending and conflict responses use a canonical error envelope. Tenant execution is at-least-once, so handlers should deduplicate durable effects by paymentId.
        - `mode` 'always', required: Every matching request must settle x402 before the handler runs.
        - `amount_usd_micros` integer, required: USD micro-units charged per matching request. 250000 means $0.25.
        - `amount_msat` integer: Pins the Lightning price in millisatoshis for the route's lightning / lightning-testnet entries. Valid only when networks names a Lightning value. Absent, each challenge quotes amount_usd_micros into whole satoshis through the platform Lightning quote; amount_usd_micros stays the ledger amount either way.
        - `pay_to` 'org_default_payout', required: Resolve the owning organization default payout wallet at activation and serve time.
        - `networks` RoutePricingNetwork[]: Optional supported network set. Omitted means mainnet only. A Lightning value requires the organization's Lightning receiver on that network (LIGHTNING_RECEIVER_REQUIRED at activation); a Lightning-only route needs no EVM payout wallet. receipt cannot be combined with a Lightning value.
        - `receipt` 'on_fulfillment': Receipt authoring intent from the public ReleaseSpec contract. Run402 Cloud currently rejects this field at routes.replace.<index>.pricing.receipt before mutation until an interoperable delegated-signer authorization carrier is published; ordinary priced routes remain supported.
        - `discovery` RoutePricingDiscovery: Opt-in x402 Bazaar discovery metadata. When present, the route's 402 challenge carries it (resource description, mimeType, serviceName, tags, iconUrl, extensions.bazaar) plus platform attribution (the tag run402 and accepts[].extra.hosted_by), and the first paid call through the CDP facilitator lists the route in the Bazaar. Allowed only on an exact route with exactly one HTTP method (GET may include HEAD). Canonical JSON of this object is at most 4096 bytes.
          - `description` string, required: What the endpoint does and when to call it. Used verbatim.
          - `mime_type` string: Response media type. Default application/json.
          - `service_name` string: Printable ASCII.
          - `tags` string[]: Printable ASCII. The Bazaar keeps five tags; the platform appends run402 as the fifth.
          - `icon_url` string, uri: Absolute https URL on a public host name, without credentials.
          - `input` object: A GET, HEAD, or DELETE route describes query parameters (query_params_schema, object example); a POST, PUT, or PATCH route describes its body (body_type required). Schemas may reference only local # fragments.
            - `query_params_schema` object
            - `body_type` 'json' | 'form-data' | 'text'
            - `body_schema` object
            - `example` unknown
          - `output` object
            - `example` unknown
            - `schema` object
    - `changed` object[], required
      - `pattern` string, required
      - `fields_changed` string[], required
      - `from` RouteEntry: Materialized route entry exposed in release/deployment inventory and route diffs. This is the canonicalized form used by managed domains and custom-domain Worker manifests. Static alias entries carry target { type: "static", file } and exact GET+HEAD effective methods. Function entries may carry canonical pricing.
        - `pattern` string, required
        - `kind` 'exact' | 'prefix', required
        - `prefix` string, nullable, required
        - `methods` string[], nullable, required: Null means all supported methods.
        - `target` union, required: Web Route target. Function targets invoke a same-release Node 22 function. Static targets are exact static URL aliases that serve a materialized same-release static site file without redirecting or rewriting the browser URL.
          - object
            - `type` 'function', required
            - `name` string, required: Name of a materialized function in the same release.
          - object
            - `type` 'static', required
            - `file` string, required: Relative materialized static-site file path in the same release. No leading slash, query, fragment, backslash, empty segment, . segment, .. segment, or directory shorthand.
        - `pricing` RoutePricingSpec: Fixed-price tenant x402 policy for a public function web route. Supported only when target.type is function; static aliases cannot be priced. A challenge advertises maxTimeoutSeconds=300. After proof verification, Idempotency-Key (1-255 visible ASCII bytes) is scoped by verified payer, project, route pattern, and method, then bound to the normalized request contract. Same-payer/same-request/same-key retry is the only status/recovery operation. Successful routed responses expose platform-owned X-Run402-Payment-* headers and the x402 v2 PAYMENT-RESPONSE settlement header (base64 JSON SettleResponse: success, transaction, network, payer), on a first delivery and on a deduplicated replay alike; pending and conflict responses use a canonical error envelope. Tenant execution is at-least-once, so handlers should deduplicate durable effects by paymentId.
          - `mode` 'always', required: Every matching request must settle x402 before the handler runs.
          - `amount_usd_micros` integer, required: USD micro-units charged per matching request. 250000 means $0.25.
          - `amount_msat` integer: Pins the Lightning price in millisatoshis for the route's lightning / lightning-testnet entries. Valid only when networks names a Lightning value. Absent, each challenge quotes amount_usd_micros into whole satoshis through the platform Lightning quote; amount_usd_micros stays the ledger amount either way.
          - `pay_to` 'org_default_payout', required: Resolve the owning organization default payout wallet at activation and serve time.
          - `networks` RoutePricingNetwork[]: Optional supported network set. Omitted means mainnet only. A Lightning value requires the organization's Lightning receiver on that network (LIGHTNING_RECEIVER_REQUIRED at activation); a Lightning-only route needs no EVM payout wallet. receipt cannot be combined with a Lightning value.
          - `receipt` 'on_fulfillment': Receipt authoring intent from the public ReleaseSpec contract. Run402 Cloud currently rejects this field at routes.replace.<index>.pricing.receipt before mutation until an interoperable delegated-signer authorization carrier is published; ordinary priced routes remain supported.
          - `discovery` RoutePricingDiscovery: Opt-in x402 Bazaar discovery metadata. When present, the route's 402 challenge carries it (resource description, mimeType, serviceName, tags, iconUrl, extensions.bazaar) plus platform attribution (the tag run402 and accepts[].extra.hosted_by), and the first paid call through the CDP facilitator lists the route in the Bazaar. Allowed only on an exact route with exactly one HTTP method (GET may include HEAD). Canonical JSON of this object is at most 4096 bytes.
            - `description` string, required: What the endpoint does and when to call it. Used verbatim.
            - `mime_type` string: Response media type. Default application/json.
            - `service_name` string: Printable ASCII.
            - `tags` string[]: Printable ASCII. The Bazaar keeps five tags; the platform appends run402 as the fifth.
            - `icon_url` string, uri: Absolute https URL on a public host name, without credentials.
            - `input` object: A GET, HEAD, or DELETE route describes query parameters (query_params_schema, object example); a POST, PUT, or PATCH route describes its body (body_type required). Schemas may reference only local # fragments.
              - …
            - `output` object
              - …
      - `to` RouteEntry: Materialized route entry exposed in release/deployment inventory and route diffs. This is the canonicalized form used by managed domains and custom-domain Worker manifests. Static alias entries carry target { type: "static", file } and exact GET+HEAD effective methods. Function entries may carry canonical pricing.
        - `pattern` string, required
        - `kind` 'exact' | 'prefix', required
        - `prefix` string, nullable, required
        - `methods` string[], nullable, required: Null means all supported methods.
        - `target` union, required: Web Route target. Function targets invoke a same-release Node 22 function. Static targets are exact static URL aliases that serve a materialized same-release static site file without redirecting or rewriting the browser URL.
          - object
            - `type` 'function', required
            - `name` string, required: Name of a materialized function in the same release.
          - object
            - `type` 'static', required
            - `file` string, required: Relative materialized static-site file path in the same release. No leading slash, query, fragment, backslash, empty segment, . segment, .. segment, or directory shorthand.
        - `pricing` RoutePricingSpec: Fixed-price tenant x402 policy for a public function web route. Supported only when target.type is function; static aliases cannot be priced. A challenge advertises maxTimeoutSeconds=300. After proof verification, Idempotency-Key (1-255 visible ASCII bytes) is scoped by verified payer, project, route pattern, and method, then bound to the normalized request contract. Same-payer/same-request/same-key retry is the only status/recovery operation. Successful routed responses expose platform-owned X-Run402-Payment-* headers and the x402 v2 PAYMENT-RESPONSE settlement header (base64 JSON SettleResponse: success, transaction, network, payer), on a first delivery and on a deduplicated replay alike; pending and conflict responses use a canonical error envelope. Tenant execution is at-least-once, so handlers should deduplicate durable effects by paymentId.
          - `mode` 'always', required: Every matching request must settle x402 before the handler runs.
          - `amount_usd_micros` integer, required: USD micro-units charged per matching request. 250000 means $0.25.
          - `amount_msat` integer: Pins the Lightning price in millisatoshis for the route's lightning / lightning-testnet entries. Valid only when networks names a Lightning value. Absent, each challenge quotes amount_usd_micros into whole satoshis through the platform Lightning quote; amount_usd_micros stays the ledger amount either way.
          - `pay_to` 'org_default_payout', required: Resolve the owning organization default payout wallet at activation and serve time.
          - `networks` RoutePricingNetwork[]: Optional supported network set. Omitted means mainnet only. A Lightning value requires the organization's Lightning receiver on that network (LIGHTNING_RECEIVER_REQUIRED at activation); a Lightning-only route needs no EVM payout wallet. receipt cannot be combined with a Lightning value.
          - `receipt` 'on_fulfillment': Receipt authoring intent from the public ReleaseSpec contract. Run402 Cloud currently rejects this field at routes.replace.<index>.pricing.receipt before mutation until an interoperable delegated-signer authorization carrier is published; ordinary priced routes remain supported.
          - `discovery` RoutePricingDiscovery: Opt-in x402 Bazaar discovery metadata. When present, the route's 402 challenge carries it (resource description, mimeType, serviceName, tags, iconUrl, extensions.bazaar) plus platform attribution (the tag run402 and accepts[].extra.hosted_by), and the first paid call through the CDP facilitator lists the route in the Bazaar. Allowed only on an exact route with exactly one HTTP method (GET may include HEAD). Canonical JSON of this object is at most 4096 bytes.
            - `description` string, required: What the endpoint does and when to call it. Used verbatim.
            - `mime_type` string: Response media type. Default application/json.
            - `service_name` string: Printable ASCII.
            - `tags` string[]: Printable ASCII. The Bazaar keeps five tags; the platform appends run402 as the fifth.
            - `icon_url` string, uri: Absolute https URL on a public host name, without credentials.
            - `input` object: A GET, HEAD, or DELETE route describes query parameters (query_params_schema, object example); a POST, PUT, or PATCH route describes its body (body_type required). Schemas may reference only local # fragments.
              - …
            - `output` object
              - …
  - `static_assets` StaticAssetsDiff, required
    - `unchanged` integer, required
    - `changed` integer, required
    - `added` integer, required
    - `removed` integer, required
    - `newly_uploaded_cas_bytes` integer, required
    - `reused_cas_bytes` integer, required
    - `deployment_copy_bytes_eliminated` integer, required
    - `legacy_immutable_warnings` object[], required
      - `path` string, required
      - `sha256` string, required
      - `reason` string, required
    - `previous_immutable_failures` object[], required
      - `path` string, required
      - `previous_sha256` string, required
      - `candidate_sha256` string, required
    - `cas_authorization_failures` string[], required
  - `tools` object: add-app-mcp-endpoint: MCP tools added, removed, or changed between the two releases, by tool name.
    - `added` string[], required
    - `removed` string[], required
    - `changed` string[], required

## Other responses

- `400`: INVALID_QUERY_PARAM, DIFF_SAME_RELEASE, or INVALID_DIFF_TARGET.
- `404`: Either side not found in project scope.
- `501`: Feature disabled.

---

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