Documents

PSPDFKit Server provides the following API endpoints for working with documents:


Uploading a Document

To create a new document from a PDF file, POST its contents to /api/document, specifying the application/pdf content type:

Request

1
2
3
4
5
POST /api/documents
Content-Type: application/pdf
Authorization: Token token="<secret token>"

<PDF data>
Copy
1
2
3
4
5
$ curl http://localhost:5000/api/documents \
   -X POST \
   -H "Authorization: Token token=<secret token>" \
   -H "Content-Type: application/pdf" \
   -T document.pdf

Response

Copy
1
2
3
4
5
6
7
8
9
10
11
HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": {
    "document_id": ...,
    "errors": [],
    "sourcePdfSha256": ...,
    "title": "..."
  }
}

PSPDFKit Server will extract the title of the document from the PDF metadata if it is present.

The errors list will be non-empty if errors were encountered when importing annotations from the document. Each error will have the format {"reason": "Error description"}.

PSPDFKit Server also supports uploading files as multipart/form-data. When using this method, the server will try reading the title from the PDF metadata and fall back to the filename if the metadata is not available.

Request

Copy
1
2
3
4
5
6
7
8
9
10
POST /api/documents
Content-Type: multipart/form-data; boundary=customboundary
Authorization: Token token="<secret token>"

--customboundary
Content-Disposition: form-data; name="file"; filename="Example Document.pdf"
Content-Type: application/pdf

<PDF data>
--customboundary--

Providing Your Own ID for Documents

As of version 2018.6, PSPDFKit Server supports providing an arbitrary document_id on upload. This can be useful when you want to use your own identifiers for documents. This feature can also be used to migrate from an existing document management solution on demand, as we explained in the document migration guide:

Request

Copy
1
2
3
4
5
6
7
8
9
10
POST /api/documents
Content-Type: multipart/form-data; boundary=customboundary
Authorization: Token token="<secret token>"

--customboundary
Content-Disposition: form-data; document_id="your_document_identifier_1"; filename="Example Document.pdf"
Content-Type: application/pdf

<PDF data>
--customboundary--
Copy
1
2
3
4
$ curl -X POST http://localhost:5000/api/documents/ \
   -H "Authorization: Token token=<secret token>" \
   -F "file=@example.pdf" \
   -F "document_id=your_document_identifier_1"

Providing Your Own Title for Documents

As of version 2019.2, PSPDFKit Server supports providing an arbitrary title on upload, which will override the title included in the PDF document (if present):

Request

Copy
1
2
3
4
5
6
7
8
9
10
POST /api/documents
Content-Type: multipart/form-data; boundary=customboundary
Authorization: Token token="<secret token>"

--customboundary
Content-Disposition: form-data; name="file"; title="My custom title"; filename="Example Document.pdf"
Content-Type: application/pdf

<PDF data>
--customboundary--
Copy
1
2
3
4
$ curl -X POST http://localhost:5000/api/documents/ \
   -H "Authorization: Token token=<secret token>" \
   -F "file=@example.pdf" \
   -F "title=My custom title"

Adding a Document from a URL

You can also add a document to PSPDFKit Server by specifying the URL the document can be fetched from. A document added by a URL is not persistently stored in PSPDFKit Server and will be fetched from the URL when necessary. This is useful when you already have a document storage solution and you want PSPDFKit Server to fetch the documents from your document storage.

To add a document from a URL, POST its URL — and optionally, its SHA256 hash, your document_id, and your title — to /api/document, specifying the application/json content type:

Request

Copy
1
2
3
4
5
6
7
8
POST /api/documents
Content-Type: application/json
Authorization: Token token="<secret token>"

{
  "url": "http://exampleserver/sample.pdf",
  "sha256": "d37b9395c2baf168f977ce9ff9ec007d7270fc84cbf1549324bfc8dfc34333a9"
}
Copy
1
2
3
4
5
$ curl http\://127.0.0.1\:5000/api/documents \
    -X POST \
    -H "Authorization: Token token=<secret token>" \
    -H "Content-type: application/json" \
    -d '{"url": "http://exampleserver/sample.pdf", "sha256": "d37b9395c2baf168f977ce9ff9ec007d7270fc84cbf1549324bfc8dfc34333a9", "title": "My custom title"}'

Response

Copy
1
2
3
4
5
6
7
8
9
10
11
12
HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": {
    "createdAt": ...,
    "document_id": ...,
    "errors": [],
    "sourcePdfSha256": ...,
    "title": "...",
  }
}

