VirusTotal Developer Hub

Welcome to the VirusTotal developer hub. Here you'll find comprehensive guides and documentation to help you start working with VirusTotal's API as quickly as possible. Let's jump right in!

Overview

 

The VirusTotal API version 3 is now in beta. It will be officially released in 2019H1 in order to replace the API version 2, which will be deprecated. This new API was designed with ease of use and uniformity in mind and it's inspired in the http://jsonapi.org/ specification.

This API follows the REST principles and has predictable, resource-oriented URLs. It uses JSON for requests and responses, including errors.

Important notice

This API is already mature and stable, but some backward incompatible changes are still possible. We encourage you to start using it for experimentation and non-mission-critical projects, but keep in mind that you are in the bleeding-edge.

Authentication

 

For authenticating with the API you must include the x-apikey header with your personal API key in all your requests. Your API key can be found in your VirusTotal account's settings.

Your API key carries all your privileges, so keep it secure and don't share it with anyone. Always use HTTPS instead of HTTP for making your requests.

API responses

 

Most endpoints in the VirusTotal API return a response in JSON format. Unless specified otherwise a successful request's response will have the following format:

{
  'data': <response data>
}

<response data> is usually an object or a list of objects, but that's not always the case. An example of this is the /files/upload_url endpoint, which returns a URL.

Errors

 

The VirusTotal API follows the conventional HTTP response codes for indicating success or failure. Codes in the 2xx range indicate success. Codes in the 4xx range indicate an error in the request (e.g. a missing parameter, a resource was not found). Codes in the 5xx range indicate an error in VirusTotal's servers and should be rare.

Unsuccessful requests return additional information about the error in JSON format.

{
  "error": {
    "code": "<error code>",
    "message": "<a message describing the error>"
  }
}

The error code is a string with one of the values provided in the table below. The message usually provides a little more information about the error.

Error code
HTTP code
Description

AlreadyExistsError

409

The resource already exists.

AuthenticationRequiredError

401

The operation requires an authenticated user. Verify that you have provided your API key.

BadRequestError

400

The API request is invalid or malformed. The message usually provides details about why the request is not valid.

ForbiddenError

403

You are not allowed to perform the requested operation.

InvalidArgumentError

400

Some of the provided arguments is incorrect.

NotFoundError

404

The requested resource was not found.

QuotaExceededError

429

You have exceeded one of your quotas (minute, daily or monthly). Daily quotas are reset every day at 00:00 UTC.

TooManyRequestsError

429

Too many requests.

UserNotActiveError

401

The user account is not active. Make sure you properly activated your account by following the link sent to your email.

WrongCredentialsError

401

The provided API key is incorrect.

TransientError

503

Transient server error. Retry might work.

Key concepts

 

The VirusTotal API v3 revolves around three key concepts: objects, collections and relationships. An object is any item that can be retrieved or manipulated using the API. Files, URLs, domain names and VT Hunting rulesets are some the object types exposed by the API.

A collection is a set of objects. Objects in a collection are usually of the same type, but there are a few exceptions to that rule. Some API operations are performed on objects, while some others are performed on collections.

Relationships are links between objects, for example: a file can be related to another file because one of them is a ZIP that contains the other, a URL can be related to a file because the file was downloaded from the URL, a domain name is related to all the URLs on that domain.

Objects

 

Objects are a key concept in the VirusTotal API. Each object has an identifier and a type. Identifiers are unique among objects of the same type, which means that a (type, identifier) pair uniquely identifies any object across the API. In this documentation we refer to those (type, identifier) pairs as object descriptors.

Each object has an associated URL with the following structure:

https://www.virustotal.com/api/v3/{collection name}/{object id}

Usually {collection name} is the plural form of the object type, for example, files is the collection containing all the objects of type file, and analyses is the collection containing all the analysis objects. The format for {object id} varies from one object type to another.

A GET request to the object's URL returns information about the object in the following format:

{
  "data": {
    "type": "{object type}",
    "id": "{object id}",
    "links": {
      "self": "https://www.virustotal.com/api/v3/{collection name}/{object id}"
    },
    "attributes" : {
      "integer_attribute": 1234,
      "string_attribute": "this is a string",
      "dictionary_attribute": { "one": 1, "two": 2 },
      "list_attribute": [ "foo", "bar", "baz" ]
    },
    "relationships" : {
       ..
    }
  } 
}

Besides an ID and a type, the object has a set of attributes and relationships. Attributes can be of any type supported by JSON, including lists and dictionaries. The attributes field is always present in all objects, but relationships is optional, depending on whether or not you asked for relationships to be included while making your request. This will discussed in depth in the Relationships section.

Each type of object has its own pre-defined set of attributes, you won't be able to add nor remove attributes, you can only modify existing ones (as long as they are writable). For modifying an object's attributes you must send a PATCH request to the object's URL. If you try to modify a read-only attribute you will get an error. The PATCH request's body must contain the attributes you want to modify in a structure like the one shown in the example below. Any attribute not included in the request will remain unchanged.

{
  "data": {
    "type": "{object type}",
    "id": "{object id}",
    "attributes" : {
      "integer_attribute": 1234,
      "string_attribute": "this is a new string",
    }
  } 
}

Notice that both the object's ID and type are included in the PATCH request's body, and they must match those specified in the URL.

Some object types can be also deleted by sending a DELETE request to the object's URL.

Collections

 

Collections are sets of objects. For most object types there is a top-level collection representing all objects of that type. Those collections can be accessed by using a URL like:

https://www.virustotal.com/api/v3/{collection name}

Many operations in the VirusTotal API are performed by sending requests to a collection. For example, you can analyse a file by sending a POST request to /api/v3/files, which effectively adds a new item to the files collection. You can create a new VT Hunting ruleset by sending a POST request to /api/v3/intelligence/hunting_rulesets. Sending a POST request to a collection is usually the way in which new objects are created.

Similarly, a DELETE request sent to a collection has the effect of deleting all objects in that collection. Of course there's no DELETE method for certain collections like files, urls or analyses, but you can use DELETE with /api/v3/intelligence/hunting_notifications, which, as you already inferred, deletes all your VT Hunting notifications.

Many collections are also iterable, you can retrieve all objects in the collection by sending successive GET requests to the collection. On each request you get a number of objects and a cursor that can be used for continuing the iteration. The snippet below exemplifies the response from a GET request to /api/v3/{collection name}.

{
    "data": [
      { .. object 1 .. },
      { .. object 2 .. },
      { .. object 3 .. }
    ],
    "meta": {
      "cursor": "CuABChEKBGRhdGUSCQjA1.."
    },
    "links": {
        "next": "https://www.virustotal.com/api/v3/{collection name}?cursor=CuABChEKBGRhdGUSCQjA1..",
        "self": "https://www.virustotal.com/api/v3/{collection name}"
    }
}

As the next field in the links section suggest, you can use the cursor in the response's metadata as a parameter in a subsequent call for retrieving the next set of objects. You can also use the limit parameter for controlling how many objects are returned on each call.

Relationships

 

Relationships are the way in which the VirusTotal API expresses links or dependencies between objects. An object can be related to objects of the same or a different type. For example, a file object can be related to some other file object that contains the first one, or a file object can be related to URL objects representing the URLs embedded in the file.

Relationships can be one-to-one or one-to-many, depending of whether the object is related a single object or to multiple objects.

When retrieving a particular object with a GET request you may want to retrieve its relationships with other objects too. This can be done by specifying the relationship you want to retrieve in the relationships parameter.

https://www.virustotal.com/api/v3/{collection name}/{object id}?relationships={relationship}

More than one relationship can be included in the response by specifying a comma-separated list of relationship names.

https://www.virustotal.com/api/v3/{collection name}/{object id}?relationships={relationship 1},{relationship 2}

The objects returned by such requests include the relationships dictionary, where keys are the names of the requested relationships, and values are either an object descriptor (if the relationship is one-to-one) or a collection as described in the Collections section (if the relationship is one-to-many). Notice however that these collections don't contain the whole related objects but only their descriptors (i.e: their type and ID).

{
  "type": "{object type}",
  "id": "{object id}",
  "links": {
    "self": "https://www.virustotal.com/api/v3/{collection name}/{object id}"
  },
  "attributes" : {
     ..
  },
  "relationships" : {
     "{one-to-one relationship}": {
       "data": {
         "id": "www.google.com",
         "type": "domain"
       },
       "links": {
         "related": "https://www.virustotal.com/api/v3/{collection name}/{object id}/{one-to-one relationship}",
         "self": "https://www.virustotal.com/api/v3/{collection name}/{object id}/relationships/{one-to-one relationship}"
       }
     },
     "{one-to-many relationship}": {
       "data": [
         { .. object descriptor 1 .. },
         { .. object descriptor 2 .. },
         { .. object descriptor 3 .. }
       ],
       "meta": {
         "cursor": "CuABChEKBGRhdGUSCQjA1LC...",
       },
       "links": {
         "next": "https://www.virustotal.com/api/v3/{collection name}/{object id}/relationships/{one-to-many relationship}?cursor=CuABChEKBGRhdGUSCQjA1LC...",
         "self": "https://www.virustotal.com/api/v3/{collection name}/{object id}/relationships/{one-to-many relationship}"
       },
     },
    "{relationship 2}": { ... },
    "{relationship 3}": { ... }
  }
}

If you take a closer look to the links field for the relationship in the example above, you'll see that the self URL looks like:

https://www.virustotal.com/api/v3/{collection name}/{object id}/relationships/{relationship}

One-to-many relationships are simply collections that contains objects that are somehow related to a primary object, so they usually have their own URL that you can use for iterating over the related objects by sending GET requests to the URL as described in the Collections section. Well, actually they have two URLs:

https://www.virustotal.com/api/v3/{collection name}/{object id}/relationships/{relationship}
https://www.virustotal.com/api/v3/{collection name}/{object id}/{relationship}

The first one is a collection that contains only the descriptors (type and ID) for the related objects, the second one contains the complete objects, with all their attributes. If you are interested only in the type and ID of the related objects you should use the first one, as it's more efficient to retrieve only the descriptors than the complete objects.

Another important difference between both endpoints is that {object id}/relationships/{relationship} represents the relationship, as an independent entity, and can support operations that change the relationship without altering the objects. On the contrary, {object id}/{relationship} is representing the related objects, not the relationship. For example, if you want to grant a user viewing permissions to a Graph, you use:

POST https://www.virustotal.com/api/v3/graphs/{id}/relationships/viewers

This endpoint receives a user descriptor, it doesn't modify the user nor the graph, it simply creates a relationship between them. On the other hand, when you create a new comment for a file you use:

POST https://www.virustotal.com/api/v3/files/{id}/comments

Because in this case you are not only modifying the relationship between a file and a comment, you are also creating a new comment object.

Users & Groups

 

Users and groups can be managed using the VirusTotal API. Using the API endpoints described in this section group administrators can programmatically add and remove users from their group, list the users existing users, and much more.

/users/{id}

Retrieve user information

 
gethttps://www.virustotal.com/api/v3/users/id
curl --request GET \
  --url https://www.virustotal.com/api/v3/users/{id} \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

User ID

Headers

x-apikey
string
required

Your API key

 
{
  "type": "user",
  "id": "wcoyote",
  "links": {
    "self": "https://www.virustotal.com/api/v3/users/wcoyote"
  },
  "data": {
    "attributes": {
      "apikey": "48e3f0c8d...",
      "email": "wcoyote@acme.com",
      "first_name": "Wile E.",
      "last_login": 1517212458,
      "last_name": "Coyote",
      "privileges": {
        "intelligence": {
          "granted": true,
          "inherited_from": "acme"
        },
        "monitor": {
          "granted": true,
          "inherited_from": "acme"
        },
        "monitor-partner": {
          "granted": true,
          "inherited_from": "acme"
        }
      },
      "quotas": {
        "api_requests_daily": {
          "allowed": 5760,
          "used": 0
        },
        "api_requests_hourly": {
          "allowed": 240,
          "used": 0
        },
        "api_requests_monthly": {
          "allowed": 178560,
          "used": 0
        },
        "intelligence_downloads_monthly": {
          "allowed": 0,
          "used": 0
        },
        "intelligence_retrohunt_jobs_monthly": {
          "allowed": 0,
          "used": 0
        },
        "intelligence_searches_monthly": {
          "allowed": 0,
          "used": 0
        },
        "monitor_storage_bytes": {
          "allowed": 104857600,
          "used": 0
        },
        "monitor_uploaded_bytes": {
          "allowed": 314572800,
          "used": 0
        }
      },
      "reputation": 100,
      "status": "active",
      "user_since": 1496049868
    }  
  }
}

/groups/{id}

Retrieve group information

 
gethttps://www.virustotal.com/api/v3/groups/id
curl --request GET \
  --url https://www.virustotal.com/api/v3/groups/{id} \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

Group ID

Headers

x-apikey
string
required

Your API key

 
{
  "type": "group",
  "id": "acme",
  "links": {
    "self": "https://www.virustotal.com/api/v3/groups/acme"
  },
  "data": {
    "attributes": {
      "allowed_scanners": [],
      "apikey":"ebdc9dd69dcfc2...",
      "auto_add_users": [],
      "billing_address": "Coyote Road 1",
      "billing_country": "United States",
      "billing_country_iso": "US",
      "billing_emails": ["billing@acme.com"],
      "billing_organization_legal_name": "Acme Inc.",
      "billing_tax_id": "1234567",
      "contact_emails": ["contact@acme.com"],
      "country": "United States",
      "country_iso": "US",
      "domain_name": "acme.com",
      "organization": "Acme",
      "privileges": {
        "download": {
          "granted": false
        },
        "file-feed": {
          "granted": false
        },
        "intelligence": {
          "granted": true
        },
        "monitor": {
          "granted": false
        },
        "retrohunt": {
          "granted": false
        },
        "url-feed": {
          "granted": false
        },
      },
      "quota_usage_by_user": {},
      "quotas": {
        "api_requests_daily": {
          "allowed": 15000000,
          "used": 0
        },
        "api_requests_hourly": {
          "allowed": 3300000,
          "used": 0
        },
        "api_requests_monthly": {
          "allowed": 1000000000,
          "used": 0
        },
        "intelligence_downloads_monthly": {
          "allowed": 1000000,
          "used": 0
        },
        "intelligence_retrohunt_jobs_monthly": {
          "allowed": 300,
          "used": 0
        },
        "intelligence_searches_monthly": {
          "allowed": 1000000,
          "used": 0
        },
        "monitor_storage_bytes": {
          "allowed": 5242880000,
          "used": 0
        },
        "monitor_storage_files": {
          "allowed": 100000,
          "used": 0
        },
        "monitor_uploaded_bytes": {
          "allowed": 15728640000,
          "used": 0
        },
        "monitor_uploaded_files": {
          "allowed": 300000,
          "used": 0
        }
      }
    }
  }
}

/groups/{id}/relationships/{relationship}

Retrieve objects related to a group.

 

Header Auth

 Authentication is required for this endpoint.
gethttps://www.virustotal.com/api/v3/groups/id/relationships/relationship
curl --request GET \
  --url https://www.virustotal.com/api/v3/groups/{id}/relationships/{relationship} \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

Group ID.

relationship
string
required

Relationship name (see table below)

Query Params

limit
string

Maximum number of related objects to retrieve

cursor
int32

Continuation cursor

Headers

x-apikey
string
required

Your API key

 

Group objects have number of relationships to other objects. As mentioned in the Relationships section, those related objects can be retrieved by sending GET requests to the relationship URL.

The relationships supported by group objects are:

Relationship
Description
Accessibility

graphs

Graphs created by group members.

Everyone

