---
title: "Opening documents"
description: "Open a PDF, unlock a password-protected file, say who is working on it, and close it again."
source: "https://www.cloudpdf.com/docs/engine/documents/opening"
---

# Opening documents

`engine.open()` gives you a handle to one document. Everything you do with the document starts
from that handle.

```ts
const doc = await engine.open({ kind: 'token', token: () => fetchDocumentToken('contract') });
```

## Open a document

The document is already on your server, so you open it by reference. There are three ways,
depending on where the credential comes from:

| Input                           | When to use it                                                   |
| :------------------------------ | :--------------------------------------------------------------- |
| `{ kind: 'token', token }`      | Your backend created a token for this user and this document.    |
| `{ kind: 'id', id }`            | Your app has a token for your whole account (admin tools, jobs). |
| `{ kind: 'share', shareToken }` | A public share link from the CloudPDF dashboard.                 |

[Authentication](https://www.cloudpdf.com/docs/engine/authentication) shows how to create tokens and when to use each.

`open()` fetches the document's details from the server, never the file itself. Pages, text and
images arrive as you ask for them.

## Password-protected files

A PDF can have its own password. When you know it, pass it when you open:

```ts
const doc = await engine.open(input, { password: 'secret' });
```

When you don't, open without one and ask the user only if the file needs it.
`doc.security.passwordPrompt` tells you:

```ts
const doc = await engine.open(input);

if (doc.security.passwordPrompt.state === 'required') {
  const password = await askUserForPassword();
  await doc.security.unlock({ password });
}
```

| `passwordPrompt.state` | What it means                                                                      |
| :--------------------- | :--------------------------------------------------------------------------------- |
| `'none'`               | Nothing to do: the file has no password, or it's already fully unlocked.           |
| `'required'`           | The file can't be read without its password. Ask before you do anything else.      |
| `'optional'`           | The file is open, but its owner password would give more rights. You may offer it. |

`passwordPrompt.hint` says which password to ask for (`'user'` or `'owner'`), when the engine
knows. When the state is `'required'`, `passwordPrompt.incorrect` is `true` if the last password
you tried was wrong.

A locked document still opens: without a password, `open()` succeeds, and every call that reads
the file fails with `DocPasswordRequired` until you unlock it. A wrong password doesn't fail
`open()` either: the document opens locked, and `passwordPrompt.incorrect` is `true`, so you can
say "that password is wrong" and ask again.

`unlock()` fails with `DocPasswordIncorrect` when the password is wrong, so you can ask again:

```ts
import { EngineError, EngineErrorCode } from '@cloudpdf/engine';

while (doc.security.passwordPrompt.state === 'required') {
  try {
    await doc.security.unlock({ password: await askUserForPassword() });
  } catch (error) {
    if (!EngineError.is(error, EngineErrorCode.DocPasswordIncorrect)) throw error;
    showMessage('That password is wrong. Try again.');
  }
}
```

### Owner password

A PDF can have two passwords. The user password opens it; the owner password also lifts the
file's own restrictions, such as "no printing" or "no copying". When a file is open but not with
its owner password, `passwordPrompt` is `'optional'`.

To accept only the owner password, pass `mode: 'owner'`. The user password then fails with
`DocPasswordIncorrect`:

```ts
await doc.security.unlock({ password, mode: 'owner' });
```

The file's own restrictions only count when the user's permissions include `pdf.permissions`;
see [Permissions](https://www.cloudpdf.com/docs/engine/concepts/permissions#the-pdfs-own-restrictions).

On the cloud, who the user is and what they may do come from their token, so `open()` has no
options for them. See [What a token carries](https://www.cloudpdf.com/docs/engine/authentication#what-a-token-carries).

## Close a document

Close a document when you're done with it:

```ts
await doc.close();
```

Closing stops the live updates for this document and forgets what the engine cached. The document
itself stays on the server. After it, calls on `doc` fail with `DocNotOpen`. Closing twice is
fine.

## One engine, many documents

Create one engine for your app and open every document on it:

```ts
const [contract, invoice] = await Promise.all([
  engine.open(contractInput),
  engine.open(invoiceInput),
]);
```

Keep the engine for as long as your app runs. When you do want to shut it down, at the end of a
script for example, destroy it; that also closes every document still open on it:

```ts
await engine.destroy();
```

Each document keeps the token it was opened with, so one engine can hold documents opened for
different users or with different permissions.

## Good to know

### Cancelling an open

`open()` returns a promise you can cancel, like every call:

```ts
const opening = engine.open(input);
cancelButton.onclick = () => opening.abort();
```

See [Errors & cancelling](https://www.cloudpdf.com/docs/engine/concepts/errors-and-cancelling).
