---
title: "Read app content on a draft"
method: GET
path: "/api/v2/documents/{identifier}/draft/{draftIdentifier}/app"
tags: ["Documents"]
---

# Read app content on a draft

`GET /api/v2/documents/{identifier}/draft/{draftIdentifier}/app`

**Alpha.** The app sub-resource may change shape without a deprecation cycle while apps mature. The document routes are stable.

Read the app content on a named draft — the draft-side counterpart of `GET …/app`, and the read half of the draft write loop: app writes are last-write-wins whole-document replaces, so fetch the draft’s latest HTML here before building the next `PUT …/draft/{draftIdentifier}/app` body. Same response shape as the published read. Writes cap the HTML at 2 MiB — apps saved before the cap may read back larger, and a body over the cap is rejected on the way back in. The published document’s content is unaffected by draft edits — read it via `GET …/app`.

A draft with no app is a 404 — including a draft that carries a dashboard, which can never carry an app.

A document carries at most one of a dashboard or an app — never both; workbook-only is valid. The app HTML and settings live only at the app sub-resource routes; the document read carries an `app` slice pointing here, and the whole-document PATCH accepts that slice back only as it was read.

## Path parameters

- `draftIdentifier` string, required — Draft workbook identifier (see `PATCH /api/v2/documents/{identifier}/draft`).
- `identifier` string, required — Published document identifier.

## Query parameters

- `pretty` '0' | '1' | 'true' | 'false' — Set `true` or `1` to pretty-print (2-space indent) the response; `false` / `0` (the default) is compact. Key ordering is deterministic regardless.

## Response `200`

The draft’s app content.

- DocumentsV2AppContentResponse
  - `html` string, required — The complete app HTML document.
  - `settings` DocumentsV2AppSettings, required — The app's sandbox settings: capability toggles plus the safe-domain and navigation allowlists. A write replaces the whole object; omitted fields take their locked-down defaults. Host lists are normalized (deduped, invalid or Omni-owned hosts dropped) before they are stored.
    - `allowClipboard` boolean
    - `allowDefaultMapProviders` boolean
    - `allowDownloads` boolean
    - `allowExternalNavigation` boolean
    - `allowInternalNavigation` boolean
    - `externalNavOpensInNewTab` boolean
    - `navAllowedDomains` string[]
    - `navAllowedDomainsEnabled` boolean
    - `safeDomains` string[]
    - `safeDomainsEnabled` boolean

## Other responses

- `401` — Authentication required.
- `403` — Insufficient permissions to read the document.
- `404` — Document or draft not found, the draft has no app (a dashboard draft never does), or the organization has apps disabled.
- `405` — Method not allowed.

## Changes

- **2026-09-04** `d733952abba0` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/omniapp/apis/omni-api/changes/api/v2/documents/:identifier/draft/:draftIdentifier/app/get.md)

---

[API](https://skmtc.dev/omniapp/apis/omni-api.md) · [All operations](https://skmtc.dev/omniapp/apis/omni-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/omniapp/omni-api/revisions/d733952abba0/schema)