{
    "data": [
        {
            "attributes": {
                "creation_date": 1530175655,
                "graph_data": {
                    "description": "Piedpiper.com"
                },
                "links": [
                    {
                        "connection_type": "subdomains",
                        "source": "piedpiper.com",
                        "target": "relationships_subdomains_piedpipercom"
                    },
                    {
                        "connection_type": "subdomains",
                        "source": "relationships_subdomains_piedpipercom",
                        "target": "www.piedpiper.com"
                    },
                    {
                        "connection_type": "subdomains",
                        "source": "relationships_subdomains_piedpipercom",
                        "target": "assets.piedpiper.com"
                    },
                    {
                        "connection_type": "resolutions",
                        "source": "piedpiper.com",
                        "target": "relationships_resolutions_piedpipercom"
                    },
                    {
                        "connection_type": "resolutions",
                        "source": "relationships_resolutions_piedpipercom",
                        "target": "104.16.18.64"
                    },
                    {
                        "connection_type": "resolutions",
                        "source": "relationships_resolutions_piedpipercom",
                        "target": "104.16.19.64"
                    },
                    {
                        "connection_type": "resolutions",
                        "source": "relationships_resolutions_piedpipercom",
                        "target": "104.16.15.64"
                    },
                    {
                        "connection_type": "resolutions",
                        "source": "relationships_resolutions_piedpipercom",
                        "target": "104.16.16.64"
                    },
                    {
                        "connection_type": "resolutions",
                        "source": "relationships_resolutions_piedpipercom",
                        "target": "104.16.17.64"
                    },
                    {
                        "connection_type": "resolutions",
                        "source": "relationships_resolutions_piedpipercom",
                        "target": "198.185.159.136"
                    }
                ],
                "nodes": [
                    {
                        "entity_id": "piedpiper.com",
                        "index": 0,
                        "text": "piedpiper.com",
                        "type": "domain",
                        "x": -129,
                        "y": 229
                    },
                    {
                        "entity_id": "relationships_subdomains_piedpipercom",
                        "index": 1,
                        "type": "relationship",
                        "x": -114,
                        "y": 312
                    },
                    {
                        "entity_id": "www.piedpiper.com",
                        "index": 2,
                        "type": "domain",
                        "x": -136,
                        "y": 356
                    },
                    {
                        "entity_id": "assets.piedpiper.com",
                        "index": 3,
                        "type": "domain",
                        "x": -79,
                        "y": 347
                    },
                    {
                        "entity_id": "relationships_resolutions_piedpipercom",
                        "index": 4,
                        "type": "relationship",
                        "x": -154,
                        "y": 144
                    },
                    {
                        "entity_id": "104.16.18.64",
                        "index": 5,
                        "type": "ip_address",
                        "x": -129,
                        "y": 98
                    },
                    {
                        "entity_id": "104.16.19.64",
                        "index": 6,
                        "type": "ip_address",
                        "x": -178,
                        "y": 182
                    },
                    {
                        "entity_id": "104.16.15.64",
                        "index": 7,
                        "type": "ip_address",
                        "x": -201,
                        "y": 114
                    },
                    {
                        "entity_id": "104.16.16.64",
                        "index": 8,
                        "type": "ip_address",
                        "x": -105,
                        "y": 134
                    },
                    {
                        "entity_id": "104.16.17.64",
                        "index": 9,
                        "type": "ip_address",
                        "x": -208,
                        "y": 151
                    },
                    {
                        "entity_id": "198.185.159.136",
                        "index": 10,
                        "type": "ip_address",
                        "x": -170,
                        "y": 92
                    }
                ],
                "position": {
                    "scale": "1",
                    "x": 1346,
                    "y": 561
                },
                "private": false
            },
            "id": "bccd7d4c73f540cab15effd52164658f2a5aa510552f8507f98718f39a438b95",
            "links": {
                "self": "http://localhost:8080/api/v3/graphs/bccd7d4c73f540cab15effd52164658f2a5aa510552f8507f98718f39a438b95"
            },
            "type": "graph"
        },
        {
            "attributes": {
                "creation_date": 1530175617,
                "graph_data": {
                    "description": "Hooli.com"
                },
                "links": [
                    {
                        "connection_type": "subdomains",
                        "source": "hooli.com",
                        "target": "relationships_subdomains_hoolicom"
                    },
                    {
                        "connection_type": "subdomains",
                        "source": "relationships_subdomains_hoolicom",
                        "target": "www.hooli.com"
                    },
                    {
                        "connection_type": "downloaded_files",
                        "source": "hooli.com",
                        "target": "relationships_downloaded_files_hoolicom"
                    },
                    {
                        "connection_type": "downloaded_files",
                        "source": "relationships_downloaded_files_hoolicom",
                        "target": "993b97a069b66508366ee96b3d9a634664ddc13f0d3627b6df478518efd45637"
                    }
                ],
                "nodes": [
                    {
                        "entity_id": "hooli.com",
                        "index": 0,
                        "text": "hooli.com",
                        "type": "domain",
                        "x": 34,
                        "y": 162
                    },
                    {
                        "entity_id": "relationships_subdomains_hoolicom",
                        "index": 1,
                        "type": "relationship",
                        "x": -24,
                        "y": 152
                    },
                    {
                        "entity_id": "www.hooli.com",
                        "index": 2,
                        "type": "domain",
                        "x": -69,
                        "y": 154
                    },
                    {
                        "entity_id": "relationships_downloaded_files_hoolicom",
                        "index": 3,
                        "type": "relationship",
                        "x": 89,
                        "y": 185
                    },
                    {
                        "entity_id": "993b97a069b66508366ee96b3d9a634664ddc13f0d3627b6df478518efd45637",
                        "index": 4,
                        "type": "file",
                        "x": 128,
                        "y": 210
                    }
                ],
                "position": {
                    "scale": "1",
                    "x": 1132,
                    "y": 455
                },
                "private": false
            },
            "id": "272b78feda2261af16e23789baeba67989619b5ee736637ff0d474808248bd52",
            "links": {
                "self": "https://www.virustotal.com/api/v3/graphs/g272b78feda2261af16e23789baeba67989619b5ee736637ff0d474808248bd52"
            },
            "type": "graph"
        }
    ],
    "links": {
        "self": "https://www.virustotal.com/api/v3/groups/danigroup/graphs?limit=10"
    }
}

Livehunt

 

VT Hunting's Livehunt is a service that allows you to hook into the stream of files submitted to VirusTotal and get notified whenever one of them matches a certain YARA rule. The API endpoints described in this section allows you to manage your YARA rules and notifications.

/hunting_rulesets

Retrieve Malware Hunting rulesets

 
gethttps://www.virustotal.com/api/v3/intelligence/hunting_rulesets
curl --request GET \
  --url https://www.virustotal.com/api/v3/intelligence/hunting_rulesets \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Query Params

limit
int32

Maximum number of rulesets to retrieve

filter
string

Return the rulesets matching the given criteria only

order
string

Sort order

cursor
string

Continuation cursor

Headers

x-apikey
string
required

Your API key

 

This endpoint returns the Malware Hunting rulesets viewable by the user making the request. A ruleset is viewable by a user either if it was created by the user or it was shared with him by someone else. This endpoint is equivalent to GET /users/{user}/hunting_rulesets, where {user} is the username of the user owning the API key. In fact, if you look carefully at the example response below you'll notice that the self and next links do not point to /intelligence/hunting_rulesets but to /users/{user}/hunting_rulesets

{
  "data": [
    {
      "type": "hunting_ruleset",
      "id": "{id}",
      "links": {
      	"self": "https://www.virustotal.com/api/v3/intelligence/hunting_rulesets/{id}"
      },
      "attributes": {
        "creation_date": 1523635880,
        "enabled": true,
        "limit": 1000,
        "modification_date": 1525263069,
        "name": "foo",
        "notification_emails": [],
        "rules": "rule foo {condition: false}"
      }
    },
    { .. ruleset 2 .. },
    { .. ruleset 3 .. },
    { .. ruleset 4 .. },
  ],
  "meta": {
    "cursor": "Cu0FCsACCpIC9xuRl9v..."
  },
  "links": {
    "self": "https://www.virustotal.com/api/v3/users/{user}/hunting_rulesets",
    "next": "https://www.virustotal.com/api/v3/users/{user}/hunting_rulesets?cursor=Cu0FCsACCpIC9xuRl9v..."
  }
}

The filter parameter allows to filter the rulesets according to the values of certain attributes. For example you can get only the enabled rulesets with enabled:true. With name:foo and rules:foo you can search for rulesets having the word "foo" in their names or in the YARA rules respectively. Notice however that this only works with full words (words delimited by non-alphanumeric characters), if the ruleset's name is "foobar" it won't appear if you filter with name:foo.

The order parameters control the order in which rulesets are returned, accepted orders are: name, creation_date and modification_date. You can prepend + and - suffixes to specify ascending and descending orders (examples: name-, creation_date+, ). If not suffix is specified the order is ascending by default.

/hunting_rulesets

Create a new Malware Hunting ruleset

 
posthttps://www.virustotal.com/api/v3/intelligence/hunting_rulesets
curl --request POST \
  --url https://www.virustotal.com/api/v3/intelligence/hunting_ruleset \
  --header 'x-apikey: <your API key>'
  --data='{"data": {"type": "hunting_ruleset", "attributes": {"name", "<name>", "rules": "<rules>"}}}'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Body Params

data
string
required

A Malware Hunting ruleset

Headers

x-apikey
string
required

Your API key

 

This endpoint creates a new Malware Hunting ruleset. The request's body must have the following structure:

{
  "data": {
    "type": "hunting_ruleset",
    "attributes": {
      "name": "foobar",
      "enable": true,
      "limit": 100,
      "rules": "rule foobar { strings: $ = \"foobar\" condition: all of them }",
      "notification_emails": ["wcoyte@acme.com", "rrunner@acme.com"]
    }
  }
}

The name and rules attributes are required, the remaining ones are optional.

{
  "type": "hunting_ruleset",
  "id": "{id}",
  "links": {
    "self": "https://www.virustotal.com/api/v3/intelligence/hunting_ruleset/{id}"
  },
  "data": {
    "attributes": {
      "name": "foobar",
      "enabled": true,
  		"limit": 100,
      "creation_date": 1521016318,
      "modification_date": 1521016318,
      "number_of_rules": 1,
      "rules": "rule foobar { strings: $ = \"foobar\" condition: all of them }",
      "notification_emails": ["notifications@acme.com"],
    }
  }
}