If a title attribute is not provided, PSPDFKit Server will extract the title of the document from the PDF metadata (if present).

The errors list will be non-empty if errors were encountered when importing annotations from the document. Each error will have the format {"reason": "Error description"}.

When the SHA256 is specified but the hash does not match the calculated hash from the document downloaded from the URL, the following response is returned by the server:

Response

Copy
1
2
3
4
5
6
7
8
9
HTTP/1.1 409 Conflict
Content-Type: application/json

{
  "error": {
    "reason": "hash_mismatch",
    "description": "The provided hash does not match the calculated hash from the document."
  }
}

When using the API to add a document from a URL, your backend storage must always deliver the same file, since the SHA256 will never be recalculated after the document is created. If the file on your storage backend changes and PSPDFKit Server needs to refetch the file (e.g. because it’s no longer cached), this will result in a hash_mismatch error on PSPDFKit Server.

Including Annotations via the XFDF/Instant JSON File

PSPDFKit Server supports importing an XFDF or Instant JSON file when adding a new document. This replaces all existing annotations in the uploaded PDF with the annotations from the uploaded XFDF or Instant JSON file. If you want to add annotations to already existing ones instead of replacing them when you import an XFDF file, you can set keep_current_annotations to true. Then POST either the PDF file or the document URL, along with the XFDF or Instant JSON file, as part of a multipart/form-data request:

To upload a PDF file with an Instant JSON or XFDF file:

Request

Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
POST /api/documents
Content-Type: multipart/form-data; boundary=customboundary
Authorization: Token token="<secret token>"

--customboundary
Content-Disposition: form-data; name="file"; filename="Example Document.pdf"
Content-Type: application/pdf

<PDF data>
--customboundary
Content-Disposition: form-data; name="attachment"; filename="attachment.xfdf"
Content-Type: application/json

<annotations data>
--customboundary
Content-Disposition: form-data; name="keep_current_annotations"

true
--customboundary--

To add a document from a URL with an Instant JSON or XFDF file:

Request

Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
POST /api/documents
Content-Type: multipart/form-data; boundary=customboundary
Authorization: Token token="<secret token>"

--customboundary
Content-Disposition: form-data; name="url";

http://exampleserver/sample.pdf
--customboundary
Content-Disposition: form-data; name="attachment"; filename="attachment.xfdf"
Content-Type: application/json

<annotations data>
--customboundary
Content-Disposition: form-data; name="keep_current_annotations"

true
--customboundary--

Fetching Document Properties

Request

1
2
GET /api/documents/:document_id/properties
Authorization: Token token="<secret token>"
1
2
$ curl http://localhost:5000/api/documents/abc/properties \
   -H "Authorization: Token token=<secret token>"

Response

If a document with the given ID exists, PSPDFKit Server will return an HTTP response with the status 200 and the following JSON payload:

Copy
1
2
3
4
5
6
HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": {"sourcePdfSha256": "...", "title": "...", "passwordProtected": ..., "storage": {"type": "built-in"}}
}

The fields sourcePdfSha256, passwordProtected, and title are assigned by PSPDFKit Server when a document is uploaded.

The storage key includes information about the storage mechanism used for the underlying PDF document:

  • When the type is built-in, it uses the built-in database-backed storage.
  • When the type is s3, it uses the S3 asset storage. The response also includes the S3 bucket used.
  • When the type is remote, it indicates a remote PDF file. The response includes the URL of the file.

For more information about how assets are stored, please see the Asset Storage guide.

If there’s no such document, an HTTP response with the status 404 and the following JSON payload will be returned:

1
2
3
4
5
6
HTTP/1.1 404 Not Found
Content-Type: application/json

{
  "error": {"reason": "document_not_found"}
}

Fetching a Document’s PDF File

Download the latest version of a document as a PDF, with annotations included. Include source=true in the query to download the version of the PDF document that was originally uploaded:

Request

1
2
GET /api/documents/:document_id/pdf?source=true
Authorization: Token token="<secret token>"
1
2
$ curl "http://localhost:5000/api/documents/abc/pdf?source=true" \
   -H "Authorization: Token token=<secret token>"

Response

1
2
3
4
HTTP/1.1 200 OK
Content-Type: application/pdf

<PDF data>

