Guides

    Embedding the editor

    Put the collaborative editor in your own app with an iframe.

    Render DocDealer's collaborative editor inside your own product. Your users never see a DocDealer login, and your API key never reaches their browser.

    How it works

    Your backend trades its API key for an embed token: short-lived, scoped to one document, and safe to put in an iframe URL.

    Rendering diagram…
    Your backend holds the key; the browser only ever sees a scoped token

    A cross-site iframe sends no cookies, so the token in the URL is the credential. That is also why you must mint it server-side: anything the browser can read, your users can read.

    Mint a session

    curl
    # Your backend, holding your API key.
    curl -X POST https://thedocdealer.com/api/embed/sessions \
      -H "Authorization: Bearer $DOCDEALER_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "documentId": "<uuid>",
        "displayName": "Ana Torres",
        "externalUserId": "user-1042",
        "parentOrigin": "https://app.example.com"
      }'
    
    # → { "token": "...", "url": "https://thedocdealer.com/embed/<uuid>?embed_token=...",
    #     "expiresAt": "2026-08-24T12:34:56.000Z" }

    Prop

    Type

    Then drop the returned url straight into an iframe:

    your page
    <iframe src="{url}" style="width:100%;height:100%;border:0" title="Editor"></iframe>

    Keeping the session alive

    Tokens last 15 minutes by default, and the iframe renews itself at half-life without any help from you. Each renewal re-checks your API key server-side, which is what makes revocation take effect.

    It cannot always renew itself, though: a laptop that slept past the expiry, a reload of a stale src, or a session that has run for 12 hours. Then it asks your page, because only your backend can mint a token. Implement the other half of that exchange and sessions survive indefinitely:

    your page
    // Your page. The iframe renews itself while it can; when it can't,
    // it asks you — because only your backend holds the API key.
    window.addEventListener('message', async event => {
      if (event.origin !== 'https://thedocdealer.com') return
    
      const msg = event.data
      if (msg?.source !== 'docdealer-embed' || msg.type !== 'token-request') return
    
      // Your own session check belongs here. Returning nothing ends the
      // embedded session, which is what you want when your user signs out.
      if (!currentUser) return
    
      const res = await fetch('/api/embed-token', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ documentId: msg.documentId, displayName: currentUser.name }),
      })
      const { token } = await res.json()
    
      iframe.contentWindow.postMessage(
        { source: 'docdealer-embed', v: 1, type: 'token', token },
        'https://thedocdealer.com'
      )
    })

    Note the origin check on the way in and the explicit target origin on the way out. Both matter: without them any page could hand your iframe a token, or read yours.

    Declining to answer is a feature. It is how you end an embedded session when your own user signs out.

    Matching your theme

    Pass theme when you mint the session and the editor paints light or dark from the first frame — no flash of the wrong palette:

    POST /api/embed/sessions
    { "documentId": "<uuid>", "displayName": "Ana Torres", "theme": "light" }

    If your users can toggle the theme without a reload, send it over the same bridge and the iframe follows immediately:

    your page
    iframe.contentWindow.postMessage(
      { source: 'docdealer-embed', v: 1, type: 'theme', theme: 'dark' },
      'https://thedocdealer.com'
    )

    While embedded, the editor takes the theme only from you — it neither reads nor writes the visitor's own stored DocDealer preference, so it can never drift out of sync with your page.

    What an embed session can do

    Everything a DocDealer user can do to that one document. The embedded editor is the same component the app itself renders, so your users get the form, the collaborative document, attachments with OCR, section generation and export.

    The boundary is the document, not the feature set:

    • One document. Every other id is denied — including documents in the same organization, and including on the endpoints that take the id in the request body rather than the path.
    • No creating or listing. It cannot create documents, list your documents, or list your templates.
    • No administration. No API-key management, no admin endpoints, and it cannot mint another session.

    It can spend AI credit on that document: generating sections and analysing attachments are AI calls, and they are what the editor is for. So treat an embed token like a logged-in session scoped to one document — short-lived, and worth revoking if it leaks. Disabling the API key that minted it kills every live session within one token lifetime.

    One deliberate exception to the single-document rule: fields backed by an organization connector can read and invoke that connector, since those fields are unusable otherwise.

    Practical notes

    • Content Security Policy. Your page needs frame-src https://thedocdealer.com. If you serve over HTTP in development, note that upgrade-insecure-requests will break the frame.
    • An invalid token renders an error, not a redirect. Redirecting a cross-site iframe to a login page is a dead end, so a bad token returns 401 and an expired one shows a recoverable state instead.
    • Your users appear as themselves. The displayName you sign shows up on cursors and in the document's edit history.

    A complete worked example — backend, page, and both halves of the bridge — lives in the repository:

    README.md
    Dockerfile
    package.json