Skip to content

05 — Appendix

ResourceURLRelevance
Stripe Billing overviewhttps://stripe.com/docs/billingPrimary reference for subscriptions, prices, invoices
Stripe Invoicing APIhttps://stripe.com/docs/api/invoicesInvoice object, line items, finalization, status
Stripe Subscriptions APIhttps://stripe.com/docs/api/subscriptionsSubscription creation, metered billing, billing cycle
Stripe Prices APIhttps://stripe.com/docs/api/pricesPrice types: licensed, metered, tiered, graduated
Stripe Meters APIhttps://stripe.com/docs/billing/subscriptions/usage-basedUsage-based billing via Meters (new) vs. legacy usage records
Stripe Usage Records APIhttps://stripe.com/docs/api/usage_recordsLegacy metered billing path (deprecated but functional)
Stripe InvoiceItem APIhttps://stripe.com/docs/api/invoiceitemsAdding line items to upcoming invoices
Stripe Smart Retrieshttps://stripe.com/docs/billing/revenue-recovery/smart-retriesAutomated failed payment retry
Stripe Dunning configurationhttps://stripe.com/docs/billing/revenue-recovery/dunningDunning email schedules, Stripe-managed comms
Stripe Customer Portalhttps://stripe.com/docs/billing/subscriptions/customer-portalSelf-service card update, invoice history
Stripe Webhookshttps://stripe.com/docs/webhooksEvent delivery, signature verification, retries
Stripe Webhook best practiceshttps://stripe.com/docs/webhooks/best-practicesIdempotency, ordering, failure handling
Stripe Credit Noteshttps://stripe.com/docs/billing/invoices/credit-notesIssuing refunds/adjustments on finalized invoices
Stripe Taxhttps://stripe.com/docs/taxFuture enablement path (not in scope at cutover)
Stripe event typeshttps://stripe.com/docs/api/events/typesFull list of webhook event types
ResourceURLRelevance
Cloudflare Workershttps://developers.cloudflare.com/workers/Runtime for billing Worker
Cloudflare Browser Renderinghttps://developers.cloudflare.com/browser-rendering/PDF rendering from HTML (leading candidate)
Cloudflare R2https://developers.cloudflare.com/r2/Invoice PDF storage (replaces S3 CDN)
Workers Cron Triggershttps://developers.cloudflare.com/workers/configuration/cron-triggers/Daily reconciliation job
Workers Analytics Enginehttps://developers.cloudflare.com/analytics/analytics-engine/Structured observability from billing Worker
Wrangler CLIhttps://developers.cloudflare.com/workers/wrangler/Deploy, dev, secret management
PackageURLPurpose
Honohttps://hono.devTypeScript HTTP framework for billing Worker
Stripe Node SDKhttps://github.com/stripe/stripe-nodeStripe API client (Workers-compatible)
Handlebarshttps://handlebarsjs.comInvoice PDF template engine
Mailgun.jshttps://github.com/mailgun/mailgun.jsMailgun API client (Workers-compatible)
Vitesthttps://vitest.devUnit + integration testing
ProjectPathRelationship
Admin Dashboard Cloudflare Migration../Admin Dashboard Cloudflare Migration/Sibling — billing ops surface in new admin-api; this project defines what billing endpoints admin-api needs
Public API Cloudflare Migration../Public API Cloudflare Migration/Predecessor — auth model, deployment pipeline, observability approach to mirror
Adventive Brand Guidehttps://brandguide.adventive.com/dashboardInvoice PDF design reference
ServiceReferencePurpose
Mailgunhttps://app.mailgun.comInvoice email delivery (stays)
Acodeihttps://acodei.comQuickBooks sync from Stripe events (unchanged)

Files analyzed during this planning engagement:

FileDescriptionSourceDate
application/controllers/Billing.phpInvoice trigger, payment trigger, 6-step dunning, Mailgun send, month-end Excel export (960 lines)adventive-admin repo2026-04-23
application/models/Billing_model.phpAll billing proxy methods, pricing tier queries, billing history (933 lines)adventive-admin repo2026-04-23
application/libraries/Mailgun.phpCustom curl-based Mailgun client, sendTemplatedEmail, invoice send pathsadventive-admin repo2026-04-23
application/config/adventive.phpbilling_service URL, billing email sender, HubSpot BCC, invoice CDN URLadventive-admin repo2026-04-23
application/controllers/ManagedServiceJob.phpManaged service job CRUDadventive-admin repo2026-04-23
application/models/ManagedService_model.phpManaged service job queries (505 lines)adventive-admin repo2026-04-23
Stripe account stateProducts (5), Prices (5), Subscriptions (0), Invoices (10 sampled)Stripe MCP connector2026-04-23

