API Documentation
Manage your documents, leads, viewers, and analytics programmatically. Build integrations with your CRM, Slack, or any tool that accepts webhooks.
Looking for step-by-step integration guides? See Integration Guides →
Authentication
Generate an API key from your settings. Include it as a Bearer token in all requests:
curl https://sharedoc.co/api/v1/documents \
-H "Authorization: Bearer bd_live_your_key_here"
API keys are shown once on generation. Store them securely. You can revoke and regenerate keys from Settings.
Rate Limits
100 requests per minute per API key. Every response includes rate limit headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 97
X-RateLimit-Reset: 1680000060
When rate limited, you'll receive a 429 response. Wait until the reset timestamp before retrying.
Errors
All errors follow a standard format:
{
"error": {
"code": "not_found",
"message": "Document not found"
}
}
| Status | Code | Description |
|---|---|---|
| 400 | bad_request | Invalid parameters or file type |
| 401 | unauthorized | Missing or invalid API key |
| 422 | validation_error | Invalid field value (e.g. gate_page out of range) |
| 404 | not_found | Resource not found |
| 429 | rate_limited | Too many requests |
| 500 | internal_error | Server error |
List Documents
GET /api/v1/documents
Returns all documents for the authenticated user. Supports filtering, search, and sorting.
| Parameter | Default | Description |
|---|---|---|
page | 1 | Page number |
per_page | 20 | Results per page (max 100) |
search | Filter by title (case-insensitive) | |
engagement | Filter by engagement level: high_interest, read, skimmed, opened, not_opened | |
has_leads | Only docs with captured leads (true) | |
since | Filter by created date (ISO 8601, e.g. 2026-04-01) | |
until | Filter by created date (ISO 8601) | |
sort | created_at | Sort by: views, engagement, title |
# List high-interest documents with leads
curl "https://sharedoc.co/api/v1/documents?engagement=high_interest&has_leads=true&sort=views" \
-H "Authorization: Bearer bd_live_your_key_here"
{
"documents": [
{
"id": "uuid",
"title": "Series A Deck",
"short_code": "s-ab12cd",
"url": "https://sharedoc.co/s/ab12cd",
"page_count": 12,
"views": 47,
"unique_viewers": 12,
"leads_count": 5,
"engagement_summary": { "label": "High Interest", "type": "hot" }
}
],
"pagination": { "page": 1, "per_page": 20, "total": 3, "total_pages": 1 }
}
Get Document
GET /api/v1/documents/{short_code}
Get document details and settings.
curl https://sharedoc.co/api/v1/documents/s-ab12cd \
-H "Authorization: Bearer bd_live_your_key_here"
{
"id": "uuid",
"title": "Series A Deck",
"short_code": "s-ab12cd",
"url": "https://sharedoc.co/s/ab12cd",
"page_count": 12,
"original_filename": "series-a-deck.pdf",
"created_at": "2026-04-07T14:30:00Z",
"is_active": true,
"settings": {
"email_gate": true,
"gate_type": "preview",
"gate_page": 3,
"allow_download": true,
"block_free_emails": false,
"password": false,
"notifications_enabled": true
}
}
Get Document Stats
GET /api/v1/documents/{short_code}/stats
Get analytics for a document. Use since and until to filter by date range.
# Stats for the last 7 days
curl "https://sharedoc.co/api/v1/documents/s-ab12cd/stats?since=2026-04-02&until=2026-04-09" \
-H "Authorization: Bearer bd_live_your_key_here"
{
"views": 47,
"unique_viewers": 12,
"total_time_seconds": 3420,
"avg_time_seconds": 285.0,
"avg_completion": 0.72,
"downloads": 3,
"page_analytics": [
{ "page": 1, "views": 47, "avg_time_seconds": 12.0 },
{ "page": 2, "views": 38, "avg_time_seconds": 18.5 }
],
"engagement_breakdown": { "label": "Read", "type": "warm" }
}
Get Document Viewers
GET /api/v1/documents/{short_code}/viewers
Get per-viewer engagement breakdown. See exactly who viewed your document, how much they read, and when they came back. Sorted by engagement level (most engaged first).
curl https://sharedoc.co/api/v1/documents/s-ab12cd/viewers \
-H "Authorization: Bearer bd_live_your_key_here"
{
"viewers": [
{
"viewer_id": "anon_a1b2c3d4",
"email": "jane@acme.com",
"company_domain": "acme.com",
"first_viewed_at": "2026-04-07T09:15:00Z",
"last_viewed_at": "2026-04-09T14:30:00Z",
"visits": 3,
"pages_viewed": 11,
"total_pages": 12,
"completion": 0.92,
"total_time_seconds": 342.5,
"downloaded": true,
"engagement_label": "High Interest"
},
{
"viewer_id": "anon_e5f6g7h8",
"email": null,
"company_domain": null,
"first_viewed_at": "2026-04-08T16:00:00Z",
"last_viewed_at": "2026-04-08T16:02:00Z",
"visits": 1,
"pages_viewed": 3,
"total_pages": 12,
"completion": 0.25,
"total_time_seconds": 45.0,
"downloaded": false,
"engagement_label": "Skimmed"
}
],
"total_viewers": 2
}
Get Document Leads
GET /api/v1/documents/{short_code}/leads
Get leads captured through the email gate.
curl https://sharedoc.co/api/v1/documents/s-ab12cd/leads \
-H "Authorization: Bearer bd_live_your_key_here"
{
"leads": [
{
"email": "jane@acme.com",
"name": "Jane Smith",
"company_domain": "acme.com",
"captured_at": "2026-04-03T09:15:00Z",
"engagement_label": "High Interest"
}
],
"pagination": { "page": 1, "per_page": 20, "total": 5, "total_pages": 1 }
}
Upload Document
POST /api/v1/documents
Upload a PDF and configure settings in a single request. All settings are optional — defaults are applied if omitted.
| Field | Default | Description |
|---|---|---|
file required | PDF file (multipart form data) | |
title | Derived from filename | Document title |
email_gate | true | Require email to view (true/false) |
gate_type | preview | preview (show pages then gate), full (gate immediately), none |
gate_page | 3 | Page to show gate on (1 to page_count) |
allow_download | true | Allow PDF download |
block_free_emails | false | Block Gmail, Yahoo, etc. |
notifications_enabled | true | Email notifications for views |
# Upload with full gate, no downloads
curl https://sharedoc.co/api/v1/documents \
-H "Authorization: Bearer bd_live_your_key_here" \
-F "file=@deck.pdf" \
-F "title=Series A Deck" \
-F "gate_type=full" \
-F "allow_download=false" \
-F "block_free_emails=true"
{
"id": "uuid",
"title": "Series A Deck",
"short_code": "s-ab12cd",
"url": "https://sharedoc.co/s/ab12cd",
"page_count": 12,
"original_filename": "deck.pdf",
"created_at": "2026-04-07T14:30:00Z",
"is_active": true,
"settings": {
"email_gate": true,
"gate_type": "full",
"gate_page": 3,
"allow_download": false,
"block_free_emails": true,
"password": false,
"notifications_enabled": true
}
}
Update Document
PATCH /api/v1/documents/{short_code}
Update document settings. All fields are optional. Only include what you want to change.
curl -X PATCH https://sharedoc.co/api/v1/documents/s-ab12cd \
-H "Authorization: Bearer bd_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"title": "Updated Title", "allow_download": false, "gate_page": 5}'
Delete Document
DELETE /api/v1/documents/{short_code}
Soft delete a document. Returns 204 No Content.
curl -X DELETE https://sharedoc.co/api/v1/documents/s-ab12cd \
-H "Authorization: Bearer bd_live_your_key_here"
Portfolio Analytics
GET /api/v1/analytics/overview
Get analytics across all your documents. See total views, leads, top-performing content, and engagement breakdown. Supports since/until date filters.
# This month's analytics
curl "https://sharedoc.co/api/v1/analytics/overview?since=2026-04-01" \
-H "Authorization: Bearer bd_live_your_key_here"
{
"period": { "since": "2026-04-01", "until": null },
"totals": {
"documents": 14,
"total_views": 156,
"unique_viewers": 43,
"leads_captured": 18,
"avg_completion": 0.52
},
"top_documents": [
{ "short_code": "s-ab12cd", "title": "Series A Deck", "views": 47, "completion": 0.72, "leads": 5 },
{ "short_code": "s-ef56gh", "title": "Product Overview", "views": 31, "completion": 0.65, "leads": 8 }
],
"engagement_breakdown": {
"high_interest": 5,
"read": 3,
"skimmed": 8,
"opened": 15,
"not_opened": 3
}
}
Webhook Events & Payloads
ShareDoc sends POST requests to your configured URL when events occur. Every payload includes full context — enough to update a CRM or send a Slack message without follow-up API calls.
| Event | Trigger |
|---|---|
document.viewed | Someone views a document (debounced per viewer, 30min) |
document.completed | A viewer sees 100% of pages (once per viewer) |
lead.captured | Someone enters their email through the gate |
viewer.revisited | A viewer returns after 24+ hours |
engagement.milestone | A viewer crosses into "High Interest" engagement |
document.uploaded | A document is uploaded |
document.downloaded | Someone downloads a document |
document.viewed
Includes viewer identity (if they passed the email gate), engagement metrics, and visit count.
{
"id": "evt_a1b2c3d4e5f6",
"event": "document.viewed",
"created_at": "2026-04-09T14:33:00Z",
"data": {
"document": {
"id": "uuid",
"title": "Series A Deck",
"short_code": "s/ab12cd",
"url": "https://sharedoc.co/s/ab12cd"
},
"viewer": {
"email": "jane@acme.com",
"company_domain": "acme.com",
"pages_viewed": 10,
"total_pages": 12,
"completion": 0.83,
"time_spent_seconds": 245.0,
"engagement_label": "High Interest",
"visit_number": 2
}
}
}
document.completed
Fires once per viewer when they've seen every page. Use this to trigger a follow-up.
{
"id": "evt_f7g8h9i0j1k2",
"event": "document.completed",
"created_at": "2026-04-09T15:10:00Z",
"data": {
"document": { "id": "uuid", "title": "Series A Deck", "short_code": "s/ab12cd", "url": "..." },
"viewer": {
"email": "jane@acme.com",
"company_domain": "acme.com",
"completion": 1.0,
"time_spent_seconds": 420.0,
"visit_number": 3
}
}
}
lead.captured
Includes how much the lead has already read before entering their email.
{
"id": "evt_c3d4e5f6g7h8",
"event": "lead.captured",
"created_at": "2026-04-09T09:15:00Z",
"data": {
"document": { "id": "uuid", "title": "Series A Deck", "short_code": "s/ab12cd", "url": "..." },
"lead": {
"email": "jane@acme.com",
"name": "Jane Smith",
"company_domain": "acme.com",
"pages_viewed": 3,
"total_pages": 12,
"time_spent_seconds": 45.0
}
}
}
viewer.revisited
Fires when a viewer returns after 24+ hours. Strong buying signal.
{
"id": "evt_d4e5f6g7h8i9",
"event": "viewer.revisited",
"created_at": "2026-04-10T10:00:00Z",
"data": {
"document": { "id": "uuid", "title": "Series A Deck", "short_code": "s/ab12cd", "url": "..." },
"viewer": {
"email": "jane@acme.com",
"company_domain": "acme.com",
"visit_number": 3,
"first_viewed_at": "2026-04-07T09:15:00Z",
"hours_since_first_view": 72.8,
"engagement_label": "High Interest"
}
}
}
Webhook API
Manage webhooks programmatically. One webhook per account.
GET /api/v1/webhooks
Get your webhook configuration and recent delivery history.
curl https://sharedoc.co/api/v1/webhooks \
-H "Authorization: Bearer bd_live_your_key_here"
POST /api/v1/webhooks
Create or update your webhook. The signing secret is returned once on creation — store it securely.
curl -X POST https://sharedoc.co/api/v1/webhooks \
-H "Authorization: Bearer bd_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhooks/sharedoc",
"events": ["document.viewed", "lead.captured", "document.completed", "viewer.revisited"]
}'
{
"webhook_id": "uuid",
"url": "https://your-app.com/webhooks/sharedoc",
"events": ["document.viewed", "lead.captured", "document.completed", "viewer.revisited"],
"is_active": true,
"secret": "a1b2c3d4..."
}
POST /api/v1/webhooks/test
Send a test event to verify your endpoint is working.
curl -X POST https://sharedoc.co/api/v1/webhooks/test \
-H "Authorization: Bearer bd_live_your_key_here"
DELETE /api/v1/webhooks
Delete your webhook configuration. Returns 204.
Signature Verification
Every webhook includes a signature header for verification:
X-ShareDoc-Signature: t=1680000000,v1=5257a869e7ecebeda32affa62cdca3fa...
Python:
import hmac, hashlib, time
def verify_webhook(body: bytes, header: str, secret: str) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
timestamp = parts["t"]
signature = parts["v1"]
# Reject if older than 5 minutes
if abs(time.time() - int(timestamp)) > 300:
return False
signed_payload = f"{timestamp}.".encode() + body
expected = hmac.new(
secret.encode(), signed_payload, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)
Node.js:
const crypto = require('crypto');
function verifyWebhook(body, header, secret) {
const parts = Object.fromEntries(
header.split(',').map(p => p.split('=', 2))
);
const { t: timestamp, v1: signature } = parts;
if (Math.abs(Date.now()/1000 - parseInt(timestamp)) > 300) return false;
const expected = crypto
.createHmac('sha256', secret)
.update(`${timestamp}.${body}`)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected), Buffer.from(signature)
);
}
Retry Behavior
- Timeout: 10 seconds per attempt
- Retries: 3 attempts (immediate, +1 min, +30 min)
- Success: any 2xx response
- Auto-disable: after 3 consecutive failed deliveries
- Re-enable via API or from your dashboard settings
Questions? Contact support@sharedoc.co