How OpenSEO Handles DataForSEO API Rate Limits and Billing
OpenSEO manages DataForSEO API constraints through a layered architecture that maps HTTP 429 responses to typed RATE_LIMITED errors, converts HTTP 402 balance errors into specific billing AppError codes, and tracks usage credits with configurable pricing markups.
OpenSEO integrates DataForSEO (DF-SEO) services using a sophisticated billing and rate-limiting system designed to prevent double-charging and handle API constraints gracefully. The open-source codebase implements distinct credit pools, automated retry policies, and granular error classification to ensure predictable costs for hosted customers while allowing self-hosted deployments to pay raw DF-SEO rates. Understanding how OpenSEO handles DataForSEO API rate limits and billing reveals a robust pattern for third-party API cost management.
Centralized Request Wrapper with Authentication
All DataForSEO API calls flow through the createAuthenticatedFetch function in src/server/lib/dataforseo/core.ts, which serves as the primary gateway for request authentication and baseline error handling. This wrapper automatically injects the DATAFORSEO_API_KEY environment variable into request headers and enforces a strict 60-second timeout on all outbound calls.
The wrapper distinguishes between idempotent reads (such as keyword data fetches) and non-idempotent operations (like Lighthouse live tests). Idempotent requests automatically retry on transient 5xx errors up to two times with a 250ms backoff per attempt, while non-idempotent calls disable retries entirely to prevent accidental double-charging.
Billing Classification and Balance Error Detection
When DataForSEO returns non-2xx responses, OpenSEO employs a specialized classification system to distinguish between generic failures and billing-specific issues. The createDataforseoBillingClassifier function in src/server/lib/dataforseoBillingClassification.ts analyzes error responses for HTTP 402 status codes or message content containing "insufficient funds".
When detected, the system throws a typed AppError with specific codes such as BACKLINKS_BILLING_ISSUE, AI_BILLING_ISSUE, or KEYWORDS_BILLING_ISSUE. This allows upstream workflows to surface clear "billing problem" messages to users rather than generic failure notifications.
// Example: Performing a DF-SEO request with billing & rate-limit handling
import { keywordsDataApi } from "@/server/lib/dataforseo/core";
import { createDataforseoBillingClassifier } from "@/server/lib/dataforseoBillingClassification";
const classifyKeywordsError = createDataforseoBillingClassifier({
pathPrefix: "/keywords/",
billingIssueCode: "KEYWORDS_BILLING_ISSUE",
billingIssueMessage: "The connected DataForSEO account has a billing or balance issue",
});
async function fetchKeywordIdeas(projectId: string, kw: string) {
const response = await keywordsDataApi(classifyKeywordsError).relatedKeywordsLive([
/* request payload… */
]);
// `assertOk` throws a RATE_LIMITED AppError if DF-SEO returned 429
const task = assertOk(response, { classify: classifyKeywordsError, classifyPath: "/v3/keywords_data/related_keywords/live" });
// Billing info is attached to the task result
const { data, billing } = parseTaskItems(task);
return { data, billing };
}
Usage Credit Pools and Pricing Markup
OpenSEO tracks two distinct credit pools: monthly usage credits and top-up credits. The system deducts costs first from the monthly pool, then from any available top-up balance. The conversion rate is fixed at 1 USD to 1000 DF-SEO credits, defined by the AUTUMN_SEO_DATA_CREDITS_PER_USD constant in src/shared/billing.ts.
For hosted customers, the platform applies a markup factor of approximately 1.28× to raw DataForSEO costs before billing the amount to their OpenSEO subscription. The applyBillingMarkupUsd function handles this calculation, while isHostedServerAuthMode() checks determine whether to apply credit deductions or allow direct DF-SEO billing.
Self-hosted deployments bypass the OpenSEO credit pool entirely, paying DataForSEO directly using the raw cost conversion via autumnSeoDataCreditsToUsd without any platform markup.
Rate Limit Handling and Retry Policies
When DataForSEO returns HTTP 429 (RATE_LIMITED), the createAuthenticatedFetch wrapper maps this to a generic RATE_LIMITED error code within the AppError type. Calling workflows such as rank-checking or backlink fetching can then decide whether to retry later or surface a user-friendly rate-limit message.
For internal billing operations, the fetchAutumnEventsPage function in src/serverFunctions/billing.ts implements exponential backoff when Autumn's events.list endpoint returns HTTP 429. This retry logic uses a maximum retry count to prevent infinite loops while ensuring usage data eventually synchronizes.
// Example: Fetching billing usage events (rate-limited retry)
import { getBillingUsageEvents } from "@/serverFunctions/billing";
await getBillingUsageEvents({ start: 0, end: Date.now() });
// Internally this will back‑off on 429 responses from Autumn and retry up to 3 times.
Billing Usage Reporting and Balance Monitoring
The platform periodically queries Autumn's API to pull usage-credit events, aggregating them into consumable lists for the user interface. The getBillingUsageEvents function handles this synchronization, complete with rate-limit aware retry logic.
For real-time balance checks without consuming credits, the whoami tool in src/server/mcp/tools/whoami.ts exposes current credit balances. Additionally, src/server/lib/market.ts guards feature usage based on supported DataForSEO locations, preventing API calls that would immediately fail and waste credits on unsupported regions.
Self-Hosted vs. Hosted Mode Behavior
The system behaves differently depending on deployment mode. Hosted mode activates the full credit pool system, applies the 1.28× markup, and manages DataForSEO API keys centrally. Self-hosted mode bypasses these mechanisms, allowing direct payment to DataForSEO and eliminating the markup layer.
This distinction is enforced through isHostedServerAuthMode() checks in src/serverFunctions/billing.ts, which trigger early returns for non-hosted environments, ensuring self-hosted users are charged only for raw DataForSEO consumption.
Summary
- Authentication Layer: All requests route through
createAuthenticatedFetchinsrc/server/lib/dataforseo/core.tswith 60s timeouts and automatic API key injection. - Billing Errors: The
createDataforseoBillingClassifierconverts HTTP 402 and "insufficient funds" messages into typedAppErrorcodes likeBACKLINKS_BILLING_ISSUE. - Credit System: Hosted customers use a dual-pool system (monthly + top-up) with 1 USD = 1000 credits and a 1.28× markup applied via
applyBillingMarkupUsd. - Rate Limiting: HTTP 429 responses map to
RATE_LIMITEDerrors, with exponential backoff for Autumn billing events and configurable retries for idempotent DF-SEO reads. - Deployment Modes: Self-hosted installations pay raw DF-SEO rates without markup, while hosted users participate in the managed credit pool system.
Frequently Asked Questions
How does OpenSEO prevent double-charging when DataForSEO API calls fail?
OpenSEO disables automatic retries for non-idempotent operations (such as Lighthouse live tests) within the createAuthenticatedFetch wrapper, ensuring failed requests are not blindly retried. Idempotent reads retry only on transient 5xx errors with a maximum of two attempts and 250ms backoff, preventing duplicate charges while handling temporary outages.
What happens when my DataForSEO account runs out of credits?
When DataForSEO returns HTTP 402 or messages containing "insufficient funds", the createDataforseoBillingClassifier throws a specific AppError (such as AI_BILLING_ISSUE or KEYWORDS_BILLING_ISSUE). This surfaces a clear billing problem message to the user rather than a generic API error, allowing immediate identification of balance issues.
How does credit pricing differ between hosted and self-hosted OpenSEO deployments?
Hosted customers pay a marked-up rate of approximately 1.28× the raw DataForSEO cost, managed through OpenSEO's credit pool system (1 USD = 1000 credits). Self-hosted deployments bypass this entirely, paying DataForSEO directly at raw rates without platform markup or credit pool management.
Where does OpenSEO handle retry logic for DataForSEO API rate limits?
Primary rate-limit handling occurs in src/server/lib/dataforseo/core.ts, where HTTP 429 responses map to RATE_LIMITED error codes. For billing-specific rate limits when querying Autumn's events.list endpoint, src/serverFunctions/billing.ts implements exponential backoff with maximum retry limits to ensure reliable usage reporting without overwhelming upstream services.
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 →