VirusTotal API v3 Integration
Comprehensive reference for integrating with VirusTotal's threat intelligence platform, covering file scanning, URL analysis, IoC enrichment, and malware research workflows
Install in one line
CLI$Β mfkvault install virustotal-api-v3-agent-skillRequires the MFKVault CLI. Prefer MCP?
Free to install β no account needed
Copy the command below and paste into your agent.
Instant access β’ No coding needed β’ No account needed
What you get in 5 minutes
- Full skill code ready to install
- Works with 7 AI agents
- Lifetime updates included
Description
--- name: virustotal-api description: > Comprehensive reference for the VirusTotal API v3, covering authentication, rate limits, endpoint usage, and the critical differences between Free (Public) and Premium (Enterprise) tiers. Use this skill whenever a user asks about VirusTotal, VT API, scanning files or URLs with VirusTotal, threat intelligence lookups, IoC enrichment, YARA hunting, Retrohunt, Livehunt, VT Intelligence search, VT Graph, VT Monitor, VT Feeds, private scanning, malware analysis via VirusTotal, or building integrations with the VirusTotal API. Also trigger when the user mentions "VT", "virustotal", hash lookups, file reputation checks, URL scanning services, sandbox detonation reports, or any workflow involving programmatic interaction with VirusTotal's threat intelligence platform β even if they don't say "API" explicitly. --- # VirusTotal API v3 β Agent Skill ## Quick Orientation VirusTotal (VT) is a threat intelligence platform that aggregates 70+ antivirus engines, 10+ dynamic analysis sandboxes, and numerous other security tools. Its REST API (v3) is the primary programmatic interface. The API is inspired by the JSON:API specification and returns JSON for all requests and responses, including errors. **Base URL:** `https://www.virustotal.com/api/v3` **Authentication:** Every request must include the header `x-apikey: <YOUR_API_KEY>`. Your key is found at https://www.virustotal.com/gui/my-apikey after signing into VirusTotal Community. Never pass the key as a query parameter β always use the header. ``` # Example: Get a file report by SHA-256 curl --request GET \ --url https://www.virustotal.com/api/v3/files/{sha256} \ --header 'x-apikey: YOUR_API_KEY' \ --header 'accept: application/json' ``` ```python # Python equivalent import requests url = "https://www.virustotal.com/api/v3/files/{sha256}" headers = {"accept": "application/json", "x-apikey": "YOUR_API_KEY"} response = requests.get(url, headers=headers) print(response.json()) ``` --- ## Free vs Enterprise β The Most Important Distinction Almost every decision about what you can build with the VT API depends on which tier you have. The two tiers are **Public API** (free) and **Premium API** (paid, also called "Private API" or "VT Enterprise"). Throughout this skill and the VT docs, a π icon marks enterprise-only endpoints or relationships. ### Public API (Free Tier) | Aspect | Detail | |----------------------|--------------------------------------------------------------| | **Cost** | Free β sign up at virustotal.com | | **Rate limit** | 4 requests per minute | | **Daily quota** | 500 requests per day | | **Rate limit scope** | Enforced per (IP address, API key) tuple | | **Commercial use** | Prohibited | | **File download** | Not available | | **Search** | Basic search only (exact hash, URL, domain, IP) | | **Hunting** | IoC Stream only (no Livehunt, no Retrohunt) | | **Feeds** | Not available | | **Private scanning** | Not available | | **Relationships** | Subset β many relationship types are π enterprise-only | | **File attributes** | Subset β fields like exiftool, malware_config are π | **Restrictions to emphasize:** - Cannot be used in commercial products or services. - Cannot be used in business workflows that do not contribute new files. - Registering multiple accounts to circumvent limits is prohibited. ### Premium API (Enterprise Tier) | Aspect | Detail | |----------------------|--------------------------------------------------------------| | **Cost** | Paid β contact VT sales for pricing based on usage | | **Rate limit** | Governed by your licensed service step (no fixed public cap) | | **Daily quota** | Governed by your license | | **Commercial use** | Allowed per agreement | | **File download** | Yes β download samples, PCAPs, memory dumps, EVTX | | **Search** | VT Intelligence advanced corpus search with full modifiers | | **Hunting** | Livehunt (real-time YARA) + Retrohunt (historical YARA) | | **Feeds** | Full intelligence feeds (file, URL, domain, IP, sandbox) | | **Private scanning** | Yes β scan files/URLs without contributing to public corpus | | **Relationships** | Full set including embedded_domains, itw_urls, similar_files | | **File attributes** | Full set including exiftool, malware_config, office_info | **Additional enterprise capabilities:** - First/last submission dates, submission countries, file prevalence metadata. - Sandbox behavior reports for Windows PE, DMG, Mach-O, APK. - Rich relationships: embedded domains/IPs/URLs, carbonblack parents/children, etc. - VT Graph API for link analysis. - VT Monitor for software publishers and AV partners. - User/group/quota management and audit logs. - Service account management. --- ## Response Format Successful requests return HTTP 200 with this structure: ```json { "data": <response_data> } ``` Where `<response_data>` is typically an object like: ```json { "type": "file", "id": "<sha256>", "links": { "self": "https://www.virustotal.com/api/v3/files/<sha256>" }, "attributes": { ... } } ``` For collections (lists), the response includes pagination: ```json { "data": [ ... ], "meta": { "cursor": "..." }, "links": { "self": "...", "next": "..." } } ``` ### Error Format Errors return the appropriate HTTP status code (4xx for client errors, 5xx for server errors): ```json { "error": { "code": "NotFoundError", "message": "Resource \"xyz\" not found" } } ``` Common error codes: - `AuthenticationRequiredError` β missing or invalid x-apikey header - `WrongCredentialsError` β API key is not valid - `ForbiddenError` β insufficient privileges (e.g., free key hitting enterprise endpoint) - `NotFoundError` β resource does not exist in VT dataset - `QuotaExceededError` β rate limit or daily quota exceeded - `TooManyRequestsError` β too many requests in a short period - `TransientError` β temporary server issue, retry with backoff --- ## Core Endpoint Categories For the full endpoint reference with request/response details, read: - `references/endpoints-free.md` β All endpoints available to free-tier users - `references/endpoints-enterprise.md` β Enterprise-only endpoints (π) - `references/objects-and-relationships.md` β API object schemas and relationship types ### Endpoints Available to Free Users These are the bread-and-butter endpoints most integrations use: **Files** - `POST /files` β Upload a file for scanning (max 32MB; use upload URL for larger) - `GET /files/upload_url` β Get a URL for uploading files >32MB (up to 650MB) - `GET /files/{id}` β Get a file report by hash (MD5, SHA-1, or SHA-256) - `POST /files/{id}/analyse` β Request a rescan of a known file - `GET /files/{id}/comments` β Get comments on a file - `POST /files/{id}/comments` β Add a comment to a file - `GET /files/{id}/votes` β Get votes on a file - `POST /files/{id}/votes` β Cast a vote on a file - `GET /files/{id}/relationships/{relationship}` β Get related objects **URLs** - `POST /urls` β Submit a URL for scanning - `GET /urls/{id}` β Get a URL report (id = base64url of the URL without padding) - `POST /urls/{id}/analyse` β Request a rescan - Comments, votes, and relationships follow the same pattern as files **Domains** - `GET /domains/{domain}` β Get a domain report - `POST /domains/{domain}/rescan` β Request a rescan - Comments, votes, relationships **IP Addresses** - `GET /ip_addresses/{ip}` β Get an IP address report - `POST /ip_addresses/{ip}/rescan` β Request a rescan - Comments, votes, relationships **Comments** (global) - `GET /comments` β Get latest comments across VT - `GET /comments/{id}` β Get a specific comment - `DELETE /comments/{id}` β Delete your own comment **Analyses & Submissions** - `GET /analyses/{id}` β Get status/results of a scan analysis - `GET /submissions/{id}` β Get a submission object **Search (basic)** - `GET /search?query={query}` β Basic search for files, URLs, domains, IPs, comments ### Enterprise-Only Endpoints (π) These require a premium API key. Attempting them with a free key returns `ForbiddenError`. **VT Intelligence (Advanced Search)** - `GET /intelligence/search?query={query}` β Full corpus search with modifiers - `GET /intelligence/search/snippets/{id}` β Content search snippets **File Downloads** - `GET /files/{id}/download_url` β Get a time-limited download URL - `GET /files/{id}/download` β Download the actual file bytes **VT Hunting** - Livehunt: CRUD for YARA rulesets, notification retrieval, file downloads - Retrohunt: Create/manage retrohunt jobs, retrieve matches **VT Feeds** - File, URL, domain, IP, and sandbox analysis feeds (per-minute and hourly batches) **Private Scanning** - Upload and scan files/URLs privately (results not shared with VT community) **Collections (advanced)** - List all collections, export IOCs, export aggregations, search within collections **Zipping Files** - Create password-protected ZIPs of VT files for bulk download **Administration** - User/group/quota management, service accounts, audit logs **VT Monitor** - Software publisher and AV partner endpoints **VT Graph** - Create, search, update, delete graphs; manage viewer/editor permissions --- ## Practical Examples ### Example 1: Check if a file hash is malicious (Free) ```python import requests API_KEY = "your_api_key_here" FILE_HASH = "44d88612fea8a8f36de82e1278abb02f" # EICAR test file MD5 url = f"https://www.virustotal.com/api/v3/files/{FILE_HASH}" headers = {"x-apikey": API_KEY} response = requests.get(url, headers=headers) if response.status_code == 200: data = response.json() stats = data["data"]["attributes"]["last_analysis_stats"] print(f"Malicious: {stats['malicious']}, Undetected: {stats['undetected']}") elif response.status_code == 404: print("File not found in VT database") else: print(f"Error: {response.status_code} - {response.json()}") ``` ### Example 2: Submit a URL for scanning (Free) ```python import requests, base64 API_KEY = "your_api_key_here" TARGET_URL = "https://example.com" # Step 1: Submit the URL headers = {"x-apikey": API_KEY, "content-type": "application/x-www-form-urlencoded"} response = requests.post( "https://www.virustotal.com/api/v3/urls", headers=headers, data=f"url={TARGET_URL}" ) analysis_id = response.json()["data"]["id"] # Step 2: Poll for results import time time.sleep(30) # Wait for analysis to complete headers = {"x-apikey": API_KEY} result = requests.get( f"https://www.virustotal.com/api/v3/analyses/{analysis_id}", headers=headers ) print(result.json()["data"]["attributes"]["stats"]) # Alternative: look up the URL directly url_id = base64.urlsafe_b64encode(TARGET_URL.encode()).decode().rstrip("=") report = requests.get( f"https://www.virustotal.com/api/v3/urls/{url_id}", headers=headers ) ``` ### Example 3: Upload a file for scanning (Free) ```python import requests API_KEY = "your_api_key_here" FILE_PATH = "/path/to/suspicious_file.exe" # For files <= 32MB, use the direct upload endpoint with open(FILE_PATH, "rb") as f: response = requests.post( "https://www.virustotal.com/api/v3/files", headers={"x-apikey": API_KEY}, files={"file": (FILE_PATH, f)} ) print(response.json()["data"]["id"]) # Analysis ID to poll later # For files > 32MB, first get an upload URL upload_url_resp = requests.get( "https://www.virustotal.com/api/v3/files/upload_url", headers={"x-apikey": API_KEY} ) upload_url = upload_url_resp.json()["data"] # Then POST the file to that URL instead ``` ### Example 4: VT Intelligence search (π Enterprise) ```python import requests API_KEY = "your_premium_api_key" # Search for recently submitted PE files detected by 10+ engines query = "type:peexe positives:10+ fs:2025-05-01+" response = requests.get( "https://www.virustotal.com/api/v3/intelligence/search", headers={"x-apikey": API_KEY}, params={"query": query, "limit": 20} ) for item in response.json()["data"]: sha256 = item["id"] detections = item["attributes"]["last_analysis_stats"]["malicious"] print(f"{sha256}: {detections} detections") # Paginate with cursor next_link = response.json().get("links", {}).get("next") if next_link: next_page = requests.get(next_link, headers={"x-apikey": API_KEY}) ``` ### Example 5: Download a malware sample (π Enterprise) ```python import requests API_KEY = "your_premium_api_key" SHA256 = "abc123..." # Option A: Get download URL (time-limited) resp = requests.get( f"https://www.virustotal.com/api/v3/files/{SHA256}/download_url", headers={"x-apikey": API_KEY} ) download_url = resp.json()["data"] # Option B: Direct download resp = requests.get( f"https://www.virustotal.com/api/v3/files/{SHA256}/download", headers={"x-apikey": API_KEY} ) with open(f"{SHA256}.bin", "wb") as f: f.write(resp.content) ``` ### Example 6: Retrieve sandbox behavior for a file (Free, but richer with Enterprise) ```python import requests API_KEY = "your_api_key" SHA256 = "abc123..." # Get summary of all behavior reports resp = requests.get( f"https://www.virustotal.com/api/v3/files/{SHA256}/behaviour_summary", headers={"x-apikey": API_KEY} ) summary = resp.json()["data"] # Get individual sandbox reports resp = requests.get( f"https://www.virustotal.com/api/v3/files/{SHA256}/behaviours", headers={"x-apikey": API_KEY} ) for report in resp.json()["data"]: sandbox = report["attributes"].get("sandbox_name", "unknown") print(f"Sandbox: {sandbox}") ``` --- ## Rate Limiting Best Practices For free-tier users (4 req/min, 500 req/day): 1. **Cache aggressively** β VT reports don't change every second. Cache results for at least 15-60 minutes depending on your use case. 2. **Batch with sleep** β When processing multiple hashes, add a `time.sleep(15)` between requests to stay safely under 4/min. 3. **Check before scanning** β Always GET a report first before POSTing a new scan. The file or URL may already be in the database. 4. **Use the analysis endpoint wisely** β After submitting a scan, poll `/analyses/{id}` rather than repeatedly hitting the file/URL endpoint. For enterprise users: - Your limits are defined by your license. Check `GET /users/{id}/api_usage` for current consumption. - Use concurrent requests and the feeds endpoints for large-scale processing. - Use `descriptors_only=true` on search endpoints when you only need hashes. --- ## Key Concepts **Objects** β Everything in VT is an object with a `type`, `id`, `attributes`, and `links`. Object types include: file, url, domain, ip_address, comment, analysis, etc. **Relationships** β Objects link to each other through relationships. For example, a file has relationships like `contacted_domains`, `dropped_files`, `behaviours`. Many relationship types are enterprise-only (π). **Collections** β Ordered lists of objects returned by endpoints that produce multiple results. Collections support cursor-based pagination via the `cursor` parameter. **Descriptors** β Lightweight references to objects (just type + id) used for efficient listing without fetching full attributes. --- ## When to Read the Reference Files Read `references/endpoints-free.md` when you need: - Exact endpoint paths, HTTP methods, and parameters for free-tier endpoints - Request/response examples for specific operations - Relationship types available on each object for free users Read `references/endpoints-enterprise.md` when you need: - Enterprise-only endpoint details (Intelligence search, Hunting, Feeds, Private Scanning) - Administration endpoints (user/group/quota management) - VT Monitor and VT Graph specifics Read `references/objects-and-relationships.md` when you need: - Full attribute schemas for each object type - Complete relationship map showing which relationships are free vs enterprise - File object attribute details (PE info, sandbox verdicts, YARA results, etc.)
Security Status
Unvetted
Not yet security scanned
Related AI Tools
More Grow Business tools you might like
Linear
FreeManaging Linear issues, projects, and teams. Use when working with Linear tasks, creating issues, updating status, querying projects, or managing team workflows.
codex-collab
FreeUse when the user asks to invoke, delegate to, or collaborate with Codex on any task. Also use PROACTIVELY when an independent, non-Claude perspective from Codex would add value β second opinions on code, plans, architecture, or design decisions.
Rails Upgrade Analyzer
FreeAnalyze Rails application upgrade path. Checks current version, finds latest release, fetches upgrade notes and diffs, then performs selective upgrade preserving local customizations.
Asta MCP β Academic Paper Search
FreeDomain expertise for Ai2 Asta MCP tools (Semantic Scholar corpus). Intent-to-tool routing, safe defaults, workflow patterns, and pitfall warnings for academic paper search, citation traversal, and author discovery.
Hand Drawn Diagrams
FreeCreate hand-drawn Excalidraw diagrams, flows, explainers, wireframes, and page mockups. Default to monochrome sketch output; allow restrained color only for page mockups when the user explicitly wants webpage-like fidelity.
Move Code Quality Checker
FreeAnalyzes Move language packages against the official Move Book Code Quality Checklist. Use this skill when reviewing Move code, checking Move 2024 Edition compliance, or analyzing Move packages for best practices. Activates automatically when working