# Can a pay-per-call data API change its prices in the middle of my project?

> Any data API can reprice, as X and several scraper vendors did. How to spot a change automatically and keep a pay-per-call budget for X or Douyin data safe.

Canonical page: https://okdata.online/answers/data-api-price-changes/

**Short answer: **Yes. Any vendor can change prices, and several have, X among them. On okdata each call is charged the endpoint's price at the moment of the call (X post search is $0.006 today, Douyin search $0.02), the price book has a version number your script can watch, and every response states its exact charge, so a change shows up on the first call after it.

Price changes in data APIs are common enough to plan for. X replaced its $200-a-month Basic plan with [pay-per-use credits](https://opentermsarchive.org/en/memos/x-replaces-its-dollar200-entry-level-api-plan-with-a-pay-per-use-model/) in 2026. Users of a popular X scraper on a marketplace [questioned its new pricing per 1,000 results](https://apify.com/quacker/twitter-scraper/issues/unlogical-new-pricin-W1mTtb7ajE5rWMh15). On V2EX, developers noticed [API resellers raising prices across the board](https://www.v2ex.com/t/1027802). None of this is unusual. What matters is whether you notice the same day, or at month end.

## What okdata gives you to notice

- **A versioned price book.** `https://okdata.online/prices.json` lists every endpoint's price and carries a `price_book` version. If it changes, something was repriced.
- **The charge on every response.** `meta.billing.amount` is the exact cost of that call: [X post search](/apis/x/posts/search/) at $0.006, [Douyin video search](/apis/douyin/videos/search/) at $0.02.
- **No commitment to unwind.** With a prepaid balance and no plan, you can stop or switch the day prices stop working for you.

There is no price lock for a fixed period. For a long contract-style project, ask hello@okdata.online in writing.

## Make your pipeline notice

```python
import json, os, pathlib, requests
from decimal import Decimal

book = requests.get("https://okdata.online/prices.json", timeout=30).json()
seen = pathlib.Path("price_book.json")
if seen.exists() and json.loads(seen.read_text())["price_book"] != book["price_book"]:
    print("Price book changed: review prices before this run")
seen.write_text(json.dumps({"price_book": book["price_book"]}))

expected = {e["id"]: Decimal(e["price"]) for e in book["endpoints"]}
H = {"Authorization": f"Bearer {os.environ['OKDATA_API_KEY']}"}
body = requests.get("https://api.okdata.online/v1/x/posts/search", headers=H,
                    params={"query": "your brand", "sort": "latest"}, timeout=60).json()
charged = Decimal(body["meta"]["billing"]["amount"])
if charged > expected["x.posts.search"]:
    raise SystemExit(f"Charged {charged}, expected {expected['x.posts.search']}: stopping")
```

## Protect the budget itself

- **Prefer short commitments.** Annual prepayment buys a discount but makes a reprice painful. Pay-per-call with a modest balance limits exposure to what is already loaded.
- **Keep the vendor behind one function.** If your code calls `search_posts()` and not a vendor's URL directly, switching costs an afternoon instead of a rewrite.
- **Budget with headroom.** Price the plan at today's rates, then add 20 to 30 percent for re-runs and repricing.
- **Re-estimate before big pulls.** A two-minute check against the price book before a 50,000-call backfill is cheap insurance.

Current prices and the rules for what is never charged are on the [pricing page](/pricing/).

## Endpoints used

- [X post search](https://okdata.online/apis/x/posts/search/) `x.posts.search`: $0.006 per call · about 20 posts per page
- [Douyin video search](https://okdata.online/apis/douyin/videos/search/) `douyin.videos.search`: $0.02 per call · about 20 videos per page

Updated 2026-11-12
