API d’analyse APK et URL

Les URL renvoient du JSON de façon synchrone. Les APK sont soumis par fichier, empreintes complètes ou paquet, puis livrés à un webhook signé.

Bien démarrer

Vue d’ensemble

Les analyses d’URL terminent dans la requête ; celles d’APK sont asynchrones. Tous les endpoints partagent la fenêtre de fréquence du compte.

01Soumettre

Envoyer la demande ou téléverser l’APK

02Examiner

Valider, dédupliquer et analyser

03Notifier

Livrer le résultat par webhook signé

L’API APK prend en charge le polling

La réponse d’acceptation inclut job_id. Interrogez GET /api/v1/jobs/{job_id} pendant environ 24 h. callback_url est facultatif ; s’il est fourni, un webhook signé est aussi livré.

JSON · common APK fields
{
  "client_reference": "order-20260711-001",
  "callback_url": "https://example.com/webhooks/fvl",
  "use_cache": false
}
Contrôle d’accès

Authentification

Utilisez l’un des en-têtes à chaque requête. La clé complète n’apparaît qu’à sa création et doit rester côté serveur.

RecommandéAuthorization: Bearer fvl_xxx
CompatibleX-API-Key: fvl_xxx

N’intégrez jamais une clé API dans un navigateur, une application mobile, un dépôt public ou des journaux.

Contrôle d’accès

Quotas et fréquence

L’API est disponible pour VIP+, SVIP, SVIP+ et les administrateurs. Toutes les clés d’un compte partagent la fréquence.

OffreIntervalle minimalTéléversement R2 quotidien
VIP+10 minutes2 GiB
Pro3 minutes5 GiB
SVIP5 minutes10 GiB
SVIP+1 minute30 GiB
AdministrateurIllimitéIllimité
URL, création de sessions, empreintes APK et paquets partagent la limite du compte. Les succès du cache, répétitions idempotentes et tâches fusionnées n’ouvrent pas une nouvelle fenêtre.
Chaque utilisateur peut avoir une session inachevée active. La création R2 précompte une nouvelle analyse, non remboursée après émission.
API

Endpoints

Requêtes et réponses utilisent JSON, sauf le PUT R2 présigné.

POST/api/v1/url-scanAnalyser une URL en synchrone

Envoyez url et recevez le risque et le quota après débit dans la même réponse, sans webhook.

cURL
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"}'
HTTP 200
{
  "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"
    }
  }
}
POST/api/v1/apk/uploadsCréer une session de téléversement APK

Nécessite Idempotency-Key, un nom .apk, size, file_md5, expected_sha256 et les champs de rappel. L’URL dure 30 minutes.

cURL
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"
  }'
PUT · R2 required_headers
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
POST/api/v1/apk/uploads/completeTerminer et soumettre à l’examen

Envoyez upload_token et Idempotency-Key. L’objet est validé puis l’examen prépayé est soumis sans nouveau débit.

cURL
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"}'
POST/api/v1/apk/fingerprintsSoumettre des empreintes APK

Envoyez package_name, sha256, file_md5, cert_md5 et les champs de rappel sans retéléverser l’APK.

cURL
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"
  }'
POST/api/v1/packages/checkVérifier un nom de paquet

Vérifie rapidement le risque du paquet. Ce n’est pas une analyse APK complète avec hachages et certificat.

cURL
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"
  }'
HTTP 202
{
  "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"
  }
}
GET/api/v1/jobs/{job_id}Interroger une tâche asynchrone

Utilisez le job_id de l’acceptation pour lire pending / processing / completed / failed. Les résultats sont conservés environ 24 h.

cURL
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"
  }'
HTTP 202
{
  "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

Précompte avant émission, aucun remboursement après

Précompte avant émission, aucun remboursement après

L’abonnement, la fréquence, le quota, les octets quotidiens et les sessions sont vérifiés avant de débiter une analyse et d’émettre l’URL. Aucun remboursement pour téléversement inachevé ou expiré, hachage incorrect, APK invalide ou échec de file. Les échecs transitoires conservent l’échantillon pour une nouvelle tentative automatique.

Conservation des échantillons

Les APK valides sont dédupliqués par SHA-256 et archivés ; les échantillons invalides ou incohérents vont en quarantine. Conservation 90 jours ; les téléversements inachevés sont supprimés après un jour.

Contrôle de requête

Sémantique de use_cache

use_cache est un champ racine, false par défaut. R2 est prépayé avant l’URL quelle que soit sa valeur ; il ne contrôle que la réutilisation du résultat.

falseForcer une nouvelle analyse

false ignore un résultat existant et consomme une analyse quand elle démarre réellement.

cache_status = bypass
trueAutoriser le cache

true renvoie un cache valide sans débit ; une absence ou expiration relance l’analyse.

cache_status = hit | miss
Livraison des résultats

Webhook signé

Le webhook est l’unique canal des APK asynchrones. Le serveur envoie le JSON brut, un horodatage et une signature HMAC-SHA256.

X-FVL-TimestampX-FVL-Timestamp: 1720000000
X-FVL-SignatureX-FVL-Signature: sha256=<hex>
  1. Calculez webhook_secret = lowercase_hex(SHA-256(raw_api_key)).
  2. Signez X-FVL-Timestamp + "." + raw_body.
  3. Utilisez les octets UTF-8 de webhook_secret pour HMAC-SHA256 et comparez en temps constant.
  4. Validez l’heure et renvoyez un 2xx ; les autres statuts sont retentés.
Webhook JSON
{
  "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"
}
Node.js · HMAC-SHA256
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);
}

Lisez raw body avant JSON. La resérialisation modifie les octets et invalide la signature.

Contrôle de requête

Idempotence et déduplication

La création et la fin d’un téléversement, les empreintes et les paquets exigent Idempotency-Key.

La même clé et requête renvoient le même résultat pendant 24 heures sans nouveau débit.
La même clé avec une autre requête renvoie HTTP 409.
Les analyses simultanées du même actif sont fusionnées, mais chaque appel reçoit son webhook.
Référence

Erreurs

Les erreurs synchrones utilisent le statut HTTP et un JSON uniforme. Les échecs APK asynchrones arrivent via scan.failed.

HTTPSignificationAction
400Requête ou champ invalideCorrigez JSON, hachages, paquet ou rappel.
401Échec d’authentificationVérifiez la clé API.
403Accès refuséVérifiez l’offre et l’expiration.
409Conflit d’étatVérifiez l’idempotence ou l’état du téléversement.
429Quota ou fréquence dépasséRespectez Retry-After.
503Service indisponibleRetentez selon l’endpoint avec la même clé.
Node.js
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());
Python
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())
OpenAPI 3.1 lisible par machineGénérez des clients, validez les requêtes ou importez l’API dans vos outils.
Référence

Journal des modifications

v1.0.0

Version initiale : URL, R2, empreintes APK, paquets, cache, idempotence et webhooks signés.