概要
URL スキャンはリクエスト内で完了し、APK スキャンは非同期です。すべての検査エンドポイントはアカウント単位のレート枠を共有します。
検査リクエストまたは APK を送信
検証、重複排除、スキャンを実行
署名付き Webhook で結果を配信
受理応答に job_id が含まれます。GET /api/v1/jobs/{job_id} で約 24 時間ポーリングできます。callback_url は任意で、指定時は署名付き Webhook も配信します。
{
"client_reference": "order-20260711-001",
"callback_url": "https://example.com/webhooks/fvl",
"use_cache": false
}認証
各リクエストでいずれかのヘッダーを使用します。キーは作成時に一度だけ完全表示され、サーバー側で保管する必要があります。
Authorization: Bearer fvl_xxxX-API-Key: fvl_xxxAPI キーをブラウザー、モバイルアプリ、公開リポジトリ、ログに埋め込まないでください。
クォータとレート制限
API は VIP+、SVIP、SVIP+、管理者向けです。同一アカウントの全 API キーがレート枠を共有します。
| プラン | 最短間隔 | R2 日次アップロード |
|---|---|---|
| VIP+ | 10 分 | 2 GiB |
| Pro | 3 分 | 5 GiB |
| SVIP | 5 分 | 10 GiB |
| SVIP+ | 1 分 | 30 GiB |
| 管理者 | 無制限 | 無制限 |
エンドポイント
署名済み R2 PUT を除き、リクエストとレスポンスは JSON です。
/api/v1/url-scanURL を同期スキャンurl を送り、リスク結果と課金後の quota を同じ応答で受け取ります。Webhook は使用しません。
curl -X POST https://www.fuckviruslabel.com/api/v1/url-scan \
-H "Authorization: Bearer fvl_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/path"}'{
"code": 0,
"message": "success",
"data": {
"result": {
"status": "completed",
"url": "https://example.com/path",
"domain": "example.com",
"flagged": false,
"mainType": 0,
"mainTypeName": "安全",
"provider": "OPPO",
"websiteType": 0,
"matchUrl": "",
"riskDetail": "",
"cacheStatus": "live",
"checkedAt": 1783765471000,
"createdAt": 1783765471000
},
"quota": {
"identity_label": "VIP+",
"daily_limit": 20,
"daily_used": 1,
"daily_remaining": 19,
"scan_credits": 0,
"total_remaining": 19,
"usage_date": "2026-07-11"
}
}
}/api/v1/apk/uploadsAPK アップロードセッションを作成Idempotency-Key、.apk 名、size、file_md5、expected_sha256、共通コールバック項目が必要です。URL は 30 分有効です。
curl -X POST https://www.fuckviruslabel.com/api/v1/apk/uploads \
-H "Authorization: Bearer fvl_xxxxxxxxxxxxxxxx" \
-H "Idempotency-Key: upload-20260711-001" \
-H "Content-Type: application/json" \
-d '{
"client_reference": "order-20260711-001",
"callback_url": "https://api.example.com/webhooks/fvl",
"use_cache": false,
"filename": "release.apk",
"size": 24117384,
"file_md5": "0123456789abcdef0123456789abcdef",
"expected_sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
}'curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: application/vnd.android.package-archive" \
-H "Content-Length: 24117384" \
-H "Content-MD5: ASNFZ4mrze8BI0VniavN7w==" \
-H "If-None-Match: *" \
--upload-file ./release.apk/api/v1/apk/uploads/completeアップロードを完了して審査へ送信upload_token と Idempotency-Key を送信します。オブジェクトを検証し、再課金せず前払い済み審査を送信します。
curl -X POST https://www.fuckviruslabel.com/api/v1/apk/uploads/complete \
-H "Authorization: Bearer fvl_xxxxxxxxxxxxxxxx" \
-H "Idempotency-Key: order-20260711-001" \
-H "Content-Type: application/json" \
-d '{"upload_token":"upl_xxxxxxxxxxxxxxxx"}'/api/v1/apk/fingerprintsAPK フィンガープリントを送信package_name、sha256、file_md5、cert_md5 と共通コールバック項目を送り、APK の再アップロードを省けます。
curl -X POST https://www.fuckviruslabel.com/api/v1/apk/fingerprints \
-H "Authorization: Bearer fvl_xxxxxxxxxxxxxxxx" \
-H "Idempotency-Key: fingerprint-20260711-001" \
-H "Content-Type: application/json" \
-d '{
"client_reference": "fingerprint-20260711-001",
"callback_url": "https://api.example.com/webhooks/fvl",
"use_cache": true,
"package_name": "com.example.app",
"sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
"file_md5": "0123456789abcdef0123456789abcdef",
"cert_md5": "abcdef0123456789abcdef0123456789",
"version_code": 108,
"version_name": "1.0.8",
"size": 24117384,
"filename": "release.apk"
}'/api/v1/packages/checkパッケージ名を検査端末側のパッケージリスクを簡易確認します。ハッシュと証明書を含む完全 APK スキャンではありません。
curl -X POST https://www.fuckviruslabel.com/api/v1/packages/check \
-H "X-API-Key: fvl_xxxxxxxxxxxxxxxx" \
-H "Idempotency-Key: package-20260711-001" \
-H "Content-Type: application/json" \
-d '{
"client_reference": "package-20260711-001",
"callback_url": "https://api.example.com/webhooks/fvl",
"use_cache": false,
"package_name": "com.example.app"
}'{
"code": 0,
"message": "accepted",
"data": {
"client_reference": "order-20260711-001",
"job_id": "acd_xxxxxxxxxxxxxxxx",
"delivery": "webhook_and_poll",
"poll_path": "/api/v1/jobs/acd_xxxxxxxxxxxxxxxx"
}
}/api/v1/jobs/{job_id}非同期ジョブをポーリング受理応答の job_id で pending / processing / completed / failed を確認します。結果は約 24 時間保持されます。
curl -X POST https://www.fuckviruslabel.com/api/v1/packages/check \
-H "X-API-Key: fvl_xxxxxxxxxxxxxxxx" \
-H "Idempotency-Key: package-20260711-001" \
-H "Content-Type: application/json" \
-d '{
"client_reference": "package-20260711-001",
"callback_url": "https://api.example.com/webhooks/fvl",
"use_cache": false,
"package_name": "com.example.app"
}'{
"code": 0,
"message": "accepted",
"data": {
"client_reference": "order-20260711-001",
"job_id": "acd_xxxxxxxxxxxxxxxx",
"delivery": "webhook_and_poll",
"poll_path": "/api/v1/jobs/acd_xxxxxxxxxxxxxxxx"
}
}発行前に前払い、発行後は返金なし
会員資格、レート、再検査枠、日次バイト上限、未完了セッション数を確認後、再検査 1 回を引いて URL を発行します。未完了、期限切れ、ハッシュ不一致、不正 APK、キュー失敗でも返却されません。一時的な投入失敗はサンプルを保持し、自動再試行します。
有効 APK は SHA-256 で重複排除して保存し、不正または不一致のサンプルは quarantine に移します。どちらも 90 日保持し、未完了アップロードは 1 日後に削除します。
use_cache の意味
use_cache は JSON ルートに置き、既定値は false です。R2 は値にかかわらず URL 発行前に前払いし、完了後の結果再利用だけを制御します。
false強制再検査false は既存結果を迂回し、実際にスキャンを開始した時に 1 回消費します。
cache_status = bypasstrueキャッシュを許可true は有効なキャッシュを無課金で返し、ミスまたは期限切れ時に再検査します。
cache_status = hit | miss署名付き Webhook
Webhook は非同期 APK 検査の唯一の結果経路です。生の JSON、タイムスタンプ、HMAC-SHA256 署名を送信します。
X-FVL-Timestamp: 1720000000X-FVL-Signature: sha256=<hex>- webhook_secret = lowercase_hex(SHA-256(raw_api_key)) を計算します。
- X-FVL-Timestamp + "." + raw_body を署名します。
- webhook_secret の UTF-8 バイトを HMAC-SHA256 キーに使い、定数時間で比較します。
- タイムスタンプを確認して任意の 2xx を返します。非 2xx は再試行されます。
{
"event": "apk.scan.completed",
"client_reference": "order-20260711-001",
"operation": "apk_upload",
"status": "completed",
"cache_status": "bypass",
"result": { "flagged": false, "result_type_name": "安全" },
"quota": { "refresh_daily_remaining": 29, "total_remaining": 29 },
"checked_at": "2026-07-11T10:24:31.000Z"
}import crypto from "node:crypto";
export function verifyFvlWebhook(rawBody, timestamp, signature, apiKey) {
const webhookSecret = crypto
.createHash("sha256")
.update(apiKey, "utf8")
.digest("hex");
const expected = "sha256=" + crypto
.createHmac("sha256", webhookSecret)
.update(timestamp + "." + rawBody)
.digest("hex");
const expectedBytes = Buffer.from(expected, "utf8");
const signatureBytes = Buffer.from(signature, "utf8");
return expectedBytes.length === signatureBytes.length &&
crypto.timingSafeEqual(expectedBytes, signatureBytes);
}JSON 解析前に raw body を読み取ってください。再シリアライズすると署名検証に失敗します。
冪等性と重複排除
アップロード作成・完了、特徴検査、パッケージ検査には Idempotency-Key が必要です。
エラー
同期エラーは HTTP と統一 JSON を使います。非同期 APK 審査エラーは scan.failed Webhook で通知します。
| HTTP | 意味 | 対応 |
|---|---|---|
400 | リクエストまたは項目が不正 | JSON、ハッシュ、パッケージ名、コールバック URL を修正します。 |
401 | 認証失敗 | API キーを確認します。 |
403 | アクセス拒否 | プランと有効期限を確認します。 |
409 | 状態競合 | 冪等キーまたはアップロード状態を確認します。 |
429 | クォータまたはレート超過 | Retry-After に従って再試行します。 |
503 | サービス利用不可 | 同じ冪等キーで端点規則に従い再試行します。 |
const body = {
client_reference: "package-20260711-001",
callback_url: "https://api.example.com/webhooks/fvl",
use_cache: true,
package_name: "com.example.app"
};
const response = await fetch(
"https://www.fuckviruslabel.com/api/v1/packages/check",
{
method: "POST",
headers: {
Authorization: "Bearer " + process.env.FVL_API_KEY,
"Content-Type": "application/json",
"Idempotency-Key": body.client_reference
},
body: JSON.stringify(body)
}
);
if (!response.ok) throw new Error(await response.text());
console.log(await response.json());import os
import requests
payload = {
"client_reference": "package-20260711-001",
"callback_url": "https://api.example.com/webhooks/fvl",
"use_cache": True,
"package_name": "com.example.app",
}
response = requests.post(
"https://www.fuckviruslabel.com/api/v1/packages/check",
headers={
"Authorization": f"Bearer {os.environ['FVL_API_KEY']}",
"Idempotency-Key": payload["client_reference"],
},
json=payload,
timeout=20,
)
response.raise_for_status()
print(response.json())変更履歴
初回リリース:URL、R2 アップロード、APK 特徴、パッケージ、キャッシュ、冪等性、署名付き Webhook。