/hunting_rulesets/{id}

Retrieve a Malware Hunting ruleset

 
gethttps://www.virustotal.com/api/v3/intelligence/hunting_ruleset/id
curl --request GET \
  --url https://www.virustotal.com/api/v3/intelligence/hunting_ruleset/{id} \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

Ruleset identifier

Headers

x-apikey
string
required

Your API key

 
{
  "data": {
    "type": "hunting_ruleset",
    "id": "{id}",
    "links": {  
      "self": "https://www.virustotal.com/api/v3/intelligence/hunting_rulesets/{id}"
    },
    "attributes": {
      "creation_date": 1523635621,
      "enabled": false,
      "limit": 1000,
      "modification_date": 1525263082,
      "name": "foo",
      "notification_emails": [],
      "rules": "rule foo {condition: false}\n"
    }
  }
}

/hunting_rulesets/{id}

Modify a Malware Hunting ruleset

 
patchhttps://www.virustotal.com/api/v3/intelligence/hunting_rulesets/id
curl --request PATCH \
  --url https://www.virustotal.com/api/v3/intelligence/hunting_rulesets/{id} \
  --header 'x-apikey: <your API key>'
  --data='{"data": {"type": "hunting_ruleset", "id": "<id>", attributes": {"limit": 10}}}'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

Ruleset identifier

Body Params

data
json
required

A Hunting Ruleset object

Headers

x-apikey
string
required

Your API key

 
{
  "data": {
    "type": "hunting_ruleset",
    "id": "{id}",
    "attributes": {
      "enabled": true,
      "limit": 10,
      "name": "bar",
      "notification_emails": ["notifications@acme.com"],
      "rules": "rule foo {condition: false}"
    }
  }
}
{
  "data": {
    "type": "hunting_ruleset",
    "id": "{id}",
    "links": {  
      "self": "https://www.virustotal.com/api/v3/intelligence/hunting_rulesets/{id}"
    },
    "attributes": {
      "creation_date": 1523635621,
      "enabled": true,
      "limit": 10,
      "modification_date": 1525263082,
      "name": "bar",
      "notification_emails": ["notifications@acme.com"],
      "rules": "rule foo {condition: false}"
    }
  }
}

/hunting_rulesets/{id}

Delete a Malware Hunting ruleset

 
deletehttps://www.virustotal.com/api/v3/intelligence/hunting_rulesets/id
curl --request DELETE \
  --url https://www.virustotal.com/api/v3/intelligence/hunting_rulesets/{id} \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

Ruleset identifier

Headers

x-apikey
string
required

Your API key

 

/hunting_notifications

Retrieve Malware Hunting notifications

 
gethttps://www.virustotal.com/api/v3/intelligence/hunting_notifications
curl --request GET \
  --url https://www.virustotal.com/api/v3/intelligence/hunting_notifications \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Query Params

limit
string

Maximum number of notifications to retrieve

cursor
string

Continuation cursor

Headers

x-apikey
string
required

Your API key

 

/hunting_notifications

Delete Malware Hunting notifications

 
deletehttps://www.virustotal.com/api/v3/intelligence/hunting_notifications
curl --request DELETE \
  --url https://www.virustotal.com/api/v3/intelligence/hunting_notifications \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Query Params

tag
string

Delete notifications with the given tag

Headers

x-apikey
string
required

Your API key

 

This endpoint deletes Malware Hunting notifications in bulk. If the tag parameter is specified all your notifications with the given tag will be deleted. If the tag parameter is not specified all your notifications will be deleted.

/hunting_notifications/{id}

Retrieve a Malware Hunting notification

 
gethttps://www.virustotal.com/api/v3/intelligence/hunting_notifications/id
curl --request GET \
  --url https://www.virustotal.com/api/v3/intelligence/hunting_notifications/{id} \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

Notification identifier

Headers

x-apikey
string
required

Your API key

 

/hunting_notifications/{id}

Delete a Malware Hunting notification

 
deletehttps://www.virustotal.com/api/v3/intelligence/hunting_notifications/id
curl --request DELETE \
  --url https://www.virustotal.com/api/v3/intelligence/hunting_notifications/{id} \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

Notification identifier

Headers

x-apikey
string
required

Your API key

 

Retrohunt

 

Beside hunting for files in real time as they arrive to VirusTotal, you can also apply your YARA rules to files sent in the past with the Retrohunt feature. A Retrohunt job takes around ~3-4 hours to complete and scans over 100TB of files sent to VirusTotal in the last ~2.5 months. With the endpoints described in this section you can launch new Retrohunt jobs, track their progress and retrieve information about the matching files.

/retrohunt_jobs

Retrieve retrohunt jobs

 
gethttps://www.virustotal.com/api/v3/intelligence/retrohunt_jobs
curl --request GET \
  --url https://www.virustotal.com/api/v3/intelligence/retrohunt_jobs \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Query Params

limit
int32

Maximum number jobs to retrieve

filter
string

Return the jobs matching the given criteria only

cursor
string

Continuation cursor

Headers

x-apikey
string
required

Your API key

 
{
  "data": [
    {
      "type": "retrohunt_job",
      "id": "{id}",
      "links": {
        "self": "https://www.virustotal.com/api/v3/intelligence/retrohunt_jobs/{id}"
      },
      "attributes": {
        "creation_date": 1524644473,
        "finish_date": 1524658092,
        "progress": 100.0,
        "rules": "rule foobar { strings: $ = \"foobar\" condition: all of them }",
        "scanned_bytes": 121432603386664,
        "start_date": 1524645245,
        "status": "finished",
        "total_matches": 335
      },
    },
    { .. retrohunt job 2 ... },
    { .. retrohunt job 3 ... },
    { .. retrohunt job 4 ... }
  ],
  "links": {
      "next": "https://www.virustotal.com/api/v3/users/{user}/retrohunt_jobs?cursor=ClsKGgoNY3JlYXRpb25fd...",
      "self": "https://www.virustotal.com/api/v3/users/{user}/retrohunt_jobs"
  },
  "meta": {
      "cursor": "ClsKGgoNY3JlYXRpb25fd..."
  }
}

/retrohunt_jobs

Create a new retrohunt job

 
posthttps://www.virustotal.com/api/v3/intelligence/retrohunt_jobs
curl --request POST \
  --url https://www.virustotal.com/api/v3/intelligence/retrohunt_jobs \
  --header 'x-apikey: <your API key>'
  --data='{"data": {"type": "retrohunt_job", "attributes": {"rules": "<job rules>"}}}'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Body Params

data
string
required

A Retrohunt job

Headers

x-apikey
string
required

Your API key

 

This endpoint creates a new Retrohunt job. The request's body must have the following structure:

{
  "data": {
    "type": "retrohunt_job",
    "attributes": {
      "rules": "rule foobar { strings: $ = \"foobar\" condition: all of them }",
      "notification_email": "notifications@acme.com"
    }
  }
}

The rules attribute is required, while notification_email is optionally and should be provided only if you want to receive an email notification when the job is finished.

{
  "type": "retrohunt_job",
  "id": "{id}",
  "links": {
    "self": "https://www.virustotal.com/api/v3/intelligence/retrohunt_jobs/{id}"
  },
  "data": {
    "attributes": {
      "creation_date": 1521016318,
      "notification_email": "notifications@acme.com",
      "progress": 0,
      "rules": "rule foobar { strings: $ = \"foobar\" condition: all of them }",
      "status": "queued",
    }
  }
}

/retrohunt_jobs/{id}

Retrieve a retrohunt job

 
gethttps://www.virustotal.com/api/v3/intelligence/retrohunt_jobs/id
curl --request GET \
  --url https://www.virustotal.com/api/v3/intelligence/retrohunt_jobs/{id} \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

Job identifier

Headers

x-apikey
string
required

Your API key

 
{
  "type": "retrohunt_job",
  "id": "{id}",
  "links": {
    "self": "https://www.virustotal.com/api/v3/intelligence/retrohunt_jobs/{id}"
  },
  "data": {
    "attributes": {
      "creation_date": 1521016318,
      "finish_date": 1521016323,
      "notification_email": "notifications@acme.com",
      "progress": 100.0,
      "rules": "rule foobar { strings: $ = \"foobar\" condition: all of them }",
      "scanned_bytes": 39177343822,
      "status": "finished",
      "total_matches": 10000
    }
  }
}

/retrohunt_jobs/{id}

Delete a retrohunt job

 
deletehttps://www.virustotal.com/api/v3/intelligence/retrohunt_jobs/id
curl --request DELETE \
  --url https://www.virustotal.com/api/v3/intelligence/retrohunt_jobs/{id} \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

Job identifier

Headers

x-apikey
string
required

Your API key

 

/retrohunt_jobs/{id}/abort

Abort a retrohunt job

 
posthttps://www.virustotal.com/api/v3/intelligence/retrohunt_jobs/id/abort
curl --request POST \
  --url https://www.virustotal.com/api/v3/intelligence/retrohunt_jobs/{id}/abort \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

Job identifier

Headers

x-apikey
string
required

Your API key

 

/retrohunt_jobs/{id}/matches

Retrieve matches for a retrohunt job

 
gethttps://www.virustotal.com/api/v3/intelligence/retrohunt_jobs/id/matches
curl --request GET \
  --url https://www.virustotal.com/api/v3/intelligence/retrohunt_jobs/{id}/matches \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

Job identifier

Headers

x-apikey
string
required

Your API key

 

Monitor

 

Virustotal Monitor is designed to analyse goodware collections, helping antivirus companies and software developers with the early detection of false positives (mistakenly flagging legit files as malicious).

Software developers can upload their files to the service and they will be periodically scanned with the latest VirusTotal antivirus signature sets, notifying users in the event that any antivirus flags their files and keeping a historical record of all analyses performed on their software collection.

In order to simplify false positive management and allow fast remediation, Virustotal Monitor gives antivirus companies access to detected file metadata (file hash, file name and path, detection signature, and other user provided information).

For this purpose it is crucial that the user has an accurate and updated profile, as this information is going to be shared with the scanner companies if, and only if, files are detected. There is an API endpoint where the user can tweak their monitor preferences. This process can also be completed through the VirusTotal Monitor user interface:

Additionally you can use this example python script to upload your files, just provide a origin folder and a remote destination and will iterate over files in that directories and upload them to your monitor account. Use the "--help" parameter to obtain a list of upload modifiers.

Monitor Items

Details about objects stored in the VirusTotal Monitor service.

 

A MonitorItem object refers to a file or folder stored in VirusTotal Monitor and it is referenced via an ID. Using the right API calls it is not necessary to know how MonitorItem IDs are built, however, under certain circumstances you might find it easier to interact with the service by composing the IDs yourself.

A MonitorItem ID is made up of a base64 encoded string containing an utf8 formatted string following this pattern:

vtmonitor-v1://{owner_id}{path}

{owner_id} refers to the VirusTotal group your user belongs to and to whom the Monitor privilege was granted. This information can be retrieved using the GET /users/{id} endpoint with your user ID. The name of the group from which your user inherits its Monitor privileges will appear in the the inherited_from field of the monitor privilege.

{
  "type": "user",
  "id": "wcoyote",
  "links": {
    "self": "https://www.virustotal.com/api/v3/users/wcoyote"
  },
  "data": {
    "attributes": {
      "privileges": {
        "monitor": {
          "granted": true,
          "inherited_from": "acme"
        },
      }
    }  
  }
}

/items

Get a list of MonitorItem objects by path or tag

 
get/items
curl --request GET \
  --url https://www.virustotal.com/api/v3/monitor/items \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Query Params

filter
string

Return the items matching the given criteria only

cursor
string

Continue listing after this offset

limit
int32

Maximum number of items to retrieve

Headers

x-apikey
string
required

Your API key

 

Items can be listed according to the parameters contained in filter:

  • path: folder (String: /myfolder/)
  • item: (MonitorItem ID describing a folder)
  • tag: (One or more space separated tags from the following list)
    • detected: files flagged by at least one antivirus engine.
    • new-detections: files that have been flagged by at least one antivirus engine and were previously undetected.
    • decreasing-detections: files flagged by at least one antivirus engine that have less detections with respect to their previous analysis.
    • increasing-detections: files flagged by at least one antivirus engine that have more detections with respect to their pervious analysis.
    • solved-detections: files that are no longer detected by any antivirus engine and were previously detected.
    • swapped-detections: files that are detected by the same number of antivirus engines as their previous analysis but either the set of engines detecting the file or their detection labels have changed.
    • [engine_name]: files detected by the given antivirus engine.

Here you can see some examples for the most common operations:

import requests

session = requests.Session()
session.headers = {'X-Apikey': '<api-key>'}

url = "https://www.virustotal.com/api/v3/monitor/items"
querystring = {"filter": "tag:detected"}

response = session.get(url, params=querystring)
print(response.text)
import requests

session = requests.Session()
session.headers = {'X-Apikey': '<api-key>'}

url = "https://www.virustotal.com/api/v3/monitor/items"
querystring = {"filter": "tag:<av-name>"}

response = session.get(url, params=querystring)
print(response.text)
import requests

session = requests.Session()
session.headers = {'X-Apikey': '<api-key>'}

url = "https://www.virustotal.com/api/v3/monitor/items"
querystring = {"filter": "path:/"}

response = session.get(url, params=querystring)
print(response.text)
import requests

session = requests.Session()
session.headers = {'X-Apikey': '<api-key>'}

url = "https://www.virustotal.com/api/v3/monitor/items"
querystring = {"filter": "tag:new-detections"}

response = session.get(url, params=querystring)
print(response.text)
{
  "data": [
    {
      "type": "monitor_item", 
      "id": "{id}", 
      "attributes": {
        "size": 2981888, 
        "sha1": "521a85a43fc8ccbe3409e39bd8ef7719c6d747d5", 
        "first_detection_date": 1510080120, 
        "tags": [
          "detected", 
          "{engine name 1}", 
          "{engine name 2}"
        ], 
        "last_analysis_date": 1517234132, 
        "creation_date": 1510079766, 
        "item_type": "file", 
        "creator_id": "fsantos", 
        "last_analysis_results": {
          "{engine name 1}": {
            "category": "undetected", 
            "engine_name": "[{engine name 1}", 
            "engine_version": "1.3.0.9466", 
            "result": null, 
            "method": "blacklist", 
            "engine_update": "20180129"
          },
          "{engine name 2}": { 
            ... 
          }
        }, 
        "details": "This is a windows go executable file", 
        "path": "/go1.7.4_pkg_tool_windows_386/addr2line.exe", 
        "sha256": "e9a08208ade9afb630f3bad01461b552086fc675e547214c73ac966aa7806847", 
        "last_detections_count": 2, 
        "md5": "a17b39a3a280c48a6b8b4b0b7982606c"
      },
    }
  ]
}

/items

Upload a file or create a new folder

 
post/items
curl --request POST \
  --url https://www.virustotal.com/api/v3/monitor/items \
  --header 'x-apikey: <your API key>' \
  --form path='/' \
  --form file=@/path/to/file
A binary file was returned

You couldn't be authenticated

Try the API to see results

Body Params

file
file
required

Encoded file

path
string

A path relative to current monitor user root folder. In must include the filename at the end of the path or a / if it's a folder being created

item
string

A Monitor ID describing group and path

Headers

x-apikey
string
required

Your API key

 

This endpoint can be used to create or overwrite an already existing file using a multipart/form-data encoded request. The file has to be smaller than 32MB, for bigger files use a URL returned by /items/upload_url.

The parameter path indicates the path relative to your monitor root folder where the file is going to be stored. This path must include the name of the file being uploaded. For example /folder/myfile.exe. You can also provide a MonitorItemID representing a path to a file previously uploaded to VT Monitor and this will upload the new file to this path, overwriting the file referenced by the MonitorItemID.

To create a new folder just make a request with the desired path or item ending it with a slash (/), for example /mynewfolder/.

The MonitorItemID returned in the response can be used at a later stage to operate with the given file or folder and request its analysis information.

{
 "data": {
  "type": "monitor_item", 
  "id": "[MONITOR-ID]"
 }
}

/items/upload_url

Get a URL for uploading files larger than 32MB

 
get/items/upload_url
curl --request GET \
  --url https://www.virustotal.com/api/v3/monitor/items/upload_url \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Headers

x-apikey
string
required

Your API key

 

For uploading files smaller than 32MB you can simply send a POST request to the /items endpoint, but for larger files you need to get a special upload URL first. This endpoint returns one of those URLs. The returned URL can be used as a drop-in replacement for the /items endpoint. A new upload URL should be generated each big file upload.

{
  "data": "http://www.virustotal.com/_ah/upload/AMmfu6b-_DXUeFe36Sb3b0F4B8mH9Nb-CHbRoUNVOPwG/"
}

/items/{id}

Retrieve attributes and metadata for a specific MonitorItem.

 
get/items/id
curl --request GET \
  --url https://www.virustotal.com/api/v3/monitor/items/{id} \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

Monitor item identifier

Headers

x-apikey
string
required

Your API key

 
{
 "data": {
  "attributes": {
   "size": 8538624, 
   "sha1": "a9e2e47fd90b3552a072af482289532e878472fa", 
   "first_detection_date": 1502393426, 
   "next_analysis_date": 1504559882, 
   "last_analysis_date": 1504473518, 
   "tags": [
    "detected", 
    "new-detections", 
    "[ENGINE-NAME]"
   ], 
   "creation_date": 1501700980, 
   "item_type": "file", 
   "creator_id": "fsantos", 
   "last_analysis_results": {
    "[ENGINE-NAME]": {
     "category": "undetected", 
     "engine_name": "[ENGINE-NAME]", 
     "engine_version": "9.950.0.1006", 
     "result": null, 
     "method": "blacklist", 
     "engine_update": "20170903"
    }, 
    "[ENGINE-NAME]": {
     "category": "undetected", 
     "engine_name": "[ENGINE-NAME]", 
     "engine_version": "25.0.0.1", 
     "result": null, 
     "method": "blacklist", 
     "engine_update": "20170901"
    }
   }, 
   "path": "/go/bin/go.exe", 
   "sha256": "4db14737445edd2078a383520fabfd212f0979a31d0165dceac9f741fb1ab985", 
   "last_detections_count": 1, 
   "first_detection_date": 1504300116, 
   "md5": "3f389f88d18ba26e946a05883ea04130"
  }, 
  "type": "monitoritem", 
  "id": "[MONITOR-ID]"
 }
}

/items/{id}

Delete a VirusTotal Monitor file or folder.

 
delete/items/id
curl --request DELETE \
  --url https://www.virustotal.com/api/v3/monitor/items/{id} \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

Monitor item identifier

Headers

x-apikey
string
required

Your API key

 

/items/{id}/config

Configure a given VirusTotal Monitor item (file or folder).

 
patch/items/id/config
curl --request PATCH \
  --url https://www.virustotal.com/api/v3/monitor/items/{id}/config \
  --data="{'data': {\
        'id': <item-id>,\
        'type': 'monitoritem',\
        'attributes': {\
            'details': 'This is file metadata.'\
       }}}"
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

Monitor item identifier

Body Params

data
json
required

MonitorItem obj

Headers

x-apikey
string
required

Your API key

 

Is possible to set some file information/metadata into a MonitorItem by setting its details attribute, this information will be shared with Monitor Partners and should be used to give more context to them about the file in case of false positive. Folders does not support details.

import requests

item_id = '<item-id>'

url = "https://www.virustotal.com/api/v3/monitor/items/%s/config" % item_id
data = {'data': {
        'id': item_id,
        'type': 'monitoritem',
        'attributes': {
            'details': 'This is file metadata.'
       },
    }}

response = requests.request("PATCH", url, data=json.dumps(data))
print(response.text)
{
 "data": {
  "attributes": {
   "size": 49676, 
   "sha1": "892392d4f28b2dbe8ae45115a38c079dbcb14e18", 
   "first_detection_date": 1504175079, 
   "sha256": "cb9f9c1b271daa19fc78138dfd9d37686b1edb35e381f205c0b59911d8a004e1", 
   "next_analysis_date": 1504781041, 
   "last_detections_count": 1, 
   "last_analysis_date": 1504694733, 
   "tags": [
    "detected", 
    "visible", 
    "[ENGINE-NAME]"
   ], 
   "creation_date": 1504174971, 
   "item_type": "file", 
   "creator_id": "fsantos", 
   "last_analysis_results": {
    "[ENGINE-NAME]": {
     "category": "undetected", 
     "engine_name": "[ENGINE-NAME]", 
     "engine_version": "1.3.0.9330", 
     "result": null, 
     "method": "blacklist", 
     "engine_update": "20170906"
    },...
   }, 
   "details": "This is the metadata.", 
   "path": "/test/tac.exe", 
   "md5": "02c526e8efd42a1f57a75aa203cfb27f"
  }, 
  "type": "monitoritem", 
  "id": "[MONITOR-ID]"
 }
}

/items/{id}/download

Download a file in VirusTotal Monitor

 
get/items/id/download
curl --request GET \
  --url https://www.virustotal.com/api/v3/monitor/items/{id}/download \
  --header 'x-apikey: <your API key>' --location
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

Monitor item identifier

Headers

x-apikey
string
required

Your API key

 

This handler allows you to download a file already uploaded to Virustotal Monitor.

/items/{id}/download_url

Retrieve a URL for downloading a file in VirusTotal Monitor

 
get/items/id/download_url
curl --request GET \
  --url https://www.virustotal.com/api/v3/monitor/items/{id}/download_url \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

Monitor item identifier

Headers

x-apikey
string
required

Your API key

 

This endpoint returns a signed URL from where you can download the specified file from VirusTotal Monitor. The URL expires after 1 hour.

/items/{id}/analyses

Retrieve latest file analyses

 
get/items/id/analyses
curl --request GET \
  --url https://www.virustotal.com/api/v3/monitor/items/{id}/analyses \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

Monitor item identifier

Query Params

cursor
string

Continue listing after this offset

limit
string

Maximum number of analyses to retrieve

Headers

x-apikey
string
required

Your API key

 

Retrieve item analyses, use cursor and limit to retrieve older ones.

{
  "data": [
    {
      "id": "d917dd47406322341cef40cf38091292962ba81d42983456aae4dc4f7967afb1-1517474700",
      "type": "monitor_analysis",
      "attributes": {
        "analysis_results": {
          "{engine name}": {
            "category": "undetected",
            "engine_name": "{engine name}",
            "engine_update": "20180201",
            "engine_version": "1.1.1.3",
            "method": "blacklist",
            "result": null
          }
        },
        "date": 1517474787,
        "detections_count": 1,
        "sha256": "d917dd47406322341cef40cf38091292962ba81d42983456aae4dc4f7967afb1",
        "tags": [
          "detected",
          "{engine name}"
        ]
      }
    }
  ]
}

/items/{id}/owner

Retrieve latest file analyses

 
get/items/id/owner
curl --request GET \
  --url https://www.virustotal.com/api/v3/monitor/items/{id}/owner \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

Monitor item identifier

Headers

x-apikey
string
required

Your API key

 

Retrieve item analyses, use cursor and limit to retrieve older ones.

{"data": [
  {
   "attributes": {
    "analysis_results": {
     "[ENGINE-NAME]": {
      "category": "undetected",
      "engine_name": "[ENGINE-NAME]",
      "engine_update": "20180129",
      "engine_version": "1.1.1.3",
      "method": "blacklist",
      "result": null
     },
     "[ENGINE-NAME]": {
      "category": "undetected",
      "engine_name": "[ENGINE-NAME]",
      "engine_update": "20180130",
      "engine_version": "17.9.3761.0",
      "method": "blacklist",
      "result": null
     }...
    },
    "date": 1517308584,
    "detections_count": 0,
    "sha256": "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2",
    "tags": []
   },
   "id": "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2-1517308500",
   "type": "monitor_analysis"
  }...
 ]
}

/items/{id}/comments

Retrieve partner's comments on a file

 
get/items/id/comments
curl --request GET \
  --url https://www.virustotal.com/api/v3/monitor/items/{id}/comments \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

Monitor item identifier

Query Params

cursor
string

Continue listing after this offset

limit
string

Maximum number of analyses to retrieve

Headers

x-apikey
string
required

Your API key

 
{
  "data": [
    {
      "type": "monitor_hash_comment",
      "id": "6620bdb508ab363eee95fd511ae88e2e38daf948b117bd49bcf8609f87cc86de-{engine name}",
      "attributes": {
        "comment": "This is an example comment.",
        "date": 1519222846,
        "detection": "confirmed",
        "engine": "{engine name}",
        "sha256": "6620bdb508ab363eee95fd511ae88e2e38daf948b117bd49bcf8609f87cc86de"
      }
    }
  ]
}

/statistics

Retrieve statistics about analyses performed on your software collection.

 
get/statistics
curl --request GET \
  --url https://www.virustotal.com/api/v3/monitor/statistics \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Query Params

cursor
string

List after this date

limit
string

Maximum number of statistic periods to return

Headers

x-apikey
string
required

Your API key

 

This endpoint returns information about your stored files, including quota consumption, detected files, top signatures, offending engines and oldest detections pending remediation.

A dictionary with data and meta properties is received, each data attributes will reflect past days statistics and meta realtime will reflect current detection counts. Data attributes also contains information about last day consumed storage (for realtime quota consumption user data should be check /ui/signin).

{"data": [
 {
  "attributes": {
  "date": 1517270400,
  "items_detected_count": 28,
  "increasing_detections_count": 6,
  "owner_id": "monitor_group",
  "period": "day",
  "storage_bytes_count": 166709820,
  "storage_files_count": 34,
  "top_age_items": [
   {
   "age": 7621121,
   "detections_count": 46,
   "monitor_key": "[MONITOR-ID]",
   "total_engines_count": 71
   }...
  ],
  "top_detected_items": [
   {
   "detections_count": 47,
   "monitor_key": "[MONITOR-ID]",
   "total_engines_count": 71
   }...
  ],
  "top_engines": [
   {
   "count": 20,
   "engine": "[ENGINE-NAME]"
   }...
  ],
  "top_signatures": [
   {
   "count": 20,
   "signature": "Unsafe"
   }...
  ]
  },
  "id": "monitor_group-day-2018-01-30",
  "type": "monitor_statistics"
 }...
 ],
 "meta": {
 "realtime": {
  "decreasing_detections_count": 0,
  "increasing_detections_count": 6,
  "items_detected_count": 28,
  "new_detections_count": 0,
  "solved_detections_count": 0,
  "swapped_detections_count": 0
 }
 }
}

Monitor Partner

 

VirusTotal Monitor Partner's aim is to ease false positive handling by antivirus companies. It is designed to provide VirusTotal participating AV scanners with hashes, file content, metadata and ownership information for any detection of a file in a Monitor collection. Note that files will only be shared upon a false positive.

As stated in VirusTotal Monitor overview software developers having an account in Monitor can upload their goodware collection to be periodically analysed by participating antivirus scanners. Note that these accounts are handed over to users once VirusTotal staff verifies and identifies them. Any of the hashes detected by your engine will be available in the Monitor Partner webapp or via the API calls documented bellow.

A common flow is described below:

  • A Monitor account is handed over to a user.
  • Users upload some files and make some comments on them in the details metadata section.
  • At some point in time or just after being uploaded a file is detected by your engine.
  • A new hash appears in the /hashes endpoint or in the website Analyses tab.
  • You request items to get files with that particular hash from any user collection, a hash could appear in different collections with different details. This situation (one hash/many files) may happen for example because sometimes software developers include certain versions of operating system files with their binaries, so one owner may be the operating system developer and the rest some other software developers. The details about each item owner can be obtained requesting the Monitor API endpoint.
  • You can also request hash analyses to get hash historic scanning information.
  • Once a false positive is confirmed your engine signatures may be updated and in the next cycle and the hash will disappear from the Analyses.
  • Alternatively, you can confirm that the detection is correct and hide it from your analyses posting
    a comment over it. You can always access these hashes filtering with ignored tag over hashes and revert this action.

For your convenience we generate a daily CSV formatted file with company name, hash and url with your detections. A new bundle is available each day at 1am UTC.
Additionally you can use this example python script to generate a similar report for your account at the current time, it will download all related hash files and its metadata storing it on your filesystem in json format.

You can also access information about your engine detections and collection size in daily statistics.

Here are some Monitor Partner website captures:

/hashes

Get a list of MonitorHashes detected by an engine

 
get/hashes
curl --request GET \
  --url https://www.virustotal.com/api/v3/monitor_partner/hashes \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Query Params

filter
string

Retrive hashes matching this condition, refer to the right block of the documentation

cursor
string

Continue listing after this offset

limit
int32

Maximum number of items to retrieve (max: 40)

Headers

x-apikey
string
required

Your API key

 

In some cases your user may have access to analyses of more than one engine, in this case you can provide a filter query with one engine name. To retrieve your preconfigured engine names you need to access the preferences/monitor_partner/engines property calling /groups/{group_id}, in case you do not know your monitor_partner group_id, it can be obtained from privileges/monitor-partner/inherited_from property calling /users/{your_user_id}.

To display the latest hash analyses for a specific engine use the filter parameter with the modifier:

  • engine: (String: <engine-name>)

To display ignored hashes (detection confirmed ones /hashes/{sha256}/comments):

  • tag:ignored

Here you can see an example:

import requests

session = requests.Session()
session.headers = {'X-Apikey': '<api-key>'}

url = "https://www.virustotal.com/api/v3/monitor_partner/hashes"
querystring = {"filter": "engine:<engine-name>"}

response = session.get(url, params=querystring)
print(response.text)
{
 "data": [
  {
   "attributes": {
    "last_analysis_date": 1517433370,
    "last_analysis_results": {
     "[ENGINE-NAME]": {
      "category": "undetected",
      "engine_name": "[ENGINE-NAME]",
      "engine_update": "20180131",
      "engine_version": "1.1.1.3",
      "method": "blacklist",
      "result": null
     }...
    },
    "last_detections_count": 1,
    "md5": "432fb4158186f0c8268813741939239a",
    "sha1": "6d06bba4f7625409e8a2f7e201c38b1b5925609a",
    "sha256": "29037cca6156dbf44a80a0c785f2b9d5c205cecd3bf7b044d99b462149bc5ae8",
    "size": 16384
   },
   "id": "29037cca6156dbf44a80a0c785f2b9d5c205cecd3bf7b044d99b462149bc5ae8",
   "type": "monitor_hash"
  }...
 ]
}

/hashes/{sha256}/analyses

Get a list of analyses for a given sha256 hash

 
get/hashes/sha256/analyses
curl --request GET \
  --url https://www.virustotal.com/api/v3/monitor_partner/hashes/{sha256}/analyses \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

sha256
string
required

Hash sha256

Query Params

cursor
string

Continue listing after this offset

limit
string

Maximum number of items to retrieve (max: 40)

Headers

x-apikey
string
required

Your API key

 

This endpoint allows you to retrieve all analyses performed on a certain sha256 hash using cursored listings.

import requests

session = requests.Session()
session.headers = {'X-Apikey': '<api-key>'}

url = "https://www.virustotal.com/api/v3/monitor_partner/hashes/<sha256>/analyses"
response = session.get(url)
print(response.text)
{
  "data": [
    {
      "id": "d917dd47406322341cef40cf38091292962ba81d42983456aae4dc4f7967afb1-1517474700",
      "type": "monitor_analysis",
      "attributes": {
        "analysis_results": {
          "{engine name}": {
            "category": "undetected",
            "engine_name": "{engine name}",
            "engine_update": "20180201",
            "engine_version": "1.1.1.3",
            "method": "blacklist",
            "result": null
          }
        },
        "date": 1517474787,
        "detections_count": 1,
        "sha256": "d917dd47406322341cef40cf38091292962ba81d42983456aae4dc4f7967afb1",
        "tags": [
          "detected",
          "{engine name}"
        ]
      }
    }
  ]
}

/hashes/{sha256}/items

Get a list of items with a given sha256 hash

 
get/hashes/sha256/items
curl --request GET \
  --url https://www.virustotal.com/api/v3/monitor_partner/hashes/{sha256}/items \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

sha256
string
required

Hash sha256

Query Params

cursor
string

Continue listing after this offset

limit
string

Maximum number of items to retrieve (max: 40)

Headers

x-apikey
string
required

Your API key

 

This endpoint allows you to retrieve file paths, descriptions, etc. for all files in monitor with a certain sha256 hash.

import requests

session = requests.Session()
session.headers = {'X-Apikey': '<api-key>'}

url = "https://www.virustotal.com/api/v3/monitor_partner/hashes/<sha256>/items"
response = session.get(url)
print(response.text)
{
 "data": [
  {
   "attributes": {
    "creation_date": 1517387994,
    "details": "Original filename: \"shvlres.dll\"",
    "first_detection_date": 1517388090,
    "last_analysis_date": 1517474787,
    "last_analysis_results": {
     "[ENGINE-NAME]": {
      "category": "undetected",
      "engine_name": "[ENGINE-NAME]",
      "engine_update": "20180201",
      "engine_version": "1.1.1.3",
      "method": "blacklist",
      "result": null
     }...
    },
    "last_detections_count": 1,
    "md5": "1d5544d6ca1ac6674e9ea11d4b947c35",
    "path": "shvlres.dll",
    "sha1": "9024e1b34143321f4fb6ea717cde48a293bf99e0",
    "sha256": "d917dd47406322341cef40cf38091292962ba81d42983456aae4dc4f7967afb1",
    "size": 2178131
   },
   "id": "[MONITOR-ID]",
   "type": "monitor_item"
  }
 ]}
}

/hashes/{sha256}/comments

Create a comment and if necessary confirm detection over a hash

 
post/hashes/sha256/comments
curl --request POST \
  --url https://www.virustotal.com/api/v3/monitor_partner/hashes/{sha256}/comments \
  --header 'x-apikey: <your API key>' \
  --data-binary "{'data': [{'attributes': {\
                      'comment': '[TEXT]',\
                      'detection': 'confirmed',\
                      'engine': '[ENGINE-ID]',\
                      'sha256': '[HASH-SHA256]'},\
                    'type': 'monitor_hash_comment'}]}"
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

sha256
string
required

Hash sha256

Body Params

data
json

A json object with a MonitorHashComment

Headers

