End-to-end examples. Each has what it does, a prompt to paste into Claude Code, Cursor or another AI coding agent, and the code. Run them with an hr_test_ key first – the sandbox never sends e-mail.
Uploads your pitch deck once, creates one tracked link per investor (each viewer verifies their e-mail, download blocked), and tells you who …
Fills a data room from a local folder (one room folder per subfolder) and invites the guests. Create the room and switch …
A small webhook receiver: verifies HelpRange's signature, ignores duplicates and posts "ACME - Anna (anna@acme.com) opened proposal.pdf" to a Slack incoming webhook …
Uploads your pitch deck once, creates one tracked link per investor (each viewer verifies their e-mail, download blocked), and tells you who opened it and for how long. HelpRange does not e-mail the links through the API – you send each investor their own link.
Using the HelpRange REST API (docs: https://www.helprange.com/developers/llms-full.txt, key in HELPRANGE_API_KEY), write a script that uploads ./deck.pdf, creates one share link per row of investors.csv (columns name,email) with label "<name>", require_email true and allow_download false, and writes name,email,url to links.csv. Then add a command that lists who opened the deck (GET /api/v2/views filtered by document_id) with seconds read.In HelpRange: create a share link for my document "deck.pdf" for each of these investors – Anna (Fund A), Ben (Fund B) – labelled with their name, e-mail required, no download. Later: who opened deck.pdf this week and how long did they read?MCP tools used: upload_file, create_link, list_recent_views, get_document_stats. Connect your AI tool.
import csv, os, requests
HR = "https://www.helprange.com/api/v2"
H = {"Authorization": f"Bearer {os.environ['HELPRANGE_API_KEY']}"}
# 1. upload the deck once
with open("deck.pdf", "rb") as f:
deck = requests.post(f"{HR}/files", headers=H, files={"file": f}, timeout=120).json()
# 2. one tracked link per investor (label = who it is for; unique per document)
with open("investors.csv") as src, open("links.csv", "w", newline="") as dst:
out = csv.writer(dst)
out.writerow(["name", "email", "url"])
for row in csv.DictReader(src):
r = requests.post(f"{HR}/files/{deck['id']}/links", headers=H, timeout=30,
json={"label": row["name"], "require_email": True, "allow_download": False})
r.raise_for_status()
out.writerow([row["name"], row["email"], r.json()["url"]]) # send each investor their url
# 3. who read it (or get it pushed: the document.opened webhook)
for v in requests.get(f"{HR}/views", headers=H, timeout=30).json():
if v["document_id"] == deck["id"]:
print(v["link_label"], v["viewer"], v["seconds_read"], "s", v["opened_at"])
stats = requests.get(f"{HR}/documents/{deck['id']}", headers=H, timeout=30).json() # time per pageEndpoints: /api/v2/files, /api/v2/files/{file_id}/links, /api/v2/views, /api/v2/documents/{file_id} – details in the API reference.
Fills a data room from a local folder (one room folder per subfolder) and invites the guests. Create the room and switch on its NDA once in the HelpRange panel (or start from a data room template) – the API has no "create data room" or "set NDA" endpoint yet. Every invited guest then accepts the NDA before seeing a document.
Using the HelpRange REST API (docs: https://www.helprange.com/developers/llms-full.txt, key in HELPRANGE_API_KEY), write a script that takes a data room id and a local folder: check the room has an NDA (GET /api/v2/data-rooms/{id}, nda_required), turn room folders on, create one room folder per subfolder, upload every file, add the uploaded documents to their room folder, then invite every e-mail in guests.txt. Test it with an hr_test_ key first.In my HelpRange data room "Project Falcon": turn on folders, create the folders Legal, Financials and Commercial, and add the documents from my folder "Falcon DD" to the right folder by their names. Then list the room folders with their documents.MCP tools used: get_data_room, set_room_folders_enabled, create_room_folder, add_room_documents, list_room_folders. Connect your AI tool.
import os, pathlib, requests
HR = "https://www.helprange.com/api/v2"
H = {"Authorization": f"Bearer {os.environ['HELPRANGE_API_KEY']}"}
ROOM, SRC = 10, pathlib.Path("falcon-dd") # the room you created in the panel, with its NDA switched on
room = requests.get(f"{HR}/data-rooms/{ROOM}", headers=H, timeout=30).json()
assert room["nda_required"], "Switch on the room's NDA in HelpRange first"
requests.post(f"{HR}/data-rooms/{ROOM}", headers=H, json={"folders_enabled": True}, timeout=30).raise_for_status()
for sub in sorted(p for p in SRC.iterdir() if p.is_dir()):
folder = requests.post(f"{HR}/data-rooms/{ROOM}/folders", headers=H, json={"name": sub.name}, timeout=30).json()
ids = []
for path in sorted(p for p in sub.iterdir() if p.is_file()):
with path.open("rb") as f:
ids.append(requests.post(f"{HR}/files", headers=H, files={"file": f}, timeout=300).json()["id"])
if ids: # up to 100 per request
requests.post(f"{HR}/data-rooms/{ROOM}/documents", headers=H, timeout=60,
json={"document_ids": ids, "folder_id": folder["id"]}).raise_for_status()
for email in pathlib.Path("guests.txt").read_text().split():
r = requests.post(f"{HR}/data-rooms/{ROOM}/guests", headers=H, json={"email": email}, timeout=30)
print(email, r.status_code, r.json().get("already_a_guest")) # 201 invited, 200 already a guestEndpoints: /api/v2/data-rooms/{data_room_id}, /api/v2/files, /api/v2/data-rooms/{data_room_id}/folders, /api/v2/data-rooms/{data_room_id}/documents, /api/v2/data-rooms/{data_room_id}/guests – details in the API reference.
A small webhook receiver: verifies HelpRange's signature, ignores duplicates and posts "ACME - Anna (anna@acme.com) opened proposal.pdf" to a Slack incoming webhook – for your own wording, filters or channel routing. No code needed for the plain version: paste a Slack incoming webhook URL in Settings → Integrations and HelpRange posts there itself.
Write a minimal Flask app with POST /helprange-webhook that verifies the HelpRange-Signature header (HMAC-SHA256 of "<t>.<raw body>" with HELPRANGE_WEBHOOK_SECRET, 5-minute tolerance, docs: https://www.helprange.com/developers/webhooks), skips event ids it has already seen, and for document.opened events posts "<link> (<viewer>) opened <document>" to the Slack incoming webhook in SLACK_WEBHOOK_URL. Answer 200 quickly.import hashlib, hmac, json, os, time
import requests
from flask import Flask, request
app = Flask(__name__)
SECRET = os.environ["HELPRANGE_WEBHOOK_SECRET"] # whsec_… (Settings → Integrations)
SLACK = os.environ["SLACK_WEBHOOK_URL"]
seen = set() # use your database in production
def verified(raw: bytes, header: str) -> bool:
parts = [p.split("=", 1) for p in (header or "").split(",") if "=" in p]
t = next((v for k, v in parts if k == "t"), None)
if t is None or not t.isdigit() or abs(time.time() - int(t)) > 300:
return False
expected = hmac.new(SECRET.encode(), t.encode() + b"." + raw, hashlib.sha256).hexdigest()
return any(k == "v1" and hmac.compare_digest(v, expected) for k, v in parts)
@app.post("/helprange-webhook")
def helprange_webhook():
raw = request.get_data()
if not verified(raw, request.headers.get("HelpRange-Signature")):
return "bad signature", 400
event = json.loads(raw)
if event["id"] in seen: # at-least-once delivery: the same id can arrive twice
return "", 200
seen.add(event["id"])
if event["event"] == "document.opened":
d = event["data"]
requests.post(SLACK, json={"text": f"{d['link']} ({d['viewer']}) opened {d['document']}"}, timeout=5)
return "", 200Event format, headers and retries: webhooks.