A data room API turns confidential document distribution into a programmable primitive: provision rooms from your CRM, mint per-recipient watermarked links from a script, stream view events into your warehouse, and revoke everything on close with one call. This guide is the end-to-end tour for engineers: auth, the data model, every major operation with runnable examples, webhooks, and the patterns that matter in production.
The worked example throughout is the Papermark API at https://api.papermark.com/v1. It is the option this site recommends for API-first data room work, for reasons you can verify rather than take on faith: the full surface is public (43 operations across 6 resources, OpenAPI 3.1 spec), the engine behind it is open source, and the same API serves the hosted service and self-hosted deployments, so nothing here locks you in. Where behavior details matter, the canonical source of truth is papermark.com/docs.
Fundamentals
The API is conventional REST: JSON bodies, bearer authentication, resource-shaped URLs, standard status codes. If you have used the Stripe or GitHub APIs, nothing here will surprise you.
curl -sS https://api.papermark.com/v1/datarooms \
-H "Authorization: Bearer $PAPERMARK_TOKEN"
Two ways to authenticate:
- API tokens (
pm_live_…), minted at app.papermark.com/settings/tokens. Right for servers, CI, and cron. Store them in your secret manager; scope them to the narrowest team or workspace that the job needs. - OAuth 2.1 device flow, right for CLI tools and anything interactive where a human can approve a browser prompt. Grants are individually revocable and attributed in the audit log. Walkthrough in the device flow guide.
The data model in one pass
Six resources, and every workflow is a composition of them:
| Resource | What it is | Typical operations |
|---|---|---|
| Dataroom | Container for one deal, raise, or audit | create, list, update, delete, analytics |
| Document | A file plus version history | upload, list, versioning, delete |
| Folder | Hierarchy within a room | create, move, update, delete |
| Link | Access policy with a URL | create, update, delete, list views |
| Visitor | An identified external party | list, get, view history |
| View | One visit, with per-page timing | list, analytics rollups |
The design decision that makes the rest of the API composable: documents exist independently of datarooms (upload once, attach anywhere), and links carry the policy (a room has many links, each with its own expiry, watermark, and gating). Model your own integration around those two facts.
Provision a room
API="https://api.papermark.com/v1"
DR_ID=$(curl -sS -X POST "$API/datarooms" \
-H "Authorization: Bearer $PAPERMARK_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Series B — diligence", "description": "Confidential"}' \
| jq -r '.data.id')
for folder in Financials Legal "Cap Table" Product; do
curl -sS -X POST "$API/datarooms/$DR_ID/folders" \
-H "Authorization: Bearer $PAPERMARK_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"name\": \"$folder\"}"
done
Or with the TypeScript SDK, which is generated from the OpenAPI spec and fully typed:
import { Papermark } from "@papermark/sdk";
const pm = new Papermark(); // reads PAPERMARK_TOKEN
const room = await pm.datarooms.create({
name: "Series B — diligence",
description: "Confidential",
});
for (const name of ["Financials", "Legal", "Cap Table", "Product"]) {
await pm.datarooms.folders.create(room.id, { name });
}
Upload documents
Small files go up as multipart form data. Large files use presigned uploads: request an upload URL, PUT the bytes directly to object storage, then confirm. The presigned path keeps large transfers off the API tier and is the right default above a few tens of megabytes; the full pattern, including parallelism and retry handling, is covered in presigned uploads.
curl -sS -X POST "$API/documents" \
-H "Authorization: Bearer $PAPERMARK_TOKEN" \
-F "file=@financial-model.pdf" \
-F "dataroom_id=$DR_ID"
Documents are versioned: uploading a new version keeps every link pointing at the same document while viewers get the latest content, and the old versions stay retrievable for the audit trail. In a live deal this is the difference between "re-send new links to 20 bidders" and "the room is simply current."
Mint links: where the policy lives
A link is a policy object. Everything that controls access hangs off it:
curl -sS -X POST "$API/links" \
-H "Authorization: Bearer $PAPERMARK_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"dataroom_id": "'"$DR_ID"'",
"name": "Acme Capital — round 2",
"email_protected": true,
"allow_download": false,
"expires_at": "2026-08-15T00:00:00Z",
"enable_watermark": true,
"watermark_text": "{{email}} · {{date}}"
}'
One link per recipient is the pattern to internalize: it is what makes engagement attribution, leak attribution, and per-recipient revocation possible. The reasoning and the bulk-minting code are in per-recipient share links. Field names above follow the canonical docs; treat papermark.com/docs/api as the source of truth for the exact schema.
Read the analytics
Every view is recorded with visitor identity (via the email gate), per-page dwell time, IP, and timestamps. The rollups answer the questions deal teams actually ask:
# Who has viewed, and how much
curl -sS "$API/datarooms/$DR_ID/analytics" \
-H "Authorization: Bearer $PAPERMARK_TOKEN"
# One visitor's full history
curl -sS "$API/visitors/$VISITOR_ID/views" \
-H "Authorization: Bearer $PAPERMARK_TOKEN"
Because the output is structured JSON rather than a dashboard, you can compute the metrics your process cares about: total engaged minutes per bidder, which pages of the financial model get the most attention, who has gone quiet for a week. The audit log guide covers schema details and warehouse export.
Webhooks
Polling analytics works for digests; webhooks are the push path. Register an endpoint at app.papermark.com/settings/webhooks and you receive events for views, downloads, and link activity as they happen. Verify the signature on every delivery, respond 200 quickly, and process async: the standard webhook hygiene applies. A complete worked receiver, including Slack routing, is in view events to Slack.
Errors and production behavior
The API uses conventional status codes: 401 for a bad or revoked token, 403 for a scope miss, 404 for a resource outside your workspace, 422 for validation failures with a field-level error body, 429 with a Retry-After header when you exceed rate limits.
Production checklist:
- Retry idempotently. Retry
429and5xxwith exponential backoff and jitter. For creates, check-then-create or use client-side deduplication keys so a retried request cannot double-provision a room. - Page everything. List endpoints paginate; loop the cursor to completion before acting on "all links" or "all documents," or your hygiene sweep silently misses page two.
- Verify bulk operations. After a 400-document upload, list and count. Distributed uploads fail partially; scripts that assume success corrupt the room's completeness silently.
- Scope tokens per job. The CI job that uploads board decks does not need delete permissions on deal rooms. Narrow tokens turn a leaked credential from an incident into an inconvenience.
- Keep the audit log external. Stream view events to your warehouse from day one. When the post-close dispute arrives in 2029, you want the log in your infrastructure, on your retention policy.
Beyond raw REST
The same 43-operation surface is exposed three more ways, so pick the interface per job rather than per platform: typed SDKs for TypeScript and Python for application code, the papermark CLI for shell scripts and CI, and the MCP server when the operator is an AI agent rather than a program — covered in depth in MCP data rooms: the complete guide. Everything ends up at the same API with the same tokens and the same audit log.
See also
More in Engineering
What is a virtual data room: the complete developer guide
A from-first-principles guide to virtual data rooms for engineers: the six core primitives, server-side access controls, watermarking, page-level audit logs, hosted vs self-hosted deployment, and how to pick a platform you can drive with code.
OAuth 2.1 device flow with PKCE for virtual data room APIs: a complete walkthrough
How OAuth 2.1 device authorization grant works in practice, how a modern dataroom API implements it, and how to add device-flow login to a CLI or distributed tool you are building: worked example uses the Papermark API.
Large file uploads to a virtual data room API: the S3 presigned URL flow
How presigned-URL uploads work, why they exist, when to use them instead of multipart POST, and a complete worked example with chunked retry and multipart-upload support for files over 5GB: implementation against the Papermark API.