x-apikey
string
required

Your API key

 

This endpoint allows you to create a comment over certain hash, this comment may be visible to other partners (for example if they also detect the hash) and to monitor users who have a file with this hash.
A MonitorHashComment also have a detection attribute that could be set to 'confirmed' to ignore this particular hash from that moment on. Once the hash comment is marked as confirmed any new monitor analysis for this file that your engine will detect will not be shown anymore when requesting latests analyses. This behabiour can be reverted deleting the comment or updating it with detection attribute set to None.
Ignored hashes with detections still can be retrieved using /hashes endpoint with a filter "tag:ignored"

import requests

sha256 = '<hash-sha256>'
engine = '<your-engine-id>'

url = "https://www.virustotal.com/api/v3/monitor_partner/hashes/%s/comments" % sha256
data = {'data': [{'attributes': {
          'comment': '[TEXT]',
          'detection': 'confirmed',
          'engine': engine,
          'sha256': sha256},
        'type': 'monitor_hash_comment'}]}

response = requests.request("POST", url, data=json.dumps(data))
print(response.text)
{
  'data': [
    {
      'type': 'monitor_hash_comment',
      'id': '{id}',
      'attributes': {
        'comment': '{text}',
        'detection': 'confirmed',
        'engine': '{engine name}',
        'sha256': '{sha256}'
      }
    }
  ]
}

/comments/{id}

Retrieve comment data

 
get/comments/id
curl --method GET \
  --url https://www.virustotal.com/api/v3/monitor_partner/comments/{id}/ \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

Comment ID

Headers

x-apikey
string
required

Your API key

 

This endpoint allows you to retrieve partner comments over a certain sha256 hash.

import requests

session = requests.Session()
session.headers = {'X-Apikey': '<api-key>'}

url = "https://www.virustotal.com/api/v3/monitor_partner/comments/<comment-id>/"
response = session.get(url)
print(response.text)
{
  'data': [
    {
      'type': 'monitor_hash_comment',
      'id': '{id}',
      'attributes': {
        'comment': '{text}',
        'detection': 'confirmed',
        'engine': '{engine name}',
        'sha256': '{sha256}'
      }
    }
  ]
}

/comments/{id}

Create a comment and if necessary confirm detection over a hash

 
patch/comments/id
curl --request PATCH \
  --url https://www.virustotal.com/api/v3/monitor_partner/comments/{id} \
  --header 'x-apikey: <your API key>' \
  --data-binary "{'data': [{'attributes': {\
                      'comment': '[TEXT]',\
                      'detection': 'confirmed',\
                      'engine': '[ENGINE-ID]',\
                      'sha256': '[HASH-SHA256]'},\
                    'type': 'monitor_hash_comment'}]}"
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

Comment identifier

Body Params

data
json

A json object with a MonitorHashComment

Headers

x-apikey
string
required

Your API key

 

This endpoint allows you to update a comment and change detection if necessary. More information about detection attribute could be found in /hashes/{sha256}/comments.

import requests

comment_id = '<comment-id>'

url = "https://www.virustotal.com/api/v3/monitor_partner/comments/{comment_id}" % comment_id
data = {'data': [{'attributes': {
          'comment': '[TEXT]',
          'detection': 'confirmed',
          'engine': '[ENGINE]',
          'sha256': '[HASH-SHA256]},
        'id': comment_id,
        'type': 'monitor_hash_comment'}]}

response = requests.request("POST", url, data=json.dumps(data))
print(response.text)
{'data': [
  {'attributes': {
     'comment': '[TEXT]',
     'detection': 'confirmed',
     'engine': '[ENGINE-ID]',
     'sha256': '[HASH-SHA256]'
   },
   'id': '[MONITOR-COMMENT-ID]',
   'type': 'monitor_hash_comment'
  }]}

/comments/{id}

Remove a comment and reset confirmed detection for a hash.

 
delete/comments/id
curl --request DELETE \
  --url https://www.virustotal.com/api/v3/monitor_partner/comments/{id} \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

id
string
required

Comment identifier

Headers

x-apikey
string
required

Your API key

 

This endpoint allows you to delete a comment and change detection to None so hash will appear over analysis listings if detected. More information about detection attribute could be found in /hashes/{sha256}/comments.

import requests

comment_id = '<comment-id>'

url = "https://www.virustotal.com/api/v3/monitor_partner/comments/{comment_id}" % comment_id

response = requests.request("DELETE", url)
print(response.text)

/files/{sha256}/download

Download a file with a given sha256 hash

 
get/files/sha256/download
curl --method GET \
  --url https://www.virustotal.com/api/v3/monitor_partner/files/{sha256}/download \
  --header 'x-apikey: <your API key>' --location
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

sha256
string
required

Hash sha256

Query Params

cursor
string

Continue listing after this offset

limit
int32

Maximum number of items to retrieve (max: 40)

Headers

x-apikey
string
required

Your API key

 

This endpoint allows you to download a file by sha256 hash.

import requests

session = requests.Session()
session.headers = {'X-Apikey': '<api-key>'}

url = "https://www.virustotal.com/api/v3/monitor_partner/files/{sha256}/download"
response = session.get(url)
print(response.text)

/files/{sha256}/download_url

Retrieve a download url for a file with a given sha256 hash

 
get/files/sha256/download_url
curl --request GET \
  --url https://www.virustotal.com/api/v3/monitor_partner/files/{sha256}/download_url \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

sha256
string
required

Hash sha256

Query Params

cursor
string

Continue listing after this offset

limit
int32

Maximum number of items to retrieve (max: 40)

Headers

x-apikey
string
required

Your API key

 

This endpoint allows you to get a download url for a file with a given sha256 hash. These URLs are ephemeral and have a one hour expiration date.

import requests

session = requests.Session()
session.headers = {'X-Apikey': '<api-key>'}

url = "https://www.virustotal.com/api/v3/monitor_partner/files/{sha256}/download_url"
response = session.get(url)
print(response.text)

/detections_bundle/download

Download a daily detection bundle

 
get/detections_bundle/download
curl --request GET \
  --url https://www.virustotal.com/api/v3/monitor_partner/detections_bundle/download \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

sha256
string
required

Hash sha256

Query Params

cursor
string

Continue listing after this offset

limit
string

Maximum number of items to retrieve (max: 40)

Headers

x-apikey
string
required

Your API key

 

Each day a CSV formated list with hash detections is generated for each engine. Each line contains an owner company, hash, analysis history link and a hash download url.
If your account is set up for more than one engine you should access each engine bundle pointing to /api/v3/monitor/detections_bundle/{engine}/download
To download previous bundles you can use: /api/v3/monitor/detections_bundle/{engine}/{date('%Y-%m-%d')}/download

import requests

session = requests.Session()
session.headers = {'X-Apikey': '<api-key>'}

url = "https://www.virustotal.com/api/v3/monitor_partner/detections_bundle/download"
response = session.get(url)
print(response.text)

/detections_bundle/download_url

Get daily detection bundle URL

 
get/detections_bundle/download_url
curl --request GET \
  --url https://www.virustotal.com/api/v3/monitor_partner/detections_bundle/download_url \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Path Params

sha256
string
required

Hash sha256

Query Params

cursor
string

Continue listing after this offset

limit
string

Maximum number of items to retrieve (max: 40)

Headers

x-apikey
string
required

Your API key

 

Refer to /detections_bundle/download for additional options.

import requests

session = requests.Session()
session.headers = {'X-Apikey': '<api-key>'}

url = "https://www.virustotal.com/api/v3/monitor_partner/detections_bundle/download_url"
response = session.get(url)
print(response.text)

/statistics

Get a list of MonitorHashes detected by an engine

 
get/statistics
curl --request GET \
  --url "https://www.virustotal.com/api/v3/monitor_partner/statistics" \
  --header 'x-apikey: <your API key>'
A binary file was returned

You couldn't be authenticated

Try the API to see results

Query Params

cursor
string

List after this date

limit
string

Maximum number of statistic periods to return

filter
string

Filter parameters

Headers

x-apikey
string
required

Your API key

 

Statistics provide information about hashes detected and total hashes analyzed by your engine. In case you have more than one engine you can use filter=engine:<engine-name>

{
  "data": [
    {
      "attributes": {
        "date": 1517356800,
        "engine": "[ENGINE-NAME]",
        "hashes_count": 1840,
        "hashes_detected_count": 34,
        "items_count": 1840,
        "items_detected_count": 34,
        "period": "day"
      },
      "id": "[ENGINE-NAME]-day-2018-01-31",
      "links": {
        "self": "https://www.virustotal.com/api/v3/monitor_partner/statistics/[ENGINE-NAME]-day-2018-01-31"
      },
      "type": "monitor_partner_statistics"
    }...
  ]
}