To target a specific Instant layer, you can modify the endpoint path from /api/documents/:document_id/pdf to /api/documents/:document_id/layers/:layer_name/pdf.

Fetching a Document’s Flattened PDF

Include flatten=true in the query to download a document as a flattened PDF:

Request

1
2
GET /api/documents/:document_id/pdf?flatten=true
Authorization: Token token="<secret token>"
1
2
$ curl "http://localhost:5000/api/documents/abc/pdf?flatten=true" \
   -H "Authorization: Token token=<secret token>"

Response

1
2
3
4
HTTP/1.1 200 OK
Content-Type: application/pdf

<PDF data>

To target a specific Instant layer, you can modify the endpoint path from /api/documents/:document_id/pdf?flatten=true to /api/documents/:document_id/layers/:layer_name/pdf?flatten=true.

Editing a Document’s PDF and Downloading the Resulting File

The Document Editor is a separate component of PSPDFKit for Web, and it’s available for licenses with the document editing feature. It provides you and your users with a whole host of page editing features, including new page creation, page duplication, reordering, merging imported documents, rotation, and deletion.

This endpoint will apply a list of operations to an existing document and return the resulting PDF file without persisting it in the system.

You can find a list of supported operations in the JSON Format guide.

For example, you can rotate the first page of a document 90 degrees clockwise:

Request

Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
POST /api/documents/:document_id/pdf_with_operations
Content-Type: application/json
Authorization: Token token="<secret token>"

{
  "operations": [
    {
      "type": "rotatePages",
      "pageIndexes": [0],
      "rotateBy": 90
    }
  ]
}

Response

1
2
3
4
HTTP/1.1 200 OK
Content-Type: application/pdf

<PDF data>
Copy
1
2
3
4
5
$ curl http://localhost:5000/api/documents/:document_id/pdf_with_operations \
  -X POST \
  -H "Authorization: Token token=<secret token>" \
  -H "Content-Type: application/json" \
  -d '{"operations": [{"type": "rotatePages", "pageIndexes": [0], "rotateBy": 90}]}'

To support the importDocument operation, it’s necessary to use the multipart/form content type, as the operation requires attaching a PDF file to be imported into an existing document.

For example, you can rotate the first page of a document and then add the contents of another PDF directly after:

Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
POST /api/documents/:document_id/pdf_with_operations
Content-Type: multipart/form-data; boundary=customboundary
Authorization: Token token="<secret token>"

--customboundary
Content-Disposition: attachment; name="operations"; filename="operations.json"
Content-Type: application/json

{
  "operations": [
    {
      "type": "rotatePages",
      "pageIndexes": [0],
      "rotateBy": 90
    },
    {
      "type": "importDocument",
      "document": "5ce11b7c-0726-48a2-a493-1cf4f92f26c5"
      "afterPageIndex": 0
    },
  ]
}
--customboundary
Content-Disposition: attachment; name="5ce11b7c-0726-48a2-a493-1cf4f92f26c5"; filename="imported.pdf"
Content-Type: application/pdf

<PDF data>
--customboundary--
Copy
1
2
3
4
$ curl http://localhost:5000/api/documents/:document_id/pdf_with_operations \
  -H "Authorization: Token token=<secret token>" \
  -F "operations=<operations.json" \
  -F "5ce11b7c-0726-48a2-a493-1cf4f92f26c5=@imported.pdf;type=application/pdf"

Response

1
2
3
4
HTTP/1.1 200 OK
Content-Type: application/pdf

<PDF data>

As you can pass more than one importDocument operation, it’s necessary to assign a unique ID to the name of the PDF attachment so that it can be referenced in the corresponding operation’s body.

To target a specific Instant layer, you can modify the endpoint path from /api/documents/:document_id/pdf_with_operations to /api/documents/:document_id/layers/:layer_name/pdf_with_operations.

Editing a Document’s PDF and Persisting the Resulting File

This endpoint will apply a list of operations to an existing document and store the resulting PDF file at the document’s base layer.

Applying a document operation will affect both the data stored by PSPDFKit Server and the responses returned by other endpoints. For example, if you remove a page from a document, all annotations belonging to that page will be deleted as well. Similarly, other functionality (e.g. searching in a document) will return different results.

If you need to preserve the original document, PDF file, and related data, we recommend leveraging Instant Layers and always using named layers.

You can find a list of supported operations in the JSON Format guide.

For example, you can rotate the first page of a document 90 degrees clockwise:

Request

Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
POST /api/documents/:document_id/apply_operations
Content-Type: application/json
Authorization: Token token="<secret token>"

{
  "operations": [
    {
      "type": "rotatePages",
      "pageIndexes": [0],
      "rotateBy": 90
    }
  ]
}

Response

Copy
1
2
3
4
5
6
HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": {"sourcePdfSha256": "...", "title": "...", "passwordProtected": ..., "storage": {"type": "built-in"}}
}
Copy
1
2
3
4
5
$ curl http://localhost:5000/api/documents/:document_id/apply_operations \
  -X POST \
  -H "Authorization: Token token=<secret token>" \
  -H "Content-Type: application/json" \
  -d '{"operations": [{"type": "rotatePages", "pageIndexes": [0], "rotateBy": 90}]}'

To support the importDocument operation, it’s necessary to use the multipart/form content type, as the operation requires attaching a PDF file to be imported into an existing document.

For example, you can rotate the first page of a document and then add the contents of another PDF directly after:

Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
POST /api/documents/:document_id/apply_operations
Content-Type: multipart/form-data; boundary=customboundary
Authorization: Token token="<secret token>"

--customboundary
Content-Disposition: attachment; name="operations"; filename="operations.json"
Content-Type: application/json

{
  "operations": [
    {
      "type": "rotatePages",
      "pageIndexes": [0],
      "rotateBy": 90
    },
    {
      "type": "importDocument",
      "document": "5ce11b7c-0726-48a2-a493-1cf4f92f26c5"
      "afterPageIndex": 0
    },
  ]
}
--customboundary
Content-Disposition: attachment; name="5ce11b7c-0726-48a2-a493-1cf4f92f26c5"; filename="imported.pdf"
Content-Type: application/pdf

<PDF data>
--customboundary--
Copy
1
2
3
4
$ curl http://localhost:5000/api/documents/:document_id/apply_operations \
  -H "Authorization: Token token=<secret token>" \
  -F "operations=<operations.json" \
  -F "5ce11b7c-0726-48a2-a493-1cf4f92f26c5=@imported.pdf;type=application/pdf"

Response

Copy
1
2
3
4
5
6
HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": {"sourcePdfSha256": "...", "title": "...", "passwordProtected": ..., "storage": {"type": "built-in"}}
}

As you can pass more than one importDocument operation, it’s necessary to assign a unique ID to the name of the PDF attachment so that it can be referenced in the corresponding operation’s body.

To target a specific Instant layer, you can modify the endpoint path from /api/documents/:document_id/apply_operations to /api/documents/:document_id/layers/:layer_name/apply_operations.

Efficiently Copying a Document

It is often useful to be able to create a new document using a previously uploaded PDF file and share it with a different set of users. In order to avoid repeating the upload, PSPDFKit Server provides a copy_document endpoint.

This will copy all layers and their latest annotations from the document, so if annotations were already modified by a user, the copied document will include those changes:

Request

1
2
3
4
5
6
7
POST /api/copy_document
Content-Type: application/json
Authorization: Token token="<secret token>"

{
  "document_id": "abc",
}
Copy
1
2
3
4
5
$ curl http://localhost:5000/api/copy_document \
  -X POST \
  -H "Authorization: Token token=<secret token>" \
  -H "Content-Type: application/json" \
  -d '{"document_id": "abc"}'

Response

1
2
3
4
5
6
7
8
HTTP/1.1 200 OK
Content-Type: application/json

{
   "data": {
      "document_id": <ID of the new document>
   }
}

It’s also possible to pass the ID of the new document:

Request

Copy
1
2
3
4
5
6
7
8
POST /api/copy_document
Content-Type: application/json
Authorization: Token token="<secret token>"

{
  "document_id": "abc",
  "new_document_id": "def"
}
Copy
1
2
3
4
5
$ curl http://localhost:5000/api/copy_document \
  -X POST \
  -H "Authorization: Token token=<secret token>" \
  -H "Content-Type: application/json" \
  -d '{"document_id": "abc", "new_document_id": "def"}'

Response

1
2
3
4
5
6
7
8
HTTP/1.1 200 OK
Content-Type: application/json

{
   "data": {
      "document_id": "def"
   }
}

Common Use Case for Copying a Document

If you want to share a document with multiple users who should not see one another’s annotations, you can use copy_document to create an individual document for each user.

Deleting a Document

To delete a document, use the DELETE method:

Request

