# How DataForSEO API Credit Billing Classification Works in OpenSEO

> Understand DataForSEO API credit billing in OpenSEO. Learn how requests map to features, costs are marked up, converted to credits, and deducted from your pool.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: how-to-guide
- Published: 2026-08-10

---

**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)](https://github.com/every-app/open-seo/blob/main/src/shared/billing-credit-features.ts) (lines 38-71) handles this mapping:

```ts
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_research`
- `domain_overview`
- `backlinks`
- `site_audit`
- `rank_tracking`
- `ai_citations`
- `ai_prompt_responses`
- `local_seo`
- `onboarding`
- `agent`

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)](https://github.com/every-app/open-seo/blob/main/src/server/lib/dataforseo/client.ts) (lines 48-61). The `meter` function provides:

1. **Pre-flight credit check** – `assertUsageCreditsAvailable` verifies the organization has sufficient usage credits and returns the current `monthlyRemaining` balance
2. **Actual SDK execution** – The wrapped DataForSEO call proceeds only if credits are available
3. **Post-call cost tracking** – `trackDataforseoCost` records the spend using either the auto-derived feature from the path mapping or an explicit `creditFeature` override

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)](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`:

```ts
// 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**: `monthlyRemaining` usage 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`:

```ts
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`](https://github.com/every-app/open-seo/blob/main/src/shared/billing.ts) | `1.28` | Platform margin multiplier |
| `AUTUMN_SEO_DATA_CREDITS_PER_USD` | [`src/shared/billing.ts`](https://github.com/every-app/open-seo/blob/main/src/shared/billing.ts) | `1000` | USD-to-credit conversion rate |
| `CreditFeature` enum | [`src/shared/billing-credit-features.ts`](https://github.com/every-app/open-seo/blob/main/src/shared/billing-credit-features.ts) | 10 variants | Product feature taxonomy |

---

## Summary

- **Classification**: `mapDataforseoPathToCreditFeature` maps API paths to product features in [`src/shared/billing-credit-features.ts`](https://github.com/every-app/open-seo/blob/main/src/shared/billing-credit-features.ts)
- **Metering**: The `meter` wrapper in [`src/server/lib/dataforseo/client.ts`](https://github.com/every-app/open-seo/blob/main/src/server/lib/dataforseo/client.ts) enforces 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 `assertUsageCreditsAvailable` failures that prevent further paid API usage
- **Observability**: All consumption emits `usage:credits_consume` events 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`](https://github.com/every-app/open-seo/blob/main/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`](https://github.com/every-app/open-seo/blob/main/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.