Skip to content

Credit Pricing System

Overview

Credits are the billing unit for PDF conversions. Each page in a document is classified by content type before conversion, and credits are charged based on the complexity of each page. This replaces the previous flat 1-credit-per-page model.

Pricing Table

Content TypeCredits/PageDetection MethodProcessing Pipeline
Pure text1No images, tables, or math operatorsMarker fast path β†’ cascade if quality < 80
Math / equations1Math font names (cmsy, stix, etc.) or image mask densityMathpix (native equation rendering)
Image pages2paintImageXObject operators in PDF streamGemini Flash alt text + vision fallback
Tables2Path-drawing operators (β‰₯10 draw + paint ops) or struct tree tagsStruct-tree extraction (free) or vision extraction
Dense tables3Text position clustering (β‰₯5 rows, β‰₯3 aligned columns, no gridlines)Always requires AI vision (MathPix or agentic vision)
Mixed content3Combination of images + tables + text on same pageFull agentic vision with iterative screenshot comparison

How Classification Works

Classification runs before conversion with zero API calls. It uses PDF binary operator inspection:

  1. classifyDocumentPages() in workers/api/src/services/pdf-complexity-detector.ts scans every page’s operator list
  2. Each page gets a contentType: text, math, image, table, dense-table, or mixed
  3. The estimate endpoint (POST /api/convert/:fileId/estimate) returns a CreditEstimate with per-type breakdown
  4. Credits are computed by estimateCredits() in workers/api/src/services/credit-estimator.ts

Pre-Conversion Credit Check

Before conversion starts, the system checks the user has enough credits using a worst-case estimate of 3 credits/page (the maximum rate). This prevents undercharging if classification misses complexity. The actual deduction after conversion uses the real classification.

Credit Deduction Points

Credits are deducted after successful conversion, not before:

PathWhere DeductedFile
Synchronous (struct-table, Mathpix, Marker)Inline after conversion completesworkers/api/src/routes/convert.ts
Chunked async (agentic vision)After chunk assembly completesworkers/api/src/scheduler/chunk-scheduler.ts

For chunked conversions, the pre-computed credit total is stored in the job’s options._creditsToDeduct field at creation time and read back at assembly time.

Smart Cascade (Quality-Based Escalation)

The system always attempts the cheapest viable pipeline first and escalates if output quality is below 80/100:

Text page β†’ Marker ($0.006) β†’ if score < 80 β†’ Gemini Flash β†’ if score < 80 β†’ Claude Sonnet
Math page β†’ Marker+temml β†’ if score < 80 β†’ MathPix β†’ if score < 80 β†’ Vision
Image page β†’ MathPix β†’ if score < 80 β†’ Vision cascade
Dense table β†’ MathPix β†’ if score < 80 β†’ Vision cascade

This means every page gets the best quality output regardless of its credit rate β€” the credit rate reflects the expected processing cost, not the quality level.

Quality Score Components

The 80-point threshold is a composite of:

  • 30% axe-core critical/serious violations
  • 15% semantic HTML ratio
  • 10% heading hierarchy validity
  • 10% table accessibility (headers, scope)
  • 10% custom WCAG validator
  • 10% equation rendering (MathML vs raw LaTeX)
  • 10% alt text quality
  • 5% image alt coverage

Post-Assembly Quality Gate

After all chunks are assembled, a final quality gate runs:

  1. Detects β€œthin” pages (< 100 chars of text content)
  2. Detects tables with headers but no data rows
  3. For flagged pages: renders as PNG, sends to Claude Vision for comprehensive description
  4. Wraps fallback in expandable <details> panel

Form Credits (Separate)

Form conversion is a separate premium action, not part of base page pricing:

  • Standard form: 3 credits/page (FORM_CREDIT_MULTIPLIER)
  • Premium form: 5 credits/page (PREMIUM_FORM_CREDIT_MULTIPLIER)

Forms are detected during preflight via AcroForm field inspection and offered as an upsell after base conversion completes.

User-Facing UI

  • Settings > Billing: Pricing table showing all content types and rates
  • Dashboard: β€œAuto-convert on upload” toggle β€” when off, files show a credit estimate breakdown before the user clicks Convert
  • Credit Estimate Panel: Expandable inline component showing per-content-type breakdown with page counts and subtotals

Key Files

FilePurpose
workers/api/src/services/credit-estimator.tsBASE_CREDITS map, estimateCredits(), computeCreditsFromClassification()
workers/api/src/services/pdf-complexity-detector.tsPer-page classification (classifyDocumentPages())
workers/api/src/services/smart-cascade-converter.tsQuality-based pipeline escalation
workers/api/src/services/quality-gate.tsPost-assembly thin page detection
workers/api/src/services/quality-scorer.ts80-point composite quality score
workers/api/src/routes/convert.tsEstimate endpoint + credit deduction
workers/api/src/scheduler/chunk-scheduler.tsChunked conversion credit deduction
apps/web/src/hooks/useCreditEstimate.tsFrontend estimate hook with caching
apps/web/src/components/dashboard/control-center/CreditEstimatePanel.tsxEstimate breakdown UI
apps/web/src/app/settings/page.tsxPricing table in Settings > Billing
packages/shared/src/constants.tsForm credit multipliers