sendapage

Documentation

sendapage turns a brand template + a one-off brief into a personalized microsite at sendapage.com/p/<slug>. This guide covers the full surface — templates, briefs, pages, analytics, and the API.

Quickstart

Three steps from zero to a published page:

  1. Sign in at /login with GitHub or Google. You start on the Free plan with 5 lifetime pages.
  2. Get a template. Easiest path: clone a starter on /templates (post-meeting follow-up, sales pitch, recruiting offer, investor update, wedding invite). Or chat with the AI to draft one at /templates/author. Or write one by hand at /templates/new.
  3. Generate a page at /pages/new: pick the template, drop in a brief, hit Generate. The microsite ships in ~60 seconds.

Send the link. Watch engagement land in the dashboard the moment the recipient opens it.

Templates

A template is the AI's brand handbook. It's reused across every page generated from it, so put effort into one good template — not into editing the AI's output afterwards.

Three ways to create a template

  • Clone a starter — fastest. Five proven templates on /templates: post-meeting follow-up, sales pitch / deal room, recruiting offer, per-LP investor update, and a consumer wedding invitation. One click clones into your workspace; edit afterwards however you like.
  • Author with AI — interview-style chat at /templates/author. The AI asks about your brand, voice, audience, and CTA, then drafts the template for you. Live preview shows the draft as it builds; one click saves.
  • Manual — start from a blank textarea at /templates/new. Most expressive, most work.

What goes in the instructions field

Treat it like onboarding a designer. Cover:

  • Brand voice — formal, playful, technical, etc.
  • Visual direction — colours, typography, layout density.
  • Required sections — e.g. hero, value props, social proof, CTA.
  • What NOT to include — e.g. no testimonials unless provided in the brief.
  • The CTA — what action you want the recipient to take.
  • Tailoring rules — for example, "if the recipient is a manager, lead with team-level outcomes; if an IC, lead with day-to-day workflow."

Analytics markup (data-track-section, data-cta="primary") is enforced globally — you don't need to mention it in templates.

Attaching template files

Upload files when creating or editing a template:

  • Markdown / text / JSON / YAMLfiles drop into the agent's working directory next to the instructions — useful for canonical brand info, FAQs, structured product data, sample copy.
  • Images, fonts, and other binary assets are placed in ./assets/<filename> and the agent will reference them directly in the generated HTML. URLs are rewritten at serve time so links work for the recipient.

Per-template caps: 20 files, 10 MB each. Images, SVG, fonts, PDF, markdown, JSON, YAML, plain text are all accepted.

Briefs

A brief is the case-specific input — who you're sending the page to and why. The agent personalizes the template using only what's in the brief plus any uploaded files. It won't invent dates, prices, names, or quotes.

Recommended structure

Recipient: Jane Smith, VP Procurement at Globex
Stage: Stage 3 (proposal review)
Key context:
- Renewal date 2026-09-15
- Current annual spend with us: $124k
- Previously raised concerns about onboarding ramp time
- Scoped expansion into APAC offices

Goals:
- Reaffirm the renewal value
- Pre-empt the ramp-time objection
- Open the APAC expansion conversation

The brief is a free-text field — markdown works, but plain prose is fine too. The clearer and more specific you are, the better the page.

One template, many briefs

One template + many briefs is the pattern. If you find yourself editing the template per recipient, you're fighting the system — move the variability into the brief.

CTAs & context

Two structured fields supplement the free-text brief.

CTAs (per-page)

Add labelled URLs the agent can pick from when emitting CTA anchors. The template decides which label to use for which audience; you supply the destinations.

{
  "ctas": [
    { "label": "book", "url": "https://calendly.com/yourname/30min" },
    { "label": "video", "url": "https://www.loom.com/share/abc123" }
  ]
}

Set in the dashboard form on /pages/new, or pass context.ctas on the API.

Free-form context

Anything else structured (CRM payload, deal data, computed fields) goes in context as JSON. The agent sees it in context.json alongside the brief and uses it where the template tells it to.

Page features

Tags

Free-text labels for organisation. Filter pages on the list view by tag chips. Set on create (comma-separated) or via API.

Password protection

For confidential sales rooms / NDA-required pages. Set a password on the page detail (Settings → Password protection). Recipients see a password gate at /p/<slug> until they enter the password; their unlock is remembered for 4 hours via an HttpOnly cookie scoped to that slug.

Duplicate

On a ready page, "Duplicate" copies brief + template + context + tags and fires a fresh generation. Useful for trying a variant without editing the original.

Expiry