The following items require a human decision before or during implementation. Items marked BLOCKING must be resolved before the indicated phase begins.

#QuestionBlocking phaseOwnerNotes
OQ-1Stripe Smart Retries configuration: how many retries, at what intervals?B.3 (BLOCKING — must configure before first live cohort)JeffreyStripe default is 4 attempts over ~4 weeks. Adventive’s current manual dunning runs 6 steps over 30 days. Align Smart Retries schedule with current customer expectations before retiring Adventive dunning.
OQ-2Browser Rendering API access: has the Cloudflare account been enabled for Browser Rendering?B.2 (BLOCKING — must confirm before PDF rendering build)PatrickBrowser Rendering is available on Workers Paid but must be explicitly enabled in the Cloudflare Dashboard under Workers & Pages → Browser Rendering.
OQ-3Historical invoice export: which format and storage location?B.4Jeffrey14 years of billing_invoice history. Options: (a) export to R2 as JSON + original PDFs, (b) retain read-only access to legacy DB after billing_service retirement, (c) export to BigQuery. Must decide before B.8 decommissions billing_service.
OQ-4Cohort 1 customer list: which accounts are flat-subscription-only (no metered impressions)?B.6 (BLOCKING)Jeffrey + PatrickCohort 1 gate is pricing-model simplicity. Need a query against account_plan_usage to identify accounts with zero impression tiers (sub-only).
OQ-5billing_service tech stack: what PDF renderer does billing_service use, and is the Handlebars template accessible?B.2PatrickThe PDF renderer in billing_service is unanalyzable from the admin repo. The template must be extracted to seed the billing Worker’s src/render/templates/invoice.hbs.
OQ-6Acodei field mapping compatibility: does Acodei handle Stripe Subscription invoices the same as manual invoices?B.3JeffreyAcodei captures Stripe events. Subscription-generated invoices (billing_reason=subscription) have a different event shape than manual invoices (billing_reason=manual). Confirm Acodei’s field mappings cover both before first live cohort.
OQ-7Customer Portal (B.9): opt-in or deferred?B.9JeffreyCustomer Portal enables self-service card update and invoice history. Low implementation cost (Stripe configuration only). Decision needed: enable immediately at B.9 with customer comms, or defer until there’s a specific support-cost trigger.
OQ-8Metering signal frequency: daily push or end-of-period summary?B.4Jeffrey + PatrickDaily impression counts from Redshift are more accurate and reduce cutover risk, but require a pipeline change. End-of-period summary matches the current billing_service behavior and is lower implementation cost. Both are compatible with Stripe metered Prices.
OQ-9Custom arrangement inventory: how many accounts have non-standard pricing not captured in account_plan_usage?B.6 (BLOCKING for Cohort 3)Jeffrey + PatrickCohort 3 includes custom-arrangement customers. Need a per-account audit of billing_service invoice history vs. account_plan_usage + account_plan_sub to identify discrepancies.
OQ-10New GitHub repository: where does billing-worker live?B.1JeffreyAssumed adventive/adventive-billing-worker on GitHub (private). Confirm organization name, visibility, and branch protection rules.
OQ-11Stripe webhook signing secret: staging vs. production endpoints registered separately?B.1 (staging), B.3 (production)PatrickStaging should point to Stripe test-mode endpoint; production to live-mode endpoint. Two separate signing secrets. Confirm who registers them and who has access to Stripe Dashboard Developers tab.
OQ-12Cloudflare account ID and API token provisioning for billing Worker CI/CDB.1PatrickGitHub Actions needs CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID as repository secrets. Same token used by admin-api CI if on same Cloudflare account.

TermDefinition
billing_serviceA separate internal Adventive API at billing.{domain}/api/billing/ that owns all Stripe API calls, rollup logic, and invoice PDF generation. The admin repo is a thin proxy to this service. Not to be confused with the billing Worker (the new replacement).
billing WorkerThe new Cloudflare Worker that replaces billing_service’s Adventive-side responsibilities: webhook ingestion, PDF rendering, Mailgun delivery, and reconciliation. The billing Worker does NOT replace Stripe — it complements Stripe.
Browser RenderingCloudflare’s headless-browser API that renders HTML to PDF. The leading candidate for replacing billing_service’s PDF renderer. Limit: 2 simultaneous renders per account at a time.
Credit NoteA Stripe object that reduces the amount owed on a finalized invoice. Used for refunds, corrections, or goodwill adjustments. Does not create a new invoice — adjusts the existing one.
Dual-run periodThe phase during a cohort migration when both billing_service (legacy) and the billing Worker (new) are live simultaneously for the same customer. The billing Worker is authoritative; billing_service is a shadow check. One billing cycle minimum.
DunningThe process of communicating with customers after payment failure to recover the revenue. Currently owned by Adventive (6-step manual sequence in Billing.php). Post-migration: fully owned by Stripe (Smart Retries + Stripe dunning email schedules).
Graduated pricingA Stripe tiered price model where each tier’s rate applies only to the quantity within that tier (not to the full quantity). Adventive’s current impression pricing is graduated.
HyperdriveCloudflare’s MySQL connection pooling layer. Used by the billing Worker for reconciliation reads of the legacy billing_invoice table during the dual-run period.
idempotency keyA unique key that prevents duplicate operations when a request is retried. For usage events: {account_id}:{period}:{usage_type}. For Stripe API calls: passed as Idempotency-Key header.
InvoiceItemA Stripe object that adds a line item to a customer’s next invoice. Used for managed service fees and custom line items. InvoiceItems are created as-accrued and automatically included when the subscription invoice finalizes.
licensed (usage_type)A Stripe Price billing model where the subscription charges a flat amount per billing cycle, regardless of usage. Used for flat monthly subscription fees.
metered (usage_type)A Stripe Price billing model where usage is reported via Usage Records (or Meters), and the subscription charges based on actual usage at period end. Used for ST/RM/CV impression pricing.
MeterThe new Stripe API for usage-based billing (replaces legacy Usage Records API). Adventive should evaluate Meters vs. legacy Usage Records at B.4 — Meters offer idempotency guarantees natively.
Point of no return (B.8)The phase at which legacy billing_service is retired and the billing Worker is the sole billing runtime. After B.8, rollback requires restoring from DB backup and restarting billing_service — not a quick revert. Extra scrutiny required before B.8.
R2Cloudflare’s S3-compatible object storage. Stores invoice PDFs generated by the billing Worker (replaces billing.adventivecdn.com S3/CloudFront CDN).
reconciliationComparing Stripe invoice totals against the legacy billing_invoice DB (during dual-run) or against Acodei/QuickBooks (post-migration) to detect discrepancies. Zero tolerance: no drift is acceptable before a cohort is marked migrated.
Smart RetriesStripe’s machine-learning-based payment retry system. Automatically retries failed payments at times statistically more likely to succeed. Must be explicitly configured on the Stripe account.
Stripe-SignatureHTTP header set by Stripe on every webhook delivery. Contains an HMAC-SHA256 signature over the raw request body. Billing Worker must verify this header before processing any event.
subscriptionA Stripe object that manages recurring billing for a customer. The billing Worker creates one Subscription per Adventive customer with the appropriate flat + metered Prices attached.
Usage RecordA data point submitted to Stripe for a metered Price, reporting the quantity of usage for a subscription item in a period. Used to calculate the metered portion of a subscription invoice.

All formal decisions are in decisions/. Summary of locked-in decisions referenced throughout this document:

DecisionSummaryFile
Stripe Billing scopeStripe owns billing engine; Adventive owns PDF + email + metering signaldecisions/2026-04-23-stripe-billing-scope.md
Custom invoice PDF retainedCustom PDF non-negotiable; Cloudflare Browser Rendering leading candidatedecisions/2026-04-23-custom-invoice-pdf-retained.md

VersionDateAuthorChange
1.02026-04-23Jeffrey LambertInitial planning deliverable — repo analysis complete; Stripe inventory complete; all chapters populated; PDF generated