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

# Edit URL (embedded viewer)

> Give your users a live, in-app view of documents your API generated — no file download, no third-party viewer, no infra on your side.

Every completed run returns an `edit_url` alongside the `download_url`.
Drop it in an `<iframe>` and your end-users see the generated document
rendered as a full spreadsheet / document / presentation surface inside
your app — they can scroll, zoom, switch sheets or slides, and inspect
everything the agent produced.

```json theme={null}
{
  "run_id": "run_01HXYZ",
  "download_url": "https://backend.overtenai.com/api/v1/runs/run_01HXYZ/download",
  "edit_url":     "https://backend.overtenai.com/api/v1/edit/run_01HXYZ?token=...",
  ...
}
```

It's called `edit_url` because the surface behind it is the Overten
**editor** — the same editor the Overten web app uses for its
authenticated users. End-users can browse and edit the document live;
changes (cell values, text, slide content) persist back to the run's
artifact, so the next `download_url` fetch serves the edited version.
For programmatic / agent-driven edits, call the relevant generate
endpoint again with the same `run_id` and a new prompt — it composes
with manual edits.

## `download_url` vs `edit_url` — when to use which

|                              | `download_url`                             | `edit_url`                                                      |
| ---------------------------- | ------------------------------------------ | --------------------------------------------------------------- |
| **What you get**             | A URL to the raw file bytes                | An iframe-ready URL to a live document viewer                   |
| **Primary use**              | Save to disk, email, feed another pipeline | Show the AI's output inside your app so the user can inspect it |
| **Interactive?**             | No — one-way pull                          | Yes — scroll, zoom, switch sheets/slides, click cells           |
| **User can edit?**           | N/A (it's a file)                          | Yes — edits persist to the run's artifact                       |
| **Lifetime**                 | 24 hours (signed storage URL)              | 15 minutes, with sliding refresh on activity                    |
| **Cross-app safe to share?** | No (grants file access)                    | No (grants view access to one run)                              |

Most integrations use **both**: `edit_url` inside their dashboard so
users see results immediately, `download_url` on a "Download" button so
users can take the file elsewhere.

## How it works end-to-end

```
  Your app                 Overten API                 Overten storage
  ────────                 ───────────                 ───────────────
     │
     │ 1. Submit prompt
     │────────────────────────>│
     │                         │   run agent, persist file
     │                         │─────────────────────────────>│
     │<──── download_url       │
     │      edit_url(token) ───│
     │
     │ 2. <iframe src={edit_url}>
     │─────────────────────────┐
     │                         │  validate token
     │                         │  load file from storage
     │                         │<────────────────────────────│
     │   3. Rendered document  │
     │<────────────────────────│
```

1. You call `POST /excel/generate` (or word/slides), get back `edit_url`.
2. You embed that URL in an iframe in your UI.
3. Overten validates the token, loads the run's file from storage, and
   streams a rendering of the document into the iframe.
4. Every subsequent user action (scroll, click, zoom) stays between the
   browser and Overten — your app never sees the content, never handles
   bytes, never runs a viewer itself.

The token is what ties "this iframe open right now" to "this specific
run". It expires and is scoped — see below.

## Token semantics

* **Opaque** — a random string, not a JWT. Generated by Overten,
  validated by Overten. Don't try to parse it client-side.
* **Scoped to one run + your org** — if someone copy-pastes the URL into
  another app, the token still only unlocks *this* document for *your*
  org.
* **Short-lived, sliding** — 15 minutes from the last user activity.
  Active viewer sessions refresh the TTL automatically; idle sessions
  (user closed the tab) expire on their own.
* **No explicit revoke endpoint today.** The short sliding TTL is the
  mitigation. If you suspect a leak before a token has expired
  naturally, contact support with the `run_id` and we can invalidate on
  our side.

## Basic embed

```html theme={null}
<iframe
  src="{{ run.edit_url }}"
  width="100%"
  height="800"
  allow="clipboard-read; clipboard-write"
  sandbox="allow-scripts allow-same-origin allow-forms"
></iframe>
```

React:

```jsx theme={null}
function DocumentViewer({ run }) {
  return (
    <iframe
      src={run.edit_url}
      title="Document viewer"
      style={{ width: "100%", height: "100vh", border: 0 }}
      allow="clipboard-read; clipboard-write"
    />
  );
}
```

## How edits land

Two paths — they compose:

1. **Direct in-iframe edits.** The user types, changes a cell, rewrites
   a paragraph, moves a slide. Edits auto-save to the run's artifact
   (same storage location `download_url` points at). The next fetch
   serves the updated bytes.
2. **Agent-driven edits via API.** Call the relevant generate endpoint
   with the original `run_id` and a new prompt; the agent picks up
   whatever state is current (including the user's in-iframe edits)
   and applies the change:

   ```python theme={null}
   resp = requests.post(
       f"{API}/excel/generate",
       headers=headers,
       json={
           "run_id": "run_01HXYZ",
           "prompt": "Apply a % YoY column to the Summary sheet "
                     "and extend the headcount chart through Q4.",
       },
   )
   ```

Agent follow-ups via `run_id` are cheap because the agent resumes from
state — it's not rebuilding the workbook, just applying the delta.
Every generate response includes fresh `edit_url` and `download_url`.

## Getting a fresh URL after expiry

If the original `edit_url` has expired (e.g. the user opens your
dashboard the next morning and tries to reopen a doc from yesterday),
call the generate endpoint again with the original `run_id` and a no-op
prompt:

```bash theme={null}
curl -X POST "https://backend.overtenai.com/api/v1/excel/generate" \
  -H "X-API-Key: $OVERTEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "run_id": "run_01HXYZ",
    "prompt": "(no change — just reopening the session)"
  }'
```

The response includes a fresh `edit_url` with a new token. Resume via
`run_id` is cheap because the agent already has state.

## What `edit_url` is NOT

* **Not a shareable public link.** Tokens are scoped to one viewer
  session. Don't email an `edit_url` — it'll work for 15 minutes, then
  stop, and before then it unlocks your org's run to whoever clicked.
* **Not a download.** The iframe renders the document live; bytes
  never land on the user's disk via this route. For downloads, use
  `download_url`.
* **Not a programmatic write API.** In-iframe edits work for human
  users, but your server-side code should use the generate endpoint
  with `run_id` to apply structured changes — that's auditable, has a
  ledger row, and doesn't require a browser.
* **Not a hosted Office install.** Your end-user doesn't need Excel /
  Word / PowerPoint locally. The viewer runs entirely in the browser.

## Security notes

* **Mint per viewer.** Don't store one `edit_url` server-side and serve
  it to multiple users. The token is meant for one session — each user
  should get a freshly-minted URL.
* **Strip tokens from logs / analytics.** Drop the `token` query param
  before recording page URLs in your observability tools.
* **Restrict frame ancestors.** If you serve `edit_url` in an
  `<iframe>`, set a Content-Security-Policy on your parent page that
  limits which origins can frame your dashboard, so an attacker can't
  frame your app and read the iframe's state via JS.
* **Prefer your own domain for the parent page.** The token is only
  meaningful in-browser; someone who captures the URL during a session
  and opens it from another host still has to get past the sliding TTL.

## White-label / custom branding

By default, the viewer shows standard Overten chrome (header, logo).
Enterprise customers can get a white-label version with custom
branding — contact [support](mailto:support@overten.ai).

If you don't want to use the Overten viewer at all:

* Use `download_url` and render the file with your own tooling
  (Google Drive viewer, OnlyOffice, SheetJS, native Office apps).
* Or fetch the file bytes server-side and hand them to your preferred
  renderer.

The API returns both `download_url` and `edit_url` on every run, so
you can switch between approaches per-user or per-route without
changing your generation code.
