How OpenSEO Meters Billing for DataForSEO API Calls: A Technical Breakdown

OpenSEO tracks DataForSEO API costs through an internal credit pool, converting raw USD prices to credits at 1000 credits per dollar and applying a 28% markup for hosted deployments before deducting from user balances.

The every-app/open-seo repository implements a metered-billing pipeline that ensures every third-party DataForSEO request is accurately accounted for and billed. Understanding how OpenSEO meter billing for DataForSEO API calls works is essential for developers customizing the platform or integrating their own usage-tracking systems. The system bridges raw DataForSEO pricing with user-facing balances through a series of deterministic conversion and markup stages.

Credit Conversion and the Internal Pool

OpenSEO abstracts raw USD costs into an internal usage-credit pool to simplify balance tracking. When DataForSEO returns a price for any endpoint—whether keyword research, backlink analysis, or rank checking—the system immediately converts that value.

The conversion constant AUTUMN_SEO_DATA_CREDITS_PER_USD is set to 1000 in src/shared/billing.ts. This means a DataForSEO call costing $0.05 consumes 50 credits from the user's pool. The raw USD value returned by the API (stored as rawUsd) is multiplied by this constant to determine the credit deduction.

/* src/shared/billing.ts */
export const AUTUMN_SEO_DATA_CREDITS_PER_USD = 1000;

/** Convert internal credits back to USD (e.g., for balance display) */
export function autumnSeoDataCreditsToUsd(credits: number) {
  return credits / AUTUMN_SEO_DATA_CREDITS_PER_USD;
}

This abstraction allows the platform to display balances in whole numbers while maintaining precision for fractional cent transactions.

Hosted vs. Self-Hosted Billing Markup

The billing pipeline diverges based on deployment mode. Hosted OpenSEO customers pay a 28% markup over raw DataForSEO costs to cover platform infrastructure, while self-hosted deployments pass through raw pricing directly.

The markup is controlled by the constant SEO_DATA_COST_MARKUP = 1.28 and applied through the applyBillingMarkupUsd() function:

/* src/shared/billing.ts */
export const SEO_DATA_COST_MARKUP = 1.28;

/** Round to 5 decimal places for Stripe */
export function roundUsdForBilling(value: number) {
  return Math.round(value * 100_000) / 100_000;
}

/** Convert raw DataForSEO USD → displayed USD (hosted only) */
export function applyBillingMarkupUsd(rawUsd: number): number {
  return roundUsdForBilling(rawUsd * SEO_DATA_COST_MARKUP);
}

The roundUsdForBilling() function ensures Stripe compatibility by rounding to five decimal places, preventing floating-point arithmetic errors during checkout.

Balance Checking and Credit Thresholds

Before executing any DataForSEO call, OpenSEO validates available funds against two distinct balance types:

  • usage_credits: The monthly free quota allocated by subscription tier
  • topup_credits: Additional credits purchased via one-time top-ups

The system checks balances in sequence, drawing from free credits first, then top-up credits. If the combined balance falls below LOW_CREDITS_THRESHOLD_USD = 0.25, the UI triggers a low-credit warning.

/* src/shared/billing.ts */
export const LOW_CREDITS_THRESHOLD_USD = 0.25;
export const AUTUMN_SEO_DATA_BALANCE_FEATURE_ID = "usage_credits";
export const AUTUMN_SEO_DATA_TOPUP_BALANCE_FEATURE_ID = "topup_credits";

When credits are exhausted, the request is blocked and the user is redirected to purchase additional credits or upgrade their subscription.

Implementing Billing Display in Frontend Components

The applyBillingMarkupUsd() helper ensures consistent pricing display across the React frontend. In src/client/features/ai-search/components/BrandLookupSearchCard.tsx, the component conditionally applies the markup based on authentication mode:

/* src/client/features/ai-search/components/BrandLookupSearchCard.tsx */
import { applyBillingMarkupUsd } from "@/shared/billing";

function CostTag({ rawUsd }: { rawUsd: number }) {
  // Hosted customers see the markup, self-hosted see the raw cost.
  const displayedUsd = isHostedClientAuthMode()
    ? applyBillingMarkupUsd(rawUsd)
    : rawUsd;

  return <span>${displayedUsd.toFixed(2)}</span>;
}

This pattern ensures that self-hosted users see raw DataForSEO costs while hosted users see the marked-up price that will actually be deducted from their balance.

CLI Cost Profiling and Reporting

For administrative and auditing purposes, the repository includes CLI scripts that aggregate DataForSEO costs before applying markup. The scripts/brand-lookup-cost-profile.ts file demonstrates how to calculate both raw and billed costs for reporting:

/* scripts/brand-lookup-cost-profile.ts */
import { applyBillingMarkupUsd } from "@/shared/billing";

function computeCostReport(rawUsd: number) {
  // Raw cost from DataForSEO
  const totalRawUsd = rawUsd;

  // Hosted cost after markup
  const totalBilledUsd = applyBillingMarkupUsd(totalRawUsd);

  console.log(`Raw cost: $${totalRawUsd}`);
  console.log(`Billed (with markup): $${totalBilledUsd}`);
}

This separation allows finance teams to reconcile external DataForSEO invoices against internal credit consumption.

Stripe Integration and Checkout Flow

When balances deplete, the system initiates Stripe checkout sessions using predefined plan identifiers. The constants AUTUMN_PAID_PLAN_ID and AUTUMN_SEO_DATA_TOP_UP_PLAN_ID map to Stripe products:

  • base-plan: The recurring subscription tier
  • credit-top-up: One-time credit purchases

These identifiers, along with AUTUMN_CHECKOUT_SESSION_PARAMS, configure tax collection and billing information requirements during the checkout process. The /billing and /subscribe routes expose this logic to the frontend, ensuring seamless payment flow when usage_credits and topup_credits are insufficient.

Handling Concurrent API Workflows

Complex operations like site audits or batch rank checks may trigger multiple concurrent DataForSEO calls. The workflows in src/server/workflows/RankCheckWorkflow.ts and src/server/workflows/siteAuditWorkflowPhases.ts demonstrate how costs are batched and aggregated before being deducted from the credit pool.

Each task in these workflows calculates its individual DataForSEO cost, applies the markup if running in hosted mode, and then submits the total credit deduction to the balance system. This ensures that even with parallel execution, every API call is metered accurately without race conditions or double-charging.

Summary

  • OpenSEO meter billing for DataForSEO API calls converts raw USD costs to internal credits at a fixed rate of 1000 credits per dollar using AUTUMN_SEO_DATA_CREDITS_PER_USD.
  • Hosted deployments apply a 28% markup via applyBillingMarkupUsd() in src/shared/billing.ts, while self-hosted instances use raw DataForSEO pricing.
  • The system checks balances against usage_credits (monthly allowance) and topup_credits (purchased balance), warning users when funds drop below $0.25.
  • All prices are rounded to five decimal places using roundUsdForBilling() to ensure Stripe compatibility.
  • When credits are exhausted, the system blocks requests and redirects to Stripe checkout using plan IDs base-plan or credit-top-up.

Frequently Asked Questions

How does OpenSEO convert DataForSEO prices to internal credits?

OpenSEO multiplies the raw USD price returned by DataForSEO by the constant AUTUMN_SEO_DATA_CREDITS_PER_USD (set to 1000) to determine credit consumption. This conversion happens immediately upon receiving the API response, allowing the system to deduct precise amounts from the user's balance pool.

What is the difference between hosted and self-hosted billing?

Hosted customers pay a 28% markup over raw DataForSEO costs to cover platform infrastructure, calculated by multiplying the raw price by SEO_DATA_COST_MARKUP (1.28). Self-hosted deployments skip this markup entirely, displaying and charging only the raw DataForSEO price returned in the API response.

When does OpenSEO warn users about low credit balances?

The system triggers a low-credit warning when the combined balance of usage_credits and topup_credits falls below LOW_CREDITS_THRESHOLD_USD, which is set to $0.25. This check occurs before executing any new DataForSEO request, giving users opportunity to top up before service interruption.

What happens when a user's credit balance reaches zero?

When both usage_credits and topup_credits are depleted, OpenSEO blocks the DataForSEO request and prompts the user to purchase additional credits or upgrade their subscription. The frontend redirects to a Stripe checkout session configured with AUTUMN_CHECKOUT_SESSION_PARAMS, accepting payment for either the base-plan subscription or credit-top-up one-time purchases.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →