API
A v1 REST API for protecting APK/AAB files with an API key — no browser session required. You can integrate it into your CI and automation pipelines.
- Base URL —
https://appsolid.net - Authentication — an API-key header on every request (
Authorization: BearerorX-API-Key) - Content type — request/response bodies are
application/json(except the upload PUT)
Authentication#
Issue a key under Settings → API Keys (it is shown only once at creation, so store it somewhere safe). A key can access only its owner's jobs (ownership scoping), and revocation is done from Settings.
# Include one of these headers on every request.
curl -H "Authorization: Bearer ak_live_3f9a8c2e7b1d4056" ...
curl -H "X-API-Key: ak_live_3f9a8c2e7b1d4056" ...
Processing flow#
Four steps: upload → protect → download. Files are uploaded directly to storage (never through our server), so there is no size limit.
POST /api/v1/jobs create a job, get a presigned upload URL
PUT {uploadUrl} upload the APK/AAB bytes directly to storage
POST /api/v1/jobs/{jobId}/obfuscate run protection (synchronous)
GET /api/v1/jobs/{jobId} poll status, get the download URL
Endpoints#
Create job · POST /api/v1/jobs#
Creates an upload job and returns a presigned PUT URL.
curl -sS -X POST https://appsolid.net/api/v1/jobs \
-H "Authorization: Bearer $APPSOLID_KEY" \
-H "Content-Type: application/json" \
-d '{ "fileName": "app.apk" }'
{
"jobId": "job_3f9a8c2e",
"uploadUrl": "https://storage.appsolid.net/in/job_3f9a8c2e/app.apk?X-Amz-Signature=..."
}
Upload file · PUT {uploadUrl}#
Send the raw file bytes to the uploadUrl returned above. No headers beyond the body are required.
curl -sS -X PUT "$UPLOAD_URL" \
-H "Content-Type: application/octet-stream" \
--data-binary @app.apk
A successful upload returns an empty 200 OK.
Run protection · POST /api/v1/jobs/{jobId}/obfuscate#
Runs synchronously and usually completes within a few seconds. options are opt-in protection flags; when omitted, only core protection is applied.
curl -sS -X POST https://appsolid.net/api/v1/jobs/$JOB_ID/obfuscate \
-H "Authorization: Bearer $APPSOLID_KEY" \
-H "Content-Type: application/json" \
-d '{
"options": ["root", "emulator", "hookFw", "stringEnc", "monitoring"]
}'
{
"jobId": "job_3f9a8c2e",
"status": "COMPLETED",
"appId": "a1b2c3d4e5f6"
}
Option flags — root, adb, emulator, hookFw, inlineHook, antiInstrument, timingDebug, stringEnc, selfChecksum, monitoring, and so on. Unknown values return 400. For the meaning of each option, see Protection Options.
⚠️ AAB input constraint —
selfChecksumis APK-only; if you specify it for an AAB input, the engine rejects it fail-fast. The other options (detection, string encryption, monitoring) work on AAB as well. For background, see Performance · Compatibility.
Check status · GET /api/v1/jobs/{jobId}#
Returns a presigned download URL once complete.
curl -sS https://appsolid.net/api/v1/jobs/$JOB_ID \
-H "Authorization: Bearer $APPSOLID_KEY"
{
"status": "COMPLETED",
"appId": "a1b2c3d4e5f6",
"downloadUrl": "https://storage.appsolid.net/out/job_3f9a8c2e/app-protected.apk?X-Amz-Signature=..."
}
Full example#
A minimal shell script covering upload through protect, download, and re-signing.
#!/usr/bin/env bash
set -euo pipefail
KEY="ak_live_3f9a8c2e7b1d4056"
BASE="https://appsolid.net"
AUTH=(-H "Authorization: Bearer $KEY")
# 1. create a job
job=$(curl -sS -X POST "$BASE/api/v1/jobs" "${AUTH[@]}" \
-H "Content-Type: application/json" \
-d '{ "fileName": "app.apk" }')
jobId=$(echo "$job" | jq -r .jobId)
uploadUrl=$(echo "$job" | jq -r .uploadUrl)
# 2. upload the APK bytes straight to storage
curl -sS -X PUT "$uploadUrl" \
-H "Content-Type: application/octet-stream" \
--data-binary @app.apk
# 3. run protection (synchronous)
curl -sS -X POST "$BASE/api/v1/jobs/$jobId/obfuscate" "${AUTH[@]}" \
-H "Content-Type: application/json" \
-d '{ "options": ["root", "monitoring"] }'
# 4. fetch the protected (unsigned) output
downloadUrl=$(curl -sS "$BASE/api/v1/jobs/$jobId" "${AUTH[@]}" | jq -r .downloadUrl)
curl -sS "$downloadUrl" -o app-protected.apk
# 5. re-sign with your own keystore before distributing
apksigner sign --ks release.keystore app-protected.apk
Node.js#
The same flow using only the built-in fetch, with no dependencies (Node.js 18+).
import { readFile, writeFile } from "node:fs/promises";
const KEY = "ak_live_3f9a8c2e7b1d4056";
const BASE = "https://appsolid.net";
const auth = { Authorization: `Bearer ${KEY}` };
// 1. create a job
const create = await fetch(`${BASE}/api/v1/jobs`, {
method: "POST",
headers: { ...auth, "Content-Type": "application/json" },
body: JSON.stringify({ fileName: "app.apk" }),
});
const { jobId, uploadUrl } = await create.json();
// 2. upload the APK bytes straight to storage
const bytes = await readFile("app.apk");
await fetch(uploadUrl, {
method: "PUT",
headers: { "Content-Type": "application/octet-stream" },
body: new Blob([bytes]),
});
// 3. run protection (synchronous)
await fetch(`${BASE}/api/v1/jobs/${jobId}/obfuscate`, {
method: "POST",
headers: { ...auth, "Content-Type": "application/json" },
body: JSON.stringify({ options: ["root", "monitoring"] }),
});
// 4. fetch the protected (unsigned) output
const status = await fetch(`${BASE}/api/v1/jobs/${jobId}`, { headers: auth });
const { downloadUrl } = await status.json();
const out = await fetch(downloadUrl);
await writeFile("app-protected.apk", Buffer.from(await out.arrayBuffer()));
// 5. re-sign with your own keystore before distributing (apksigner)
Error responses#
On error the API returns a JSON body of the form { "error": "..." } with the appropriate HTTP status.
| Status | Meaning |
|---|---|
400 | Invalid request — unknown option flag or missing fileName |
401 | Missing or invalid API key |
403 | Accessing a job you don't own |
404 | Job not found |
429 | Rate limited |
5xx | Transient server error |
{ "error": "unknown option flag: foo" }
Requests are rate-limited per API key. On a
429, back off and retry.
Notes#
- The output is zipaligned and unsigned. You must re-sign it with
apksignerbefore distribution (why). - The output has a per-job
appIdbaked in, so if you have enabled monitoring, RASP telemetry is linked to the corresponding app in the dashboard. - When a threat occurs, you can separately receive a webhook notification that includes an HMAC signature.
Next#
- Protection Options —
optionsflag details - Monitoring — telemetry and dashboard