#!/usr/bin/env python3 """Render docs/zapier-billing.pdf — Zapier cost structure for Verae planning. Platypus Paragraphs for bullets (never ListFlowable). Every table cell is a Paragraph. Avoid '|' in body text (Helvetica renders it like a capital I). """ from __future__ import annotations from pathlib import Path from reportlab.lib import colors from reportlab.lib.enums import TA_CENTER, TA_LEFT from reportlab.lib.pagesizes import letter from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet from reportlab.lib.units import inch from reportlab.platypus import ( PageBreak, Paragraph, Preformatted, SimpleDocTemplate, Spacer, Table, TableStyle, ) ROOT = Path(__file__).resolve().parents[1] OUT = ROOT / "docs" / "zapier-billing.pdf" NAVY = colors.HexColor("#0F2744") TEAL = colors.HexColor("#1A6B6B") SLATE = colors.HexColor("#334155") RULE = colors.HexColor("#CBD5E1") ROW = colors.HexColor("#F1F5F9") HEAD_BG = colors.HexColor("#0F2744") HEAD_FG = colors.white CODE_BG = colors.HexColor("#F8FAFC") def styles(): base = getSampleStyleSheet() return { "cover_kicker": ParagraphStyle( "cover_kicker", parent=base["Normal"], fontName="Helvetica", fontSize=10, textColor=TEAL, alignment=TA_CENTER, spaceAfter=10, ), "cover_title": ParagraphStyle( "cover_title", parent=base["Title"], fontName="Helvetica-Bold", fontSize=24, leading=30, textColor=NAVY, alignment=TA_CENTER, spaceAfter=10, ), "cover_sub": ParagraphStyle( "cover_sub", parent=base["Normal"], fontName="Helvetica", fontSize=11.5, leading=16, textColor=SLATE, alignment=TA_CENTER, spaceAfter=8, ), "h1": ParagraphStyle( "h1", parent=base["Heading1"], fontName="Helvetica-Bold", fontSize=14.5, leading=18, textColor=NAVY, spaceBefore=14, spaceAfter=7, ), "h2": ParagraphStyle( "h2", parent=base["Heading2"], fontName="Helvetica-Bold", fontSize=11.5, leading=15, textColor=TEAL, spaceBefore=10, spaceAfter=5, ), "body": ParagraphStyle( "body", parent=base["Normal"], fontName="Helvetica", fontSize=9.4, leading=13, textColor=SLATE, alignment=TA_LEFT, spaceAfter=6, ), "bullet": ParagraphStyle( "bullet", parent=base["Normal"], fontName="Helvetica", fontSize=9.4, leading=12.8, textColor=SLATE, leftIndent=14, firstLineIndent=-10, spaceAfter=3, ), "toc": ParagraphStyle( "toc", parent=base["Normal"], fontName="Helvetica", fontSize=10, leading=15, textColor=NAVY, leftIndent=6, spaceAfter=2, ), "cell": ParagraphStyle( "cell", parent=base["Normal"], fontName="Helvetica", fontSize=7.8, leading=10.4, textColor=SLATE, ), "cell_h": ParagraphStyle( "cell_h", parent=base["Normal"], fontName="Helvetica-Bold", fontSize=7.8, leading=10.4, textColor=HEAD_FG, ), "code": ParagraphStyle( "code", parent=base["Code"], fontName="Courier", fontSize=7.6, leading=10.2, textColor=NAVY, backColor=CODE_BG, leftIndent=4, rightIndent=4, spaceBefore=3, spaceAfter=7, ), "caption": ParagraphStyle( "caption", parent=base["Normal"], fontName="Helvetica-Oblique", fontSize=8, leading=11, textColor=colors.HexColor("#64748B"), spaceAfter=8, ), } S = styles() USABLE = letter[0] - 1.4 * inch def P(text, style="body"): return Paragraph(text, S[style]) def B(text): return Paragraph(f"• {text}", S["bullet"]) def H1(text): return Paragraph(text, S["h1"]) def H2(text): return Paragraph(text, S["h2"]) def CODE(text): return Preformatted(text.rstrip() + "\n", S["code"]) def tbl(headers, rows, widths=None): if widths is None: widths = [USABLE / len(headers)] * len(headers) data = [[Paragraph(h, S["cell_h"]) for h in headers]] for row in rows: data.append([Paragraph(c, S["cell"]) for c in row]) t = Table(data, colWidths=widths, repeatRows=1) cmds = [ ("BACKGROUND", (0, 0), (-1, 0), HEAD_BG), ("VALIGN", (0, 0), (-1, -1), "TOP"), ("LEFTPADDING", (0, 0), (-1, -1), 4), ("RIGHTPADDING", (0, 0), (-1, -1), 4), ("TOPPADDING", (0, 0), (-1, -1), 3.5), ("BOTTOMPADDING", (0, 0), (-1, -1), 3.5), ("GRID", (0, 0), (-1, -1), 0.3, RULE), ("LINEBELOW", (0, 0), (-1, 0), 1, TEAL), ] for i in range(1, len(data)): if i % 2 == 0: cmds.append(("BACKGROUND", (0, i), (-1, i), ROW)) t.setStyle(TableStyle(cmds)) return t def header_footer(canvas, doc): canvas.saveState() w, h = letter canvas.setFillColor(NAVY) canvas.rect(0, h - 28, w, 28, fill=1, stroke=0) canvas.setFillColor(colors.white) canvas.setFont("Helvetica", 8) canvas.drawString(0.7 * inch, h - 18, "Verae Time · Zapier billing brief") canvas.drawRightString(w - 0.7 * inch, h - 18, "Cost structure and variable pricing") canvas.setFillColor(TEAL) canvas.rect(0, 0, w, 22, fill=1, stroke=0) canvas.setFillColor(colors.white) canvas.setFont("Helvetica", 8) canvas.drawString(0.7 * inch, 8, "Internal planning · 18 August 2026 · USD list from zapier.com/pricing") canvas.drawRightString(w - 0.7 * inch, 8, f"{doc.page}") canvas.restoreState() def cover_footer(canvas, doc): canvas.saveState() w, _ = letter canvas.setFillColor(NAVY) canvas.rect(0, 0, w, 56, fill=1, stroke=0) canvas.setFillColor(TEAL) canvas.rect(0, 56, w, 4, fill=1, stroke=0) canvas.setFillColor(colors.white) canvas.setFont("Helvetica", 9) canvas.drawCentredString(w / 2, 28, "Confirm live rates before any customer quote") canvas.setFont("Helvetica", 8) canvas.drawCentredString(w / 2, 14, "18 August 2026") canvas.restoreState() def story(): out = [] out.append(Spacer(1, 1.5 * inch)) out.append(P("VERAE TIME · COMMERCIAL PLANNING", "cover_kicker")) out.append(P("Zapier cost structure
and billing models", "cover_title")) out.append( P( "How Zapier charges for Zaps, MCP, AI, Code, Agents, and embed — " "with worked examples — so we can design Verae’s meter without " "subsidizing or colliding with Zapier.", "cover_sub", ) ) out.append(Spacer(1, 14)) out.append( tbl( ["Source", "As of", "Use"], [ [ "zapier.com/pricing (official machine-readable page)", "17–18 Aug 2026", "Plan levels, task tiers, overflow, add-ons", ], [ "Zapier “What is a task?” (updated June 2026)", "June 2026", "What counts; AI 1/3/5; MCP = 2", ], [ "verae-zapier-middleware PLAN_LIMITS", "This repo", "Our second meter (timestamps / verify / batch)", ], ], [2.5 * inch, 1.5 * inch, 2.5 * inch], ) ) out.append(PageBreak()) out.append(H1("Contents")) for line in [ "1. The one idea that unlocks the rest", "2. What a task is (and is not)", "3. Plan levels — what the customer can build", "4. Variable pricing inside the task pool", "5. Task tiers and list price", "6. Overflow (pay-per-task)", "7. Other Zapier products — different models", "8. Worked examples", "9. Verae’s meter today", "10. How this should shape our billing", "11. Planning checklist", ]: out.append(P(line, "toc")) out.append( P( "Companion narrative: docs/zapier-billing.md. Architecture guide: getting-started.md §9–10.", "caption", ) ) # 1 out.append(H1("1. The one idea that unlocks the rest")) out.append( P( "Zapier does not charge per Zap, per connected app, or (on Professional) per seat. " "It charges for successful work. You buy two things that travel together: " "a plan level (feature set) and a task tier (monthly allowance). " "Enterprise swaps the monthly reset for an annual task pool." ) ) out.append( P( "Three other economies sit beside that pool, not inside it:" ) ) out.append( tbl( ["Economy", "Unit", "Used for"], [ ["Core Zapier", "Task", "Zaps, AI by Zapier, Code by Zapier, MCP, SDK"], ["Agents add-on", "Activity", "Zapier Agents — does not draw tasks"], ["Chatbots add-on", "Bot-count tier", "Zapier Chatbots — not task-metered"], ["Verae (us)", "Timestamp / verify / batch", "Middleware PLAN_LIMITS — a second invoice"], ], [1.7 * inch, 1.8 * inch, 3.0 * inch], ) ) out.append( P( "Verae never appears on the Zapier invoice unless we sign a White Label / " "Powered by Zapier contract and resell Zapier usage ourselves.", "caption", ) ) # 2 out.append(H1("2. What a task is (and is not)")) out.append( P( "A task is counted when Zapier successfully completes a unit of work. " "Failed steps are free on Zapier (they can still cost us if we already accepted the job)." ) ) out.append( tbl( ["Counts as tasks", "Does not count"], [ [ "Successful action in another product (Create Timestamp, Slack, Drive, Sheets, webhook)", "The trigger — including polling every 1–15 minutes", ], [ "Successful Zapier MCP tool execute (read or write)", "Filter, Paths, Formatter, Delay, Looping, Sub-Zap, Digest, Manager, Storage", ], [ "AI by Zapier and Code by Zapier (see multipliers / extra runtime)", "Zapier Tables and Forms triggers and actions", ], [ "SDK execute once beta pricing starts (today: beta is free)", "Building or testing a Zap until a step succeeds in production", ], ], [3.25 * inch, 3.25 * inch], ) ) out.append( P( "One shared allowance for the whole account. There is no separate MCP budget. " "A five-step Zap that is trigger + Filter + Formatter + Timestamp + Slack uses " "two tasks, not five." ) ) # 3 out.append(H1("3. Plan levels — what the customer can build")) out.append(P("Plans are cumulative. Task volume is chosen separately (section 5).")) out.append( tbl( ["", "Free", "Professional", "Team", "Enterprise"], [ ["Seats", "1", "1", "25", "Unlimited"], ["Zap shape", "Two-step only", "Multi-step", "Multi-step", "Multi-step"], ["Polling", "15 min", "2 min", "1 min", "1 min"], ["Premium apps, webhooks", "No", "Yes", "Yes", "Yes"], ["Filters, Paths, Formatter, AI", "No", "Yes", "Yes", "Yes"], ["Shared Zaps, SAML SSO", "No", "No", "Yes", "Yes"], ["SCIM, app controls, TAM, BYOM", "No", "No", "No", "Yes"], ["Task cycle", "Monthly", "Monthly", "Monthly", "Annual pool"], ["Pay-per-task overflow", "No", "Optional", "Optional", "Custom"], [ "Entry price (annual, USD/mo)", "$0 (100 tasks)", "$19.99 (750 tasks)", "$69 (2,000 tasks)", "Sales", ], ], [1.55 * inch, 1.15 * inch, 1.35 * inch, 1.25 * inch, 1.2 * inch], ) ) out.append( P( "14-day Professional trial, no card. Non-profit: extra 15% off the subscription, " "not on pay-per-task. Live chat on Professional only at the 2,000+ task tier.", "caption", ) ) out.append( P( "Verae implication: a Free customer can only run “new file → Create Timestamp.” " "A catalog write, Slack notify, or Wait plus another action requires Professional." ) ) # 4 out.append(H1("4. Variable pricing inside the task pool")) out.append( P( "Not every successful step costs one task. Zapier uses multipliers so expensive " "compute consumes more of the same allowance. Confirm /pricing/rates before " "a contract; the page was not fetchable at write time. These multipliers are what " "Zapier publishes on the main pricing page and the June 2026 task article." ) ) out.append( tbl( ["Work", "Tasks per success", "Notes"], [ ["Typical third-party action (Verae Create Timestamp, Slack, Drive, Sheets)", "1", "The default. Design around this."], ["Standard AI by Zapier (default model)", "1", "Same as a normal action"], ["Advanced AI by Zapier", "3", "Confirm on the rate card"], ["Premium AI by Zapier", "5", "Confirm on the rate card"], ["Zapier MCP execute (read or write)", "2", "Discover / inspect / enable are free meta-tools"], [ "Code by Zapier", "0, then 1 per extra 30 s", "Included: Free 1s, Pro/Team 30s, Enterprise 2 min. Extended runtime opt-in 1–8 min on paid.", ], ["Zapier SDK", "Free in beta", "Expect it to join the task pool when beta ends"], ], [2.5 * inch, 1.5 * inch, 2.5 * inch], ) ) out.append( P( "Failed steps = 0 Zapier tasks. Autoreplay and customer retries can still hit Verae. " "That is our problem, not Zapier’s." ) ) # 5 out.append(H1("5. Task tiers and list price (USD, August 2026)")) out.append( P( "Self-serve is sold as plan × tier. Annual is about 33% off monthly. " "Implied dollars per task = list price ÷ included tasks (order-of-magnitude only)." ) ) out.append(H2("Professional")) out.append( tbl( ["Tasks / mo", "Annual / mo", "Monthly / mo", "Implied $/task (annual)"], [ ["750", "$19.99", "$29.99", "$0.027"], ["1,500", "$39.00", "$58.50", "$0.026"], ["2,000", "$49.00", "$73.50", "$0.025"], ["5,000", "$89.00", "$133.50", "$0.018"], ["10,000", "$129.00", "$193.50", "$0.013"], ["20,000", "$189.00", "$283.50", "$0.0095"], ["50,000", "$289.00", "$433.50", "$0.0058"], ["100,000", "$489.00", "$733.50", "$0.0049"], ["200,000", "$769.00", "$1,149.00", "$0.0038"], ["500,000", "$1,499.00", "$2,199.00", "$0.0030"], ["1,000,000", "$2,199.00", "$3,299.00", "$0.0022"], ["2,000,000", "$3,389.00", "$5,099.00", "$0.0017"], ], [1.6 * inch, 1.6 * inch, 1.6 * inch, 1.7 * inch], ) ) out.append(H2("Team (starts at 2,000)")) out.append( tbl( ["Tasks / mo", "Annual / mo", "Monthly / mo", "Implied $/task (annual)"], [ ["2,000", "$69.00", "$103.50", "$0.035"], ["5,000", "$119.00", "$178.50", "$0.024"], ["10,000", "$169.00", "$253.50", "$0.017"], ["20,000", "$249.00", "$373.50", "$0.012"], ["50,000", "$399.00", "$598.50", "$0.008"], ["100,000", "$599.00", "$898.50", "$0.006"], ["1,000,000", "$2,499.00", "$3,749.00", "$0.0025"], ["2,000,000", "$3,999.00", "$5,999.00", "$0.0020"], ], [1.6 * inch, 1.6 * inch, 1.6 * inch, 1.7 * inch], ) ) out.append( P( "Team’s entry dollars-per-task is higher than Pro because the customer is " "buying seats, shared connections, and SSO — not cheaper tasks. Intermediate " "tiers (300k, 400k, 750k, 1.25M, 1.5M, 1.75M) exist on the live page. Above 2M: Sales.", "caption", ) ) # 6 out.append(H1("6. Overflow (pay-per-task)")) out.append( tbl( ["Setting", "What happens"], [ [ "On (paid plans)", "Zaps and MCP keep running. Extra tasks bill at 1.25× the plan’s base dollars-per-task (annual) or 2.5× (monthly). Hard ceiling: 3× subscribed tasks, then pause.", ], ["Off", "Everything stops at the allowance."], ["Free", "No overflow. Hits 100 and stops."], ["Enterprise", "Annual pool instead of a monthly reset; overflow is contractual."], ], [1.6 * inch, 4.9 * inch], ) ) out.append( P( "Worked overage: Professional 750 annual → base ≈ $19.99 / 750 = $0.0267. " "Overflow ≈ $0.0333 per task. Same plan billed monthly: base ≈ $0.0400, " "overflow ≈ $0.100. Overflow on a monthly subscription is about 3× the " "annual overflow rate." ) ) # 7 out.append(H1("7. Other Zapier products — different models")) out.append( tbl( ["Product", "Model", "Relation to tasks"], [ ["Zap workflows", "Task", "Core"], ["Zapier MCP", "Same pool; 2 tasks per successful execute", "Meta-tools free"], ["Zapier SDK", "Beta free; expect tasks later", "Consume, not publish"], ["AI by Zapier", "Task × model tier (1 / 3 / 5)", "Inside the Zap"], ["Code by Zapier", "Included seconds + 1 task / 30 s extra", "Inside the Zap"], ["Tables / Forms", "Plan caps (records, pages, upload size)", "0 tasks when used in Zaps"], [ "Agents", "Activities (Free 400/mo; paid ~$33.33/mo annual for 1,500). Per-run cap 10 / 40.", "Does not use tasks", ], ["Chatbots", "Bot-count tiers (Free 2; paid ≈5 / ≈20)", "Does not use tasks"], ["Canvas / Copilot", "Included; Free Copilot has a daily message limit", "Not a usage meter"], [ "Directory integration (us)", "$0 to publish. Customer’s Zapier plan pays tasks.", "Partner is not billed", ], [ "White Label / Powered by Zapier / embed", "Usage-based to the product company. End users may not need their own Zapier bill.", "Sales contract", ], ["NLA / AI Actions", "Retired", "Do not design around this"], ], [1.8 * inch, 2.8 * inch, 1.9 * inch], ) ) # 8 out.append(H1("8. Worked examples")) out.append( P( "Assume Professional billed annually unless noted, and that every named " "action succeeds. Verae units are our meter." ) ) out.append(H2("A. Two-step timestamp (Free-capable)")) out.append(P("New file in Drive → Verae: Create Timestamp · 1 Zapier task and 1 Verae stamp per file.")) out.append( tbl( ["Volume", "Zapier tasks", "Fits", "Zapier $ (annual)", "Verae"], [ ["80 files / mo", "80", "Free", "$0", "80 stamps — over our free (50)"], ["200", "200", "Pro 750", "$19.99", "200 — still under our starter (500)"], ["600", "600", "Pro 750", "$19.99", "600 — over our starter; we 402 first"], ], [1.3 * inch, 1.2 * inch, 1.1 * inch, 1.4 * inch, 1.5 * inch], ) ) out.append( P( "Lesson: the customer can be fine on Zapier and still hit our 402. " "The two meters trip at different points." ) ) out.append(H2("B. Production pattern we recommend")) out.append( P( "New file → Filter → Create Timestamp → Formatter → write catalog " "(Zapier Tables = 0 tasks) → Slack. Billable: Timestamp + Slack = " "2 tasks per file that passes the filter." ) ) out.append( tbl( ["Files / mo", "Pass filter", "Zapier tasks", "Cheapest Pro tier", "Zapier $", "Verae stamps"], [ ["1,000", "20% (200)", "400", "750", "$19.99", "200"], ["1,000", "100%", "2,000", "2,000", "$49", "1,000 (our pro)"], ["10,000", "100%", "20,000", "20,000", "$189", "10,000 (contract)"], ], [1.05 * inch, 1.1 * inch, 1.05 * inch, 1.25 * inch, 0.95 * inch, 1.1 * inch], ) ) out.append( P( "Filter early: 800 of 1,000 files dropped costs 0 Zapier tasks and 0 Verae stamps. " "That is the single best cost control we can teach customers." ) ) out.append(H2("C. Create and Wait versus hook")) out.append(B("Wait in the Zap: 1 Zapier task. Fine when the user needs the certificate in the same run.")) out.append( B( "Async create + Timestamp Completed hook + update row: 1 task to create + 1 task " "when the hook fires an action = 2 tasks, but the Zap does not sit open. Prefer at volume." ) ) out.append( B( "Anti-pattern: polling Find Job Status every minute. Each successful search is a task." ) ) out.append(H2("D. Same work via Zapier MCP (an agent)")) out.append( P( "Agent executes Create Timestamp, write Sheet, Slack. Three executes × 2 tasks = " "6 Zapier tasks per file, plus Agent activities if they used Zapier Agents." ) ) out.append( tbl( ["Files / mo", "Zapier tasks", "Cheapest Pro", "Zapier $", "Same stamps via Example B"], [ ["200", "1,200", "1,500 ($39)", "$39", "400 tasks / $19.99"], ["1,000", "6,000", "10,000 ($129)", "$129", "2,000 tasks / $49"], ], [1.2 * inch, 1.2 * inch, 1.5 * inch, 1.1 * inch, 1.5 * inch], ) ) out.append( P( "Planning rule: MCP-shaped clients burn Zapier 2× per hop. Do not price " "Verae as if the customer’s only cost is our stamp." ) ) out.append(H2("E. AI enrichment in the Zap")) out.append( P( "New file → Standard AI extract (1) → Create Timestamp (1) → Sheet (1) = " "3 tasks. Swap Premium AI: 5+1+1 = 7 tasks. " "1,000 files: 3,000 vs 7,000 tasks → $89 vs $129 on Pro annual. " "Model choice is the customer’s Zapier bill unless we bury AI inside our action " "(we should not)." ) ) out.append(H2("F. Overflow month")) out.append( P( "Customer on Pro 750 annual ($19.99). A campaign pushes 1,400 successful " "timestamp-only runs." ) ) out.append(CODE( "Included: 750\n" "Overflow: 650 × ~$0.0333 ≈ $22\n" "Total Zapier that month ≈ $42\n" "Still under the 3× ceiling (2,250)\n" "\n" "Same usage on monthly Pro 750 ($29.99):\n" "Overflow: 650 × ~$0.100 ≈ $65\n" "Plus subscription ≈ $95" )) out.append(H2("G. White Label — we are the billed party")) out.append( P( "If Verae embeds Zapier and Zapier bills us per task, then 10,000 " "customer files × 2 tasks = 20,000 tasks ≈ $189/mo at Pro annual list " "plus our timestamp COGS. That number belongs in our COGS, not in the " "end customer’s Zapier account." ) ) # 9 out.append(H1("9. Verae’s meter today")) out.append(P("From verae-zapier-middleware PLAN_LIMITS — independent of Zapier.")) out.append( tbl( ["Verae plan", "Timestamps / mo", "Verifications", "Batch", "RPM"], [ ["free", "50", "50", "no", "30"], ["starter", "500", "500", "yes, max 10", "120"], ["pro", "5,000", "5,000", "yes, max 100", "600"], ["enterprise", "unlimited / contract", "contract", "yes", "3,000"], ], [1.4 * inch, 1.5 * inch, 1.3 * inch, 1.2 * inch, 1.1 * inch], ) ) out.append( P( "Over-quota → HTTP 402 QUOTA_EXCEEDED. Batch on free → 403 PLAN_UPGRADE_REQUIRED. " "These fire whether or not Zapier is still inside its task allowance." ) ) # 10 out.append(H1("10. How this should shape our billing")) out.append(B( "1. Never bundle “unlimited Zapier.” We do not control their task tier, " "MCP multiplier, or overflow toggle." )) out.append(B( "2. Meter what we uniquely do: accepted timestamp jobs, verifies, maybe " "stored GB / pin-days / Glacier restores — not Zap steps." )) out.append(B( "3. Mirror Zapier’s shape if we want familiarity: plan + included units + " "optional overage with a ceiling. Customers already understand 402 versus pause." )) out.append(B( "4. Do not copy Zapier’s 2× MCP tax onto our API. POST /zapier/v1/timestamp " "should stay one Verae unit whether the Zap used 1 task or an agent used 2." )) out.append(B( "5. Price batch as a plan gate. Zapier still charges 1 task for the batch " "action. We decide whether 100 items cost 1 or 100 of our units. Today we count " "batch size against batchMaxItems and timestamp quota." )) out.append(B( "6. Package for the hook pattern. Include enough monthly stamps that " "create + hook + catalog is cheaper on our side than polling status." )) out.append(B( "7. Three motions, three packages. Directory user = they pay Zapier + they " "pay Verae. MCP/agent user = they already pay 2 Zapier tasks per hop; keep us " "simple. Embed/White Label = Zapier may bill us; either cover that COGS or sell " "only the stamp and let them bring their own Zapier." )) out.append(B( "8. Storage / Peergos / Glacier is a third meter (getting-started §10). " "Do not hide pin-days or restore fees inside “one timestamp.”" )) out.append(B( "9. Bill on accepted jobId (HTTP 202), not on Zapier’s success callback. " "A failed later Zap step is free for them and already spent for us." )) out.append(B( "10. Quote two lines in every proposal: “Your Zapier plan (estimate N tasks)” " "and “Verae (M timestamps).” Never a single blended number." )) out.append(Spacer(1, 6)) out.append( P( "At Pro 750 annual, Zapier’s included work is about 2.7 cents per task. " "If Create Timestamp is one Zapier task + one Verae stamp, the customer’s " "Zapier share of a two-step Zap is ~$0.027. Price our stamp from chain/ops " "cost, not 1:1 to that 2.7¢ — but if we charge dollars per stamp while Zapier " "is cents per step, SMB Zaps will feel Verae-expensive even when Zapier is " "the bigger invoice at volume." ) ) # 11 out.append(H1("11. Planning checklist")) out.append(B("For each target Zap, count billable Zapier actions, not steps on the canvas.")) out.append(B("Multiply MCP executes by 2.")) out.append(B("Apply AI 1 / 3 / 5 if they enrich in the Zap.")) out.append(B("Pick the cheapest Zapier tier that covers that task count (or run overflow math).")) out.append(B("Count Verae timestamps / verifies / batch separately; check the 50 / 500 / 5,000 tripwires.")) out.append(B("If we embed Zapier, put Zapier list price into our COGS.")) out.append(B("Keep Peergos pin / Glacier restore off the timestamp SKU.")) out.append(B("Re-check zapier.com/pricing before any contract. This brief is dated 18 August 2026.")) out.append(Spacer(1, 14)) out.append( P( "Related: docs/zapier-billing.md · getting-started.md §9–10 · " "docs/diagrams/11-zapier-billing.svg · LOGIN.md (customer must have a Zapier plan to run Zaps).", "caption", ) ) return out def main(): OUT.parent.mkdir(parents=True, exist_ok=True) doc = SimpleDocTemplate( str(OUT), pagesize=letter, leftMargin=0.7 * inch, rightMargin=0.7 * inch, topMargin=0.55 * inch, bottomMargin=0.45 * inch, title="Zapier cost structure and billing models — Verae planning brief", author="Verae / Zapier research workspace", subject="Official Zapier pricing (Aug 2026) with examples for Verae billing design", ) doc.build(story(), onFirstPage=cover_footer, onLaterPages=header_footer) print(f"wrote {OUT} ({OUT.stat().st_size} bytes)") if __name__ == "__main__": main()