1
2
DELETE /api/documents/:document_id
Authorization: Token token="<secret token>"
1
2
3
$ curl http://localhost:5000/api/documents/abc \
   -H "Authorization: Token token=<secret token>" \
   -XDELETE

Response

1
2
3
4
5
HTTP/1.1 200 OK
content-length: 2
cache-control: max-age=0, private, must-revalidate

OK

If the deletion fails, a response with an error field will be returned. For example, when trying to delete a non-existing document, the response looks like this:

Copy
1
2
3
4
5
6
7
8
9
10
HTTP/1.1 404 Not Found
content-length: 41
cache-control: max-age=0, private, must-r
Content-Type: application/json

{
  "error": {
    "reason": "document_not_found"
  }
}

Deleting a document removes the document and all its annotations from the database. It also removes the PDF files and all attachments that are not needed by other documents.

Exporting a Document’s XFDF File

Export the current annotations of a document as an XFDF file:

Request

1
2
GET /api/documents/abc/document.xfdf
Authorization: Token token="<secret token>"
1
2
$ curl "http://localhost:5000/api/documents/abc/document.xfdf" \
   -H "Authorization: Token token=<secret token>"

Response

1
2
3
4
HTTP/1.1 200 OK
Content-Type: application/vnd.adobe.xfdf

<XFDF data>

Exporting a Document’s Instant JSON File

Export the current annotations of a document as an Instant JSON file:

Request

1
2
GET /api/documents/:document_id/document.json
Authorization: Token token="<secret token>"
1
2
$ curl "http://localhost:5000/api/documents/abc/document.json" \
   -H "Authorization: Token token=<secret token>"

Response

1
2
3
4
HTTP/1.1 200 OK
Content-Type: application/json

<JSON data>

Fetching Page Text

You can fetch all text contained in a page via the /pages/:page_index/text endpoint:

Request

1
2
GET /api/documents/:document_id/pages/:page_index/text
Authorization: Token token="<secret token>"
1
2
$ curl http://localhost:5000/api/documents/abc/pages/1/text \
   -H "Authorization: Token token=<secret token>"

Response

If a document with the given ID exists, the server will return an HTTP response with the status 200 and the following JSON payload:

Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
HTTP/1.1 200 OK
Content-Type: application/json

{
  "textLines": [
    {
        "contents": "Demo",
        "height": 43.73602294921875,
        "left": 502.89151000976562,
        "top": 108.1837158203125,
        "width": 82.712005615234375
    }
  ]
}

If there’s no such document, an HTTP response with the status 404 will be returned:

1
2
HTTP/1.1 404 Not Found
Content-Type: application/json

If the page index is invalid or out of bounds, an HTTP response with the status 404 will be returned:

1
2
3
4
HTTP/1.1 404 Not Found
Content-Type: application/json

Parameter 'page_index' is invalid or out of bounds.

Fetching Highlighted Page Text

You can fetch all highlighted text contained in a page via the /pages/:page_index/highlighted endpoint. Highlighted text refers to all text that is highlighted via one of the text markup annotations like underline, strikethrough, or highlight.

Please note that this is an approximation, and highlighted text might not always represent the text in the document exactly:

Request

1
2
GET /api/documents/:document_id/pages/:page_index/highlighted
Authorization: Token token="<secret token>"
1
2
$ curl http://localhost:5000/api/documents/abc/pages/1/highlighted \
   -H "Authorization: Token token=<secret token>"

Response

If a document with the given ID exists, the server will return an HTTP response with the status 200 and the following JSON payload:

Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
HTTP/1.1 200 OK
Content-Type: application/json

{
    "data": [
      {
        "annotation": {
          "id": ...,
          "content": {..},
          ..
        }
        "text": "This is a sample PDF document used to show the functionality of \r\n."
      }
    ]
}

If there’s no such document, an HTTP response with the status 404 will be returned:

1
2
HTTP/1.1 404 Not Found
Content-Type: application/json

If the page index is invalid or out of bounds, an HTTP response with the status 404 will be returned:

1
2
3
4
HTTP/1.1 404 Not Found
Content-Type: application/json

Parameter 'page_index' is invalid or out of bounds.

Prerendering a Document

You can now let PSPDFKit Server render and cache documents ahead of time via the prerender endpoint. This speeds up loading times when opening documents via PSPDFKit for Web. The rendering will be done asynchronously, and future clients asking for the document will receive the already rendered and cached pages. For more details about how PSPDFKit Server caches work, please check out our Cache guide:

Request

1
2
POST /api/documents/abc/prerender
Authorization: Token token="<secret token>"
1
2
3
$ curl http://localhost:5000/api/documents/:document_id/prerender \
   -X POST \
   -H "Authorization: Token token=<secret token>"

Response

If a document with the given ID exists, the server will immediately return an HTTP response with the status 200. Note that this doesn’t mean that all pages are prerendered, but only that the process of prerendering has successfully started:

1
2
HTTP/1.1 200 OK
Content-Type: application/json

If there’s no such document, an HTTP response with the status 404 will be returned:

1
2
HTTP/1.1 404 Not Found
Content-Type: application/json

It’s also possible to customize prerendering by passing the following options:

Request

Copy
1
2
3
4
5
$ curl http://localhost:5000/api/documents/:document_id/prerender \
   -X POST \
   -H "Authorization: Token token=<secret token>" \
   -H "Content-Type: application/json" \
   -D '{"scales": [1,2,4,6,8,12,16], "start_page": 0, "end_page": 10}'

Notes:

  • You can add as few or as many values in “scales” as you want as long as they are the values listed above.
  • If the end page value is higher than the number of pages in the PDF, it will automatically be adjusted.

Response

If a document with the given ID exists, the server will immediately return an HTTP response with the status 200. Note that this doesn’t mean that all pages are prerendered, but only that the process of prerendering has successfully started:

1
2
HTTP/1.1 200 OK
Content-Type: application/json

If there’s no such document, an HTTP response with the status 404 will be returned:

1
2
HTTP/1.1 404 Not Found
Content-Type: application/json

If the parameters are invalid (e.g. a non-integer page number or a non-allowed scale value), an HTTP response with the status 422 will be returned:

1
2
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json

Fetching Document Outlines

You can fetch the outline (table of contents) of a document via the outline.json endpoint:

Request

1
2
GET /api/documents/abc/outline.json
Authorization: Token token="<secret token>"
1
2
3
$ curl http://localhost:5000/api/documents/:document_id/outline.json \
   -X POST \
   -H "Authorization: Token token=<secret token>"

Response

If a document with the given ID exists, the server will return an HTTP response with the status 200 and the following JSON payload:

Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": {
    "outline": [
      {
        "action": {
          "pageIndex": 0,
          "type": "goTo"
        },
        "isExpanded": true,
        "level": 0,
        "title": "Page 1",
        "type": "pspdfkit/outline-element"
      }
    ]
  }
}

If there’s no such document, an HTTP response with the status 404 will be returned:

1
2
HTTP/1.1 404 Not Found
Content-Type: application/json

Searching in a Document

You can search for text in documents by providing the following parameters:

  • q — This is for the search query. Make sure the text you want to search for is encoded for URLs and has a minimum of three characters.
  • (optional) start — This is the page index from where you want to start the search (default: 0).
  • (optional) limit — This is the number of pages you want to search for (default: page count of the document).

Request

1
2
GET /api/documents/abc/search?q=pspdfkit&start=0&limit=10
Authorization: Token token="<secret token>"
Copy
1
2
$ curl http://localhost:5000/api/documents/:document_id/search?q=pspdfkit&start=0&limit=10 \
   -H "Authorization: Token token=<secret token>"

Response

If a document with the given ID exists, the server will return an HTTP response with the status 200 and the following JSON payload:

Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
HTTP/1.1 200 OK
Content-Type: application/json
 {
  "data": [
    {
      "pageIndex": 0
      "previewText": "PSPDFKIT FOR WEB Demo PDFs"
      "rangeInPreview": [2, 3]
      "rectsOnPage": [[48.45750427246094, 23.53656005859375, 26.207992553710938, 18.5250244140625]]
      "isAnnotation": false
    }
  ]
 }

The data is structured as follows:

  • pageIndex — This is the page index where the text is.
  • previewText — This is the surrounding text of the search query.
  • rangeInPreview — This is the location and length of the search query in the preview text. The first element is the location (character position) within the preview text, and the second element is the length of the query text itself.
  • rectsOnPage — This is the position and bounding box of the text in page coordinates [left, top, width, height].
  • isAnnotation — This is always false, for now. Searching for annotation content is not yet supported.

When there is an issue with the request (for example, when q is missing) you will receive a JSON response with an error:

1
2
3
4
5
6
7
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
  "error": {
    "reason": "Missing required URL parameter 'q'."
  }
}

If there’s no such document, an HTTP response with the status 404 will be returned:

1
2
HTTP/1.1 404 Not Found
Content-Type: application/json

Fetching Document Information

You can fetch information about page count, the dimensions of pages, and permissions of a document via the document_info endpoint:

Request

1
2
GET /api/documents/abc/document_info
Authorization: Token token="<secret token>"
1
2
$ curl http://localhost:5000/api/documents/:document_id/document_info \
   -H "Authorization: Token token=<secret token>"

Response

If a document with the given ID exists, the server will return an HTTP response with the status 200 and the following JSON payload:

Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
HTTP/1.1 200 OK
Content-Type: application/json
 {
  "data": {
    {
      "pageCount": 10,
      "pages" : [
        {
          "height": 792,
          "pageIndex": 0,
          "pageLabel": "Frontpage",
          "rotation": 0,
          "width": 612
        },
        ...
      ],
      "permissions": {
        "printing": true,
        ...
      },
      "title": "Document title"
    }
  }
}

If there’s no such document, an HTTP response with the status 404 will be returned:

1
2
HTTP/1.1 404 Not Found
Content-Type: application/json

Persisting the Default Layer as a New Document

To persist the current content of the default layer as a new document, send a POST request to the /copy_with_instant_json endpoint. This will create a new PDF containing the latest annotations of the default layer, import the uploaded Instant JSON, and persist the resulting PDF as a new document. The response will include the document_id of the new document:

Request

1
2
3
POST /api/documents/:document_id/copy_with_instant_json
Content-Type: application/json
Authorization: Token token="<secret token>"
Copy
1
2
3
$ curl -X POST http://localhost:5000/api/documents/:document_id/copy_with_instant_json \
   -H "ContentType: application/json" \
   -H "Authorization: Token token=<secret token>"

Response

Copy
1
2
3
4
5
6
7
8
9
10
11
HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": {
    "document_id": ...,
    "errors": [],
    "sourcePdfSha256": ...,
    "title": "..."
  }
}

Importing Instant JSON and Downloading the Resulting PDF File

To import an Instant JSON file and download the resulting PDF, you can POST a multipart/form request including an instant.json file. This will create a new PDF containing the latest annotations of the default layer, import the uploaded Instant JSON, and respond with the resulting PDF. Please note that this action will not modify the existing document, but rather only import the Instant JSON on a temporary file that will be downloaded in the process:

Request

Copy
1
2
3
4
5
6
7
8
9
POST /api/documents/:document_id/pdf_with_instant_json
Content-Type: multipart/form-data; boundary=customboundary
Authorization: Token token="<secret token>"
--customboundary
Content-Disposition: form-data; name="instant.json"; filename="instant.json"
Content-Type: application/json

<instant.json data>
--customboundary--

Response

1
2
3
4
HTTP/1.1 200 OK
Content-Type: application/pdf

<PDF data>

Importing Instant JSON and Persisting the Resulting PDF File

To import an Instant JSON file and persist the resulting PDF as a new document, you can POST a multipart/form request including an instant.json file. This will create a new PDF containing the latest annotations of the default layer, import the uploaded Instant JSON, and persist the resulting PDF as a new document. The response will include the document_id of the new document:

Request

Copy
1
2
3
4
5
6
7
8
9
POST /api/documents/:document_id/copy_with_instant_json
Content-Type: multipart/form-data; boundary=customboundary
Authorization: Token token="<secret token>"
--customboundary
Content-Disposition: form-data; name="instant.json"; filename="instant.json"
Content-Type: application/json

<instant.json data>
--customboundary--
Copy
1
2
3
4
5
$ curl http://localhost:5000/api/documents/:document_id/pdf_with_instant_json \
   -o document-with-imported-data.pdf \
   -X POST \
   -H "Authorization: Token token=secret" \
   -F "instant.json=@instant.json;type=application/json"

Response

Copy
1
2
3
4
5
6
7
8
9
10
11
HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": {
    "document_id": ...,
    "errors": [],
    "sourcePdfSha256": ...,
    "title": "..."
  }
}

Accessing Password-Protected Documents

To access password-protected documents via the upstream API, you need to include the pspdfkit-pdf-password header in all requests that work on a password-protected document. The exception to this is uploading or deleting a document or accessing the properties of a document via the /properties endpoint.