Base URL: https://apiapk.cc/api/v1. Sign up, create an API key in your account and send your first request:
Machine-readable API description: OpenAPI 3.1 · Postman collection — import it into Postman, Insomnia or a client generator (openapi-generator) to get a ready SDK for your language.
curl -H "X-API-Key: YOUR_KEY" "https://apiapk.cc/api/v1/app?id=com.whatsapp"
The data covers over 4 million Google Play apps from the US storefront in English (from another country if an app is not available in the US), refreshed nightly. Apps that disappear from the store stay in the database with their last data.
Every request except /v1/health must include the API key in a header:
X-API-Key: ak_live_…
Also accepted: Authorization: Bearer …. Passing the key in URL parameters is not allowed: it would end up in logs and browser history.
Each call costs 0–3 credits depending on the endpoint, regardless of the number of rows in the response (up to 100); the batch apps call costs 1 credit per app. Plan credits for the current month are used first, then the prepaid balance. If a request fails on our side, the credits are returned. Plans & packs
| Header | Meaning |
|---|---|
X-Credits-Cost | credits this request cost |
X-Credits-Remaining | credits left (plan + balance) |
X-Cache | HIT — served from cache (faster), MISS — fresh query to the index |
X-RateLimit-Limit / -Remaining | the key's per-minute limit and what's left |
X-Plan | free | pro | scale | business |
Your remaining credits are also in the _credits field of every response and in /v1/account (free).
Every response has an ok field. Lists contain results, total, page, per, pages. Error: ok = false, error is the explanation, code is a machine-readable code. Dates are ISO 8601 in UTC.
{ "ok": true, "app": { "id": "com.whatsapp", "title": "WhatsApp", "installs": { "label": "10,000,000,000+", "min": 10000000000, "real": 12445120489 }, … },
"_credits": { "cost": 1, "plan_remaining": 1999, "balance": 0, "available": 1999, "cached": false } }
{ "ok": false, "code": "insufficient_credits", "error": "Not enough credits: this call costs 2, you have 1. …" }
| HTTP | code | When |
|---|---|---|
| 400 | invalid_param, invalid_request | invalid or missing parameter |
| 401 | missing_api_key, invalid_api_key | no key, or the key is revoked |
| 402 | insufficient_credits | not enough credits — top up or upgrade your plan |
| 403 | account_blocked, plan_required | the account is blocked, or the endpoint requires a higher plan |
| 404 | not_found | the app or developer isn't in the database, or the endpoint is unknown |
| 429 | rate_limited | per-minute request limit exceeded |
| 503 | service_unavailable | a temporary database problem — retry later; no credits are charged |
All endpoints are GET /api/v1/{name}. Pagination: page (from 1) and per (1–100), up to the 10,000th result. Sorting: sort + order=asc|desc.
Your plan, plan credits and balance, the credit reset date and the per-minute limit.
The full app record: title, description, what's new, installs (threshold and exact number), rating, number of ratings and reviews, star distribution, price, in-app purchases, ads, category, content rating, version, minimum Android, release and update dates, icon, screenshots, video, developer and their website. For removed apps: the last saved data and the removal date.
id * | app package name |
Up to 100 apps in one call: GET ?ids=a,b,c or POST with the list in the body (one per line, or JSON {"ids": […]}). 1 credit per app; ids we don't have come back in not_found.
ids * | package names, comma-separated, up to 100 |
Search and filters over the whole database. At least one filter is required. Without q, results are sorted by installs.
q | words to search in the title, description and developer name |
category | category ID, e.g. GAME_PUZZLE (see /v1/categories) |
developer_id | Google Play developer ID |
min_installs | minimum installs (Google Play thresholds: 1000, 10000…) |
max_installs | maximum installs |
min_score | minimum rating, 0–5 |
min_ratings | minimum ratings |
free | true — free only, false — paid only |
ads | true — with ads, false — without |
iap | true — with in-app purchases |
lang | title language, ISO code: en, de, pt… |
released_from | released from this date, YYYY-MM-DD |
released_to | released up to this date, inclusive |
updated_from | updated from this date |
updated_to | updated up to this date, inclusive |
status | live (in the store, default), removed or all |
sort | relevance | installs | real_installs | score | ratings | reviews | released | updated | price |
order | desc | asc |
page | page, from 1 |
per | rows per page, 1–100 (default 20) |
Suggestions by the start of a title: the 10 most popular matches. Free.
q * | start of the title, 2+ characters |
A developer and all their apps: counts (in the store and removed), total installs, average rating, first release, categories, website. On the Business plan: email, phone, address and legal name.
id | developer ID (from an app: developer.id) |
name | or the exact developer name |
status | all (default), live or removed |
sort | relevance | installs | real_installs | score | ratings | reviews | released | updated | price |
page | page, from 1 |
per | rows per page, 1–100 (default 20) |
New apps by first release date, newest first.
since | from this date, YYYY-MM-DD (default: 7 days ago) |
until | up to this date, inclusive |
category | category ID, e.g. GAME_PUZZLE (see /v1/categories) |
min_installs | minimum installs (Google Play thresholds: 1000, 10000…) |
lang | title language, ISO code: en, de, pt… |
sort | relevance | installs | real_installs | score | ratings | reviews | released | updated | price |
page | page, from 1 |
per | rows per page, 1–100 (default 20) |
Apps that disappeared from Google Play (missing in all 19 countries we check), by removal date. The app record keeps its last data.
since | from this date, YYYY-MM-DD (default: 7 days ago) |
until | up to this date, inclusive |
category | category ID, e.g. GAME_PUZZLE (see /v1/categories) |
min_installs | minimum installs (Google Play thresholds: 1000, 10000…) |
sort | removed_at | installs | score |
page | page, from 1 |
per | rows per page, 1–100 (default 20) |
Words and phrases from app titles for each language: how many apps and developers use them, how many of those are strong (100K+ installs), total installs, the leader's share and an opportunity score.
lang | language, default en |
q | word or phrase |
phrase | true — two-word phrases only, false — single words only |
min_apps | minimum apps |
max_apps | maximum apps |
sort | opportunity | apps | installs | strong | devs | max_installs |
order | desc | asc |
page | page, from 1 |
per | rows per page, 1–100 (default 20) |
All categories with app counts and total installs. Free.
status | live (in the store, default), removed or all |
Apps whose developer website domain is available to register, with the app's popularity. Pro plan and higher.
category | category ID, e.g. GAME_PUZZLE (see /v1/categories) |
min_installs | minimum installs (Google Play thresholds: 1000, 10000…) |
status | live (in the store, default), removed or all |
tld | domain zone, e.g. com |
sort | relevance | installs | real_installs | score | ratings | reviews | released | updated | price |
page | page, from 1 |
per | rows per page, 1–100 (default 20) |
A Google Play top chart for one country and category: up to 200 positions, rank change since the previous snapshot (change: how many places it moved up, "new" for new entries), icon and installs.
country * | country, ISO code: US, DE, BR… |
category * | category, e.g. GAME_PUZZLE |
collection | free | paid | grossing |
page | page, from 1 |
per | rows per page, 1–100 (default 20) |
Every chart the app is in, in the latest snapshot: country, category, collection, position; the number of charts and countries, and the best position.
id * | app package name |
country | one country only |
collection | free | paid | grossing |
Countries where the app is available on Google Play (from hreflang in the store sitemap). With 190+ countries, worldwide = true is returned without a list.
id * | app package name |
Market competition based on free charts: the entry threshold for the top 100 and top 200 (installs of the app at that position), the share of new (last 12 months) and local (≤3 countries) apps in the top, and the size of the local market. No parameters: all countries; country: the categories of one country; category: one category across all countries.
country | country, ISO code |
category | category ID, e.g. GAME_PUZZLE (see /v1/categories) |
sort | entry100 | entry200 | new_share | local_share | local_apps | local_installs | local_new |
order | desc | asc |
page | page, from 1 |
per | rows per page, 1–100 (default 20) |
Database size: apps in the store and removed, developers, new and removed in the last 7 days, time of the last update. Free.
* — required parameter
# curl — one app
curl -H "X-API-Key: $KEY" "https://apiapk.cc/api/v1/app?id=org.telegram.messenger"
# curl — puzzle games with 10M+ installs, best rated first
curl -H "X-API-Key: $KEY" "https://apiapk.cc/api/v1/search?category=GAME_PUZZLE&min_installs=10000000&sort=score"
# curl — up to 100 apps in one call (POST, one package per line)
curl -H "X-API-Key: $KEY" --data-binary $'com.whatsapp\norg.telegram.messenger' "https://apiapk.cc/api/v1/apps"
# Python — apps removed from Google Play this week
import os, requests
r = requests.get("https://apiapk.cc/api/v1/removed",
params={"since": "2026-10-20", "min_installs": 100000, "per": 100},
headers={"X-API-Key": os.environ["KEY"]}, timeout=30)
r.raise_for_status()
data = r.json()
for app in data["results"]:
print(app["removed_seen_at"], app["id"], app["installs"]["label"])
print("credits left:", data["_credits"]["available"])
// Node.js 18+ (on the server — not in the browser)
const res = await fetch("https://apiapk.cc/api/v1/developer?id=5191370068110375942", { headers: { "X-API-Key": process.env.KEY } });
const d = await res.json();
if (!d.ok) throw new Error(d.error);
console.log(d.developer.name, d.developer.apps, d.developer.total_installs);
// PHP
$ch = curl_init('https://apiapk.cc/api/v1/keywords?lang=en&q=vpn&per=50');
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['X-API-Key: ' . getenv('KEY')]]);
$d = json_decode(curl_exec($ch), true);
foreach ($d['results'] as $k) echo $k['keyword'], ' — ', $k['apps'], PHP_EOL;
You can create a key in your account. The request goes straight from your browser. The key is not stored anywhere and is gone after a page reload. Requests from the console spend credits like any other.