dataroom.dev

Use case

A fundraising data room you can call from code: investor outreach, per-investor links, engagement scoring

Replace the spreadsheet-of-shared-Drive-links with a programmable fundraising data room: per-investor watermarks, engagement scoring back into your CRM, automatic follow-up triggers. Walkthrough uses the open-source Papermark API.

Read full docsCreate a fundraising data room with the API
May 18, 2026·8 min read·By dataroom.dev

Most founders running a seed-through-Series-C round share their pitch deck and financials with somewhere between 30 and 120 investors over 6 to 16 weeks. The default tooling for this. Google Drive shared links, DocSend trial accounts, plain email attachments, the occasional Notion page. Breaks in predictable ways once the round runs beyond about a dozen recipients:

  1. You can't actually tell which investors opened the deck. A "view" in Google Drive is anyone with the URL who happened to click; you can't attribute it to a specific person without forcing a sign-in that VCs refuse to do.
  2. "Forwarded by mistake" leaks have no audit trail. The deck shows up in the inbox of an associate at a fund you never pitched, and you have no idea which of the 47 originals it came from.
  3. The link policy is uniform across all recipients. Same password, same expiry, same download permission. Even though Sequoia and your high-school friend's angel syndicate probably deserve different gating.
  4. When the round closes, you can't cleanly revoke access to everyone at once without sending a "we're rotating the link, please use this new URL" email that screams unprofessional.
  5. Engagement signal is invisible. The 11 VCs who actually read past slide 3 are indistinguishable from the 36 who opened the deck for 14 seconds and never returned.

A programmable fundraising data room fixes all five problems and adds something useful in the process: investor engagement becomes a queryable data source that drives your outreach prioritization. The funds who spent 18 minutes on slide 9 of the financial appendix are not the same funds who opened the deck for 30 seconds and bounced. Knowing the difference shortens the round.

The fundraising dataroom shape

A round-ready dataroom is small but opinionated. Typical contents:

  1. The deck: pDF, ideally also a public-shareable Notion or Pitch export for the people who hate downloads.
  2. One-pager / TLDR: for VCs who scan in 90 seconds and decide whether to take the meeting.
  3. Financial model: excel or Google Sheets export. Three-statement model with monthly granularity for the next 18 months, annual for the following 3 years.
  4. Cap table snapshot: pre and post-round, with the option pool waterfall shown. Carta export works.
  5. Founder LinkedIn bios + résumés: at least the founding team. For technical founders, GitHub or research links help.
  6. Reference letters: optional but useful for warm intros, especially at seed.
  7. Press / customer logos: optional, only if they're real and verifiable.
  8. Data security / SOC 2 / DPA: for B2B founders selling to enterprises, where the diligence depth increases.
  9. Existing investor list: useful for the social-proof play; sometimes left out deliberately for competitive reasons.
  10. Hiring plan + org chart: series A+ specifically, where the GTM hiring strategy is itself part of the diligence.

For seed and Series A, that's a single dataroom with a flat structure or two folders (Core and Deep Dive). The interesting part is what you do with the links.

Provision the room

One-time setup. Run this once at the start of the round and you're done with the boilerplate:

papermark datarooms create --name "Acme — Seed Round" --json
# → dr_acme_seed

Bulk upload:

for f in deck.pdf model.xlsx cap-table.pdf onepager.pdf data-security.pdf; do
  papermark documents upload "$f" --dataroom dr_acme_seed
done

Or do it in one Python script that handles the upload, retries on flaky networks, and prints the room URL when it's done:

from papermark import Papermark
import os

pm = Papermark()
room = pm.datarooms.create(name="Acme — Seed Round")

documents = [
    "deck.pdf", "model.xlsx", "cap-table.pdf", "onepager.pdf",
    "data-security.pdf", "founder-bios.pdf", "customer-logos.pdf",
]
for f in documents:
    if os.path.exists(f):
        pm.documents.upload(file=open(f, "rb"), dataroom_id=room.id)

print(f"Room ready: https://app.papermark.com/datarooms/{room.id}")

This takes 10-30 seconds end-to-end for a typical seed-round document set (15-40 MB total).

Per-investor links: the pattern that actually matters

If you only remember one thing from this article: one share link per investor, watermarked with the investor's identity. Not one link that everyone shares. The per-investor pattern gives you four wins at once: engagement attribution, leak attribution, per-investor policy, and clean revocation.

import { Papermark } from "@papermark/sdk";

const pm = new Papermark();

// Pull from your CRM — typically Notion, Affinity, HubSpot, or Airtable
const investors = await crm.query(
  "WHERE stage = 'seed' AND status IN ('introduced', 'committed', 'considering')",
);

for (const inv of investors) {
  const link = await pm.links.create({
    dataroomId: "dr_acme_seed",
    requireEmail: true,
    allowDownload: false,
    watermark: `${inv.name} · ${inv.fund} · {{timestamp}}`,
    // Deliberately no password — VCs hate friction, and the email gate
    // already gives you attribution
    expiresAt: addDays(new Date(), 45),
    notes: `Generated for ${inv.email} on ${new Date().toISOString()}`,
  });

  await crm.updateContact(inv.id, {
    dataroomUrl: link.url,
    dataroomLinkId: link.id,
    dataroomMintedAt: new Date(),
  });
}

For a list of 60 investors, this takes about 12 seconds to run and writes 60 distinct URLs into your CRM. Your outreach email gets a per-investor URL via merge field. Each visit is attributable to a known investor by name and fund. The result feels like 1:1 outreach because, mechanically, it is.

Engagement scoring

This is where the programmable VDR earns its keep. Pull view events back into your CRM as engagement signals on a daily or weekly schedule:

const investors = await crm.query(
  "WHERE round = 'seed' AND dataroomLinkId IS NOT NULL"
);

for (const inv of investors) {
  const analytics = await pm.links.analytics(inv.dataroomLinkId);

  await crm.updateContact(inv.id, {
    deck_opens: analytics.view_count,
    total_seconds_on_deck: analytics.total_duration_seconds,
    deepest_page_reached: analytics.max_page,
    last_viewed_at: analytics.last_view_at,
    days_since_view: daysSince(analytics.last_view_at),
    engagement_score: computeScore(analytics),
  });
}

A simple but useful engagement score:

function computeScore(a: LinkAnalytics): "cold" | "warm" | "hot" | "ice" {
  // Hot: returned more than once, spent 10+ minutes total
  if (a.view_count >= 2 && a.total_duration_seconds >= 600) return "hot";

  // Warm: spent 2+ minutes, reached past slide 5
  if (a.total_duration_seconds >= 120 && a.max_page >= 5) return "warm";

  // Cold: opened but bounced quickly
  if (a.view_count >= 1) return "cold";

  // Ice: never opened — your subject line, your timing, or your relationship needs work
  return "ice";
}

Hot investors are the ones who came back twice and spent 10+ minutes total. They're the leads you push for a follow-up meeting this week. Empirical observation from founders running rounds with this scoring in place: hot leads close at 4-6x the rate of warm leads, and warm leads close at 8-12x the rate of cold leads. The signal is strong enough to drive real prioritization.

Real-time hot-lead alerts

Webhook view events directly to Slack so the founder/CEO knows the second a target VC reads the deck. This is the single highest-leverage instrumentation you can put on the fundraising process:

// /api/papermark-webhook/route.ts
import { headers } from "next/headers";
import { verifyWebhook } from "@papermark/sdk";

export async function POST(req: Request) {
  const sig = headers().get("X-Papermark-Signature")!;
  const body = await req.text();

  if (!verifyWebhook(body, sig, process.env.PAPERMARK_WEBHOOK_SECRET!)) {
    return new Response("invalid signature", { status: 401 });
  }

  const evt = JSON.parse(body);
  if (evt.type !== "view.completed") return new Response("ok");

  // Look up the investor by linkId
  const investor = await crm.lookupByLinkId(evt.data.link_id);
  if (!investor) return new Response("ok"); // unknown — skip

  // Filter to signal-worthy events
  const signal =
    investor.is_target &&
    evt.data.duration_seconds >= 60 &&
    evt.data.pages.length >= 3;

  if (!signal) return new Response("ok");

  await slack.post({
    channel: "#fundraising",
    text:
      `🔥 *${investor.name}* (${investor.fund}) just finished the deck — ` +
      `${Math.round(evt.data.duration_seconds / 60)}m, ${evt.data.pages.length} pages, ` +
      `country: ${evt.data.visitor.country}`,
  });

  return new Response("ok");
}

The pattern that works in practice: a high-signal channel (#fundraising-hot) that pages the founder for events worth interrupting on, plus a low-signal channel (#fundraising-firehose) that captures every view for retrospective analysis.

Close-of-round cleanup

When the round closes, revoke the dataroom in one call. All outstanding links return 410 Gone on next request. The audit log stays queryable indefinitely.

papermark datarooms archive dr_acme_seed

The "archive" operation is reversible for 90 days (useful if you decide to re-open the round to a late-arriving investor) and permanent after that.

A note on "free DocSend"

Founders often ask: "Why not just use DocSend's free tier?" Three answers worth knowing:

  1. DocSend doesn't really have a permanent free tier. What's offered is a 14-day Advanced trial; after that you fall back to a Limited Trial plan capped at 5 stored documents and 10 links, with no analytics, no eSign, and no Spaces/Data Rooms. That covers showing one PDF to one investor, not a real fundraising round.
  2. DocSend has no public API. You see analytics in the dashboard, but you can't pipe them into your CRM, score investors programmatically, alert in Slack on engagement, or build a custom heatmap. The whole reason to instrument the deck is to act on the signal in real time. The dashboard gives you the data; the API gives you the leverage. DocSend has the first; only API-first platforms give you the second.
  3. DocSend doesn't have an MCP server. When you want your sales/fundraising agent (Claude, GPT, whatever) to manage outreach autonomously. Drafting follow-ups based on engagement, triaging the pipeline. The agent needs tool access. DocSend doesn't ship those tools.
  4. Papermark's free tier is more useful. Verified at the time of writing: 1 team member, 50 documents, 50 links, 30-day analytics retention, page-by-page analytics. Enough for a typical seed round's document set if not the whole pipeline. Upgrade to Pro at €24/month or Business at €59/month when you outgrow it.

The honest tradeoffs

Switching off DocSend (or off email attachments) onto an API-driven flow has costs:

  1. Brand recognition. "I'll send you a DocSend" is a sentence VCs understand without explanation. A custom-domain Papermark link looks the same to them. But a papermark.com/v/abc URL needs the occasional one-line explanation.
  2. Setup time. First-time setup of the scripts above takes 1-3 hours. After that, every subsequent round is reusable infrastructure.
  3. Maintenance. When the API ships a new field or deprecates an old one, your scripts need updating. The OpenAPI spec makes this cheap (1-2 hours per breaking change historically), but it's not zero.

For founders running their first round, DocSend's UI is faster. For founders running their second, third, or N-th round, or who already think in terms of CRM workflows, the API approach is dramatically better.

See also

More in Use case