How DataForSEO API Credit Billing Classification Works in OpenSEO
DataForSEO API credit billing classification in OpenSEO maps every API request to a product feature, applies a 28% markup to the raw USD cost, converts it to credits at 1000 credits per dollar, and deducts the amount from the organization's shared monthly and rollover credit pool.
OpenSEO uses DataForSEO as a primary data provider for SEO intelligence. Every API call incurs real costs that must be allocated, tracked, and billed against customer credit balances. The system implements a three-stage classification and metering pipeline that ensures accurate cost attribution while preventing over-spend through built-in credit enforcement.
Mapping Endpoints to Credit Features
The first step in the billing pipeline classifies the API request into a high-level product feature. This abstraction allows customers to understand their spend by capability (e.g., "Backlinks" or "Keyword Research") rather than by raw API endpoint.
The mapDataforseoPathToCreditFeature function in [src/shared/billing-credit-features.ts](https://github.com/every-app/open-seo/blob/main/src/shared/billing-credit-features.ts) (lines 38-71) handles this mapping:
import { mapDataforseoPathToCreditFeature } from "@/shared/billing-credit-features";
const path = ["v3", "backlinks", "summary", "live"];
const feature = mapDataforseoPathToCreditFeature(path);
// feature === "backlinks"
The function returns one of ten CreditFeature enum values:
keyword_researchdomain_overviewbacklinkssite_auditrank_trackingai_citationsai_prompt_responseslocal_seoonboardingagent
This classification decouples billing from DataForSEO's internal API versioning, allowing the pricing model to remain stable even when underlying endpoints change.
Metering Calls and Enforcing Credit Availability
Every DataForSEO client method is wrapped by the metering layer implemented in [src/server/lib/dataforseo/client.ts](https://github.com/every-app/open-seo/blob/main/src/server/lib/dataforseo/client.ts) (lines 48-61). The meter function provides:
- Pre-flight credit check –
assertUsageCreditsAvailableverifies the organization has sufficient usage credits and returns the currentmonthlyRemainingbalance - Actual SDK execution – The wrapped DataForSEO call proceeds only if credits are available
- Post-call cost tracking –
trackDataforseoCostrecords the spend using either the auto-derived feature from the path mapping or an explicitcreditFeatureoverride
This wrapper ensures no paid API call can execute without credit authorization. In self-hosted mode, these checks may be bypassed, but in hosted mode the enforcement is strict.
Converting Costs and Consuming Credits
The actual credit deduction happens in [src/server/billing/subscription.ts](https://github.com/every-app/open-seo/blob/main/src/server/billing/subscription.ts) (lines 223-288) via the trackUsageCreditSpend function. This implementation follows four precise steps:
1. Apply Platform Markup
Raw DataForSEO costs are multiplied by 28% markup (SEO_DATA_COST_MARKUP = 1.28) and rounded using roundUsdForBilling:
// From src/shared/billing.ts (lines 15-37)
export const SEO_DATA_COST_MARKUP = 1.28;
export const AUTUMN_SEO_DATA_CREDITS_PER_USD = 1000;
2. Convert USD to Credits
The marked-up dollar amount converts to credits at 1000 credits per USD. A $1.25 API call becomes 1,600 credits after markup.
3. Deduct From Balance Pool
Credits are consumed in strict priority order:
- First:
monthlyRemainingusage credits (subscription allowance) - Second:
topup_credits(rollover or purchased credits)
4. Emit Audit Event
A usage:credits_consume event fires to PostHog for analytics and customer-facing usage dashboards.
When credits are exhausted, checkUsageCreditsDepleted and assertUsageCreditsAvailable block further paid endpoints until the subscription renews or additional credits are purchased.
Manual Credit Charging (Advanced)
While the meter wrapper handles standard cases, direct credit charges are possible through trackUsageCreditSpend:
import { trackUsageCreditSpend } from "@/server/billing/subscription";
import { getOrCreateOrganizationCustomer } from "@/server/billing/subscription";
async function chargeManual(
ctx: BillingCustomerContext,
costUsd: number,
feature: CreditFeature,
) {
const billingCustomer = await getOrCreateOrganizationCustomer(ctx);
const { monthlyRemaining } = await assertUsageCreditsAvailable(billingCustomer.id);
await trackUsageCreditSpend({
customer: ctx,
customerId: billingCustomer.id,
creditFeature: feature,
costUsd,
monthlyRemaining,
});
}
This pattern is rarely needed but enables custom integrations or non-standard DataForSEO endpoints not covered by the automatic path mapping.
Key Configuration Constants
| Constant | Location | Value | Purpose |
|---|---|---|---|
SEO_DATA_COST_MARKUP |
src/shared/billing.ts |
1.28 |
Platform margin multiplier |
AUTUMN_SEO_DATA_CREDITS_PER_USD |
src/shared/billing.ts |
1000 |
USD-to-credit conversion rate |
CreditFeature enum |
src/shared/billing-credit-features.ts |
10 variants | Product feature taxonomy |
Summary
- Classification:
mapDataforseoPathToCreditFeaturemaps API paths to product features insrc/shared/billing-credit-features.ts - Metering: The
meterwrapper insrc/server/lib/dataforseo/client.tsenforces credit availability before every call - Cost calculation: Raw USD costs multiply by 1.28, convert at 1000 credits/USD, then deduct from monthly then rollover balances
- Blocking: Exhausted credit pools trigger
assertUsageCreditsAvailablefailures that prevent further paid API usage - Observability: All consumption emits
usage:credits_consumeevents to PostHog
Frequently Asked Questions
What happens when an organization runs out of credits?
The system blocks further DataForSEO API calls. The assertUsageCreditsAvailable function in src/server/billing/subscription.ts checks balances before every metered request and throws a credit-depleted error if monthlyRemaining and topup_credits are both zero or insufficient.
Can I override the automatic feature classification for a DataForSEO call?
Yes. While the meter function auto-derives features from the API path, callers can supply an explicit creditFeature parameter to override the mapping. This is useful for experimental endpoints or specialized billing treatments not yet in the path-to-feature registry.
How does the 28% markup translate to customer pricing?
DataForSEO reports costs in USD (e.g., $0.005 per 100 results). OpenSEO applies SEO_DATA_COST_MARKUP = 1.28 to cover infrastructure, platform operations, and margin, then converts to credits. Customers see and manage spend in credits rather than raw USD, abstracting provider cost volatility.
Where is the credit conversion rate configured if it needs to change?
The constant AUTUMN_SEO_DATA_CREDITS_PER_USD = 1000 lives in src/shared/billing.ts alongside the markup multiplier. Changing this value affects all future credit calculations but does not retroactively adjust historical transactions, as credits are deducted at call time.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →