Developers
APKCube API
Search Android apps, see which versions are available and download the APK, either from your own backend or from an AI agent. All three options below share one account and one credit balance.
On this page
Ways in
REST API
A JSON API authenticated with a bearer token. Search apps, fetch app details, list available builds and get a short-lived signed download URL.
- 29 endpoints, no SDK needed
- OpenAPI 3.1 spec for generating clients
- Every charged response shows what it cost
MCP server
A Model Context Protocol server over Streamable HTTP. Add one URL to Claude Code, Cursor or any other MCP client to get 38 tools.
- A single HTTP endpoint
- MCP 2026-07-28, and older clients still connect
- Signs in with OAuth or an API key, uses the same credits as REST
Agent skill
A single markdown file for agents that can run shell commands but don't support MCP. Add it to your agent and it can use the whole API, prices included.
- One file, nothing to install
- Contains no secrets
- Works anywhere with a shell
Quickstart#
Create an API key, send it as a bearer token, and you can start making requests. There is no SDK to install and no separate sandbox.
- Responses are JSON, and every charged one includes a header showing its cost.
- The same key works for the REST API, the skill file and the MCP server. MCP clients with a browser can sign in with OAuth instead.
/me,/categoriesand the availability check are free, so you can test a key without spending credits.
curl -sS "https://apkcube.com/api/v1/apps?q=whatsapp" \
-H "Authorization: Bearer $APKCUBE_API_KEY"const res = await fetch(
"https://apkcube.com/api/v1/apps?q=whatsapp",
{ headers: { Authorization: `Bearer ${process.env.APKCUBE_API_KEY}` } },
);
const { items } = await res.json();
console.log(items[0].packageName, res.headers.get("X-Credits-Remaining"));import os, requests
r = requests.get(
"https://apkcube.com/api/v1/apps",
params={"q": "whatsapp"},
headers={"Authorization": f"Bearer {os.environ['APKCUBE_API_KEY']}"},
)
print(r.json()["items"][0]["packageName"], r.headers["X-Credits-Remaining"])Pricing#
You buy credits and each call uses some of them. There are no plans or tiers to upgrade. Prices are set in our code, so they only change with a release and a changelog entry, never in the middle of a running job.
| Call | Credits | Notes |
|---|---|---|
| GET /me | free | Check that a key works and see its credit balance. |
| GET /categories | free | The category list used to filter searches. |
| GET /apps?q= | 1 | Search. 24 results per page, up to 60 matches in total. |
| GET /apps/{pkg} | 5 | The full listing for one package. |
| GET /apps/{pkg}/versions | 5 | All builds we have, newest first. Free when we hold no builds for the package (an empty list). |
| POST /apps/availability | free | Whether we have a build of up to 100 packages, each one's newest version, and the code and name of every version we have. For update checkers. |
| POST /apps/batch | 1 | Up to 100 packages in one call. Charged per package. |
| GET /apps/{pkg}/security | 5 | Checksum, scan result, signing certificates and permissions for one build. |
| GET /apps/{pkg}/sdks | 5 | Third-party libraries we detected in a build, and how much of it we could read. |
| GET /apps/{pkg}/trackers | 5 | Only the advertising, analytics and tracking libraries from that list, counted by category. |
| GET /apps/{pkg}/protection | 5 | Whether a build is packed, which limits what the other checks can see. |
| GET /apps/{pkg}/permissions | 5 | Permissions a build declares, with descriptions. Sensitive ones first. |
| GET /apps/{pkg}/manifest | 5 | Manifest settings and native libraries, plus the findings we flag from them. |
| GET /apps/{pkg}/raw | 10 | The raw scan record as stored, including the evidence digest, for running your own rules. |
| GET /apps/{pkg}/signing | 5 | Which key signed each release, and when it changed. |
| GET /apps/{pkg}/compare | 1 | Differences between two builds. |
| GET /lookup/hash/{hash} | 5 | Find the build that matches an MD5, SHA-1 or SHA-256. No package name needed. Free when nothing matches (found: false). |
| GET /lookup/certificate/{fp} | 5 | All packages we have that were signed by a given key. Free when we hold nothing signed by the key (total: 0). |
| GET /developers/{slug} | 1 | All apps from one publisher. |
| GET /developers/{slug}/certificates | 5 | Every signing key behind one publisher's apps, and whether each also signs anyone else's. Free when we hold no signing record for any of the publisher's apps (total: 0). |
| GET /charts | 1 | Hot, grossing, latest, new, editors' choice, and what's popular or freshly updated here. |
| GET /apps/{pkg}/similar | 1 | Apps related to one package. Free when there is nothing to list (an empty items). |
| GET /apps/{pkg}/play | 5 | Google Play's full store listing in any country and language: rating histogram, install estimate, in-app purchase prices, ads, release date. |
| GET /apps/{pkg}/reviews | 5 | One page of Google Play user reviews, with the developer's replies. Free when the page is empty (an empty items). |
| POST /apps/{pkg}/fetch | 10 | Ask us to fetch an app we don't have yet. Charged even when we already have builds (READY) or Google Play doesn't list the app; free only when a fetch for the app is already running (FETCHING). |
| GET /apps/{pkg}/fetch | 1 | Check on a fetch you started. Free when the fetch is still running (FETCHING). |
| POST /apps/{pkg}/variants | 10 | Ask for a build the default download doesn't include: every language, 32-bit ARM, universal, an older Android version or a specific device. Charged even when the variant is already built (READY); free only when a build of that variant is already running (FETCHING). |
| GET /apps/{pkg}/variants | 1 | Check on a variant build. Free when the build is still running (FETCHING). |
| POST /apps/{pkg}/download | 10 | Creates a signed download URL. This is the only call that gives you a file. |
Limitations#
Things to know before you build on the API.
- Install counts are buckets
- Google Play only shows ranges like
"10,000,000+", so that is what we return. There is no exact number behind it. - Metadata can lag behind Play
- We refresh listings about once a day, so a version can be up to a day behind Google Play. Less popular apps can take longer.
- No paid apps
- Google Play only delivers a paid app to the account that bought it, so we can't get paid apps we don't already have.
- Takedowns apply here too
- A removed app returns 451 in the API just like it does on the website. If the block is country-specific, it applies based on where your request comes from.
- No webhooks
- We don't push updates and there's no SDK. To find out when an app updates, poll the free availability check.