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"
  }
}
StatusCodeDescription
400bad_requestInvalid parameters or file type
401unauthorizedMissing or invalid API key
422validation_errorInvalid field value (e.g. gate_page out of range)
404not_foundResource not found
429rate_limitedToo many requests
500internal_errorServer error

List Documents

GET /api/v1/documents

Returns all documents for the authenticated user. Supports filtering, search, and sorting.

ParameterDefaultDescription
page1Page number
per_page20Results per page (max 100)
searchFilter by title (case-insensitive)
engagementFilter by engagement level: high_interest, read, skimmed, opened, not_opened
has_leadsOnly docs with captured leads (true)
sinceFilter by created date (ISO 8601, e.g. 2026-04-01)
untilFilter by created date (ISO 8601)
sortcreated_atSort 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.

FieldDefaultDescription
file requiredPDF file (multipart form data)
titleDerived from filenameDocument title
email_gatetrueRequire email to view (true/false)
gate_typepreviewpreview (show pages then gate), full (gate immediately), none
gate_page3Page to show gate on (1 to page_count)
allow_downloadtrueAllow PDF download
block_free_emailsfalseBlock Gmail, Yahoo, etc.
notifications_enabledtrueEmail 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.

EventTrigger
document.viewedSomeone views a document (debounced per viewer, 30min)
document.completedA viewer sees 100% of pages (once per viewer)
lead.capturedSomeone enters their email through the gate
viewer.revisitedA viewer returns after 24+ hours
engagement.milestoneA viewer crosses into "High Interest" engagement
document.uploadedA document is uploaded
document.downloadedSomeone 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

Questions? Contact support@sharedoc.co