Pages don't expire by default. Set expiresAt on a page (via API) to time-limit access — after the deadline, /p/<slug> returns 410. Useful for stage-gated sales rooms.

Open Graph / share previews

Every page auto-generates an OG card image (clean black-on-white with the page title). Pasting /p/<slug> into Slack, iMessage, LinkedIn, X, or Gmail unfurls a proper preview without any setup.

Watermark

Free-tier pages display a small "Made with sendapage" mark in the corner. Paid tiers serve unbranded.

CSV import

For batch follow-ups (post-conference lists, CRM exports), drop a CSV at /pages/import. Each row becomes a page.

  • No column mapping — the entire row is sent to the agent as JSON. Your template's instructions decide which fields matter.
  • Optional "shared context" box — text applied to every row (sender, sign-off, default CTA, conference name, etc.).
  • Caps: 200 rows / 2 MB per import. Each row is quota-checked atomically.
  • Slug auto-derived from a name- or email-shaped column when present.

Analytics

Every published page ships with first-party tracking. No third-party cookies; visitor identifiers are page-scoped and rotate daily so visitors aren't trackable across different pages.

What we capture

  • Views — server-rendered, captured even if JavaScript is blocked.
  • Active time on page — only counts seconds the tab is visible & focused.
  • Scroll depth — milestones at 25/50/75/100%.
  • Section dwell — how long the visitor spent looking at each data-track-section.
  • Link & CTA clicks — anchors with data-cta="..." are bucketed as conversions.
  • Geo & org — country / city from the request, plus reverse-DNS to org name when available.
  • Engagement score (0–100) per session, derived from active time + scroll + CTA clicks + section breadth.
  • Live indicator — pulsing badge when someone is actively on the page right now.

First-view alerts

Configure Slack / email / webhook alerts that fire when a recipient opens the page, optionally only for visitors from specific company domains (org match).

Where to find it

On the page detail in the dashboard. Per-section heatmap, geography breakdown, sortable visitor table, and a real-time activity feed.

API reference

Use the API to manage templates, generate pages, and read status from any backend (CRM, ATS, automation tooling). API access is included on Growth and above.

Authentication

Create a key at /api-keys. Pass it in the Authorization header.

Authorization: Bearer sap_live_xxxxxxxxxxxxxxxxxxxx

Templates

Full CRUD. Asset URLs you supply are server-side fetched into our blob storage (so the agent can read them at generation time) — must be public HTTPS.

# Create
curl -X POST https://sendapage.com/api/v1/templates \
  -H "Authorization: Bearer $SAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "OutboundCon 2026 — booth follow-up",
    "description": "Personalized post-booth follow-up.",
    "instructions": "# Brand voice\n...",
    "asset_urls": [
      { "url": "https://example.com/logo.svg", "name": "logo.svg" }
    ]
  }'

# List
curl https://sendapage.com/api/v1/templates -H "Authorization: Bearer $SAP_KEY"

# Get / update / delete
curl https://sendapage.com/api/v1/templates/$TEMPLATE_ID -H "Authorization: Bearer $SAP_KEY"
curl -X PATCH https://sendapage.com/api/v1/templates/$TEMPLATE_ID \
  -H "Authorization: Bearer $SAP_KEY" -H "Content-Type: application/json" \
  -d '{ "instructions": "# Updated voice\n..." }'
curl -X DELETE https://sendapage.com/api/v1/templates/$TEMPLATE_ID -H "Authorization: Bearer $SAP_KEY"

Pages

Create / list / get / delete. Page creation returns immediately with status queued; generation runs in the background.

# Create
curl -X POST https://sendapage.com/api/v1/pages \
  -H "Authorization: Bearer $SAP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": "31058a46-73bf-4488-a52a-728b73465e09",
    "brief": "Recipient: Jane Smith @ Globex...",
    "context": {
      "deal_id": "OPP-1234",
      "ctas": [{ "label": "book", "url": "https://calendly.com/me/30min" }]
    },
    "slug_hint": "globex-q1",
    "webhook_url": "https://your-app.com/sendapage-callback"
  }'

# Poll / list / delete
curl https://sendapage.com/api/v1/pages/$PAGE_ID -H "Authorization: Bearer $SAP_KEY"
curl https://sendapage.com/api/v1/pages -H "Authorization: Bearer $SAP_KEY"
curl -X DELETE https://sendapage.com/api/v1/pages/$PAGE_ID -H "Authorization: Bearer $SAP_KEY"

Page response shape

{
  "id": "8e2a...",
  "slug": "globex-q1-9td4hk7hrt",
  "status": "ready",
  "title": "Renewal review for Globex",
  "url": "https://sendapage.com/p/globex-q1-9td4hk7hrt",
  "created_at": "2026-05-03T07:38:49.000Z",
  "published_at": "2026-05-03T07:39:42.000Z",
  "error": null
}

Statuses: queuedgeneratingready (or failed with error populated).

Errors

  • 401 invalid_api_key — bad / revoked key
  • 402 api_access_not_included — upgrade to Growth or higher
  • 402 quota_exceeded — monthly page limit hit
  • 402 template_limit_reached — plan's template count maxed
  • 404 template_not_found / 404 not_found
  • 413 asset_too_large — over 10 MB
  • 422 asset_fetch_failed / 422 asset_mime_not_allowed
  • 400 invalid_payload — malformed body; details in details

Webhooks

Pass a webhook_url on page creation. We POST a JSON payload when generation finishes (success or failure):

{
  "event": "page.completed",
  "page": {
    "id": "8e2a...",
    "slug": "globex-q1-9td4hk7hrt",
    "status": "ready",
    "url": "https://sendapage.com/p/globex-q1-9td4hk7hrt",
    "title": "Renewal review for Globex",
    "created_at": "...",
    "published_at": "...",
    "error": null
  }
}

We post once. Build the receiving endpoint to be idempotent on page.id. URLs are validated server-side: HTTPS only; private/loopback/cloud-metadata addresses are rejected up-front.

Integrations

Google Forms / Typeform / any form tool

Wire a form to auto-generate a sendapage on submission via Apps Script:

const SAP_API_KEY = 'sap_live_...';
const SAP_TEMPLATE_ID = 'your-template-uuid';

function onFormSubmit(e) {
  const v = e.namedValues || {};
  const f = (k) => (v[k] && v[k][0]) || '';
  const name = f('Full Name') || f('Name');
  const email = f('Email');
  if (!name || !email) return;

  const brief = ['Recipient: ' + name, 'Email: ' + email,
    '', 'Notes:', f('What did you want to chat about?') || ''].join('\n');

  const res = UrlFetchApp.fetch('https://sendapage.com/api/v1/pages', {
    method: 'post',
    contentType: 'application/json',
    headers: { Authorization: 'Bearer ' + SAP_API_KEY },
    payload: JSON.stringify({
      template_id: SAP_TEMPLATE_ID, brief,
      context: { recipient: { name, email } },
    }),
  });
  // Optionally write back the URL into the linked Sheet from JSON.parse(res.getContentText()).url
}

CRM stage triggers

Most CRMs (HubSpot Workflows, Salesforce Flow, Pipedrive automations) can fire a webhook when a deal advances. Point that webhook at POST /api/v1/pageswith the deal's rep + prospect data as the brief, and use webhook_url to feed the generated URL back into the deal as a custom property.

Pricing & quotas

See the pricing table on the landing page for current tiers. Highlights:

  • Free — 5 lifetime pages, watermark, 1 template
  • Starter $39/mo — 50 pages/mo, 3 templates
  • Growth $79/mo — 250 pages/mo, 10 templates, custom domain, API access
  • Scale $149/mo — 1,000 pages/mo, unlimited templates, engagement alerts
  • Enterprise — SSO, audit logs, custom volume — talk to sales

Manage your subscription at /billing.

FAQ

How long does generation take?

Typically 30–90 seconds. Templates that ask the agent to do brand research take longer.

Which AI model is used?

sendapage runs Claude Code in a sandbox against an Anthropic-compatible endpoint. The model is set workspace-wide and tuned by the operator — there's no per-template or per-user model picker. We've picked a model that hits the right quality/cost tradeoff for personalized HTML; we change it as the frontier moves.

Can I edit the generated HTML?

Not yet — pages are immutable artifacts. If the output isn't what you wanted, refine the template or brief and regenerate (the "Duplicate" button on a page makes this a one-click loop). Post-edit support is planned.

Can I use my own domain?

Custom domains land at Growth and above. Configure under /billing.

Do generated pages expire?

Not by default. Set expiresAt per page via the API to time-limit a link. After the deadline, the public URL returns 410 Gone.

Can I require a password to view a page?

Yes. On the page detail, Settings → Password protection. Visitors see a password form before the page; an unlock cookie remembers them for 4 hours.

Is the data private?

Briefs, templates, and generated pages are visible only to your account. Visitor analytics use a daily-rotating salted hash, scoped per-page — visitors aren't identifiable across different pages and cannot be re-identified after the daily rotation.


Something missing? Email hello@sendapage.com.