This is a copy of the API documentation that can be found here.
Introduction
Perception Point API enables the scanning of files and URLs to detect whether they are malicious or clean. Files and URLs are scanned using Perception Point’s multi-layered architecture including HAP (Hardware Assisted Platform). The API can be used in two ways; callbacks or polling. provides a callback mechanism that allows getting notifications when scanning is completed instead of polling the service.
API Structure
Authentication
The request HEADERS must contain an Authorization token:
Header Key: “Authorization”
Header Value: “Token <TOKEN_VALUE>”
Example
response = requests.post(“https://<PERCEPTION-POINT-URL>/someAPI/”, ) print response {"scan_id": 123456} |
File API
POST https://<PERCEPTION-POINT-URL>/api/v1/files/ |
Field Name | Field Description | Mandatory/ Read Only | Field Type |
name | Filename to scan | Mandatory | String |
data | File data | Mandatory* | String |
path | Path to the file in storage | Mandatory* | String |
download_link | May be passed instead of [data/path]. Must contain a direct download link. | Optional | String |
storage | The storage that path reads from (default is our internal S3) | Optional | String |
file_password | The file password | Optional | String |
callback_url | The URL the system will send its response to | Optional | String |
callback_params | Additional params to be sent to the callback_url | Optional | JSON |
callback_headers | Headers for the callback_url | Optional | JSON |
*only one is required
The response will be the scan ID, for Example:
{"scan_id": 123456} |
If you supply a `callback_params`, then it will be included in the response under `callback_params`. For example:
{“scan_id”: 123456, “callback_params”: {“key1”: “val1”, “key2”:”value2”}} |
Examples
Request to scan a file in the default storage called sample.doc, with no callback to send the response to.
response = requests.post(“https://<PERCEPTION-POINT-URL>/api/v1/files/”, ) print response {"scan_id": 123456} |
Request to scan a file from my file system located at /tmp, the file will be called ‘my_file.doc’, the response of the scan will be sent to "https://my-api.com/callback ",
with {“Auth”: “<TOKEN_VALUE>”} as a header.
file = open(‘/tmp/example.pdf’, ‘rb’) files={"data": file} “callback_headers”:{ “Auth”: “<TOKEN_VALUE>”}, ) print response {"scan_id": 123456} |
URL API
POST https://<PERCEPTION-POINT-URL>/api/v1/urls/ |
Field Name | Field Description | Mandatory/ Read Only | Field Type |
path | The URL to be inspected | Mandatory | String |
user_agent_string | A User Agent string the URL will be scanned with | Optional | String |
user_location | The user location (USA, Europe, etc) | Optional | String |
callback_url | The URL the system will send its response to | Optional | String |
callback_params | Additional params to be sent to the callback_url | Optional | JSON |
callback_headers | Headers for the callback_url | Optional | JSON |
The response will be the scan ID, for Example:
{"scan_id": 123456} |
If you supply a `callback_params`, then it will be included in the response under `callback_params`. For example:
{“scan_id”: 123456, “callback_params”: {“key1”: “val1”, “key2”:”value2”}} |
Examples
Request to scan a URL, with no callback to send the response to.
response = requests.post(“https://<PERCEPTION-POINT-URL>/api/v1/urls/”, ) print response {"scan_id": 123456} |
Request to scan “http://images.google.com ”, the response of the scan will be sent to "https://my-api.com/callback ",
with {“Auth”: “<TOKEN_VALUE>”} as a header.
response = requests.post(“https://<PERCEPTION-POINT-URL>/api/v1/urls/”, “Callback_headers”: json.dumps({ ) print response {"scan_id": 123456} |
Callback API
The API should be at the URL provided by the callback_url field from the File or URL API’s
The API sends a POST request with the following structure:
The request HEADERS receive its value from callback_headers supplied in the File or URL API’s. In JSON format: {<KEY>: <VALUE>}
The API body will contain the following fields in JSON format:
Field Name | Field Description |
scan_id | The id of the scan in the system |
name | The name of the file / path of the URL |
type | ‘File’ or ‘URL’ accordingly |
path | The path to the file in the system’s storage, |
verdict | The verdict of the scan:
|
evidence | A list of evidence found for the verdict |
params | Additional params to be sent to the callback URL received from callback_params from the file or URL API |
Examples:
The response from the callback will be:
{ "verdict": "MAL", "scan_id": "123456", "name": "FILE.pdf", "evidence": "["{ "Data": { "Name": "cfg_trigger", "Description": "" "module_name": "DeviceHarddiskVolume1Program FilesAdobeAcrobat Reader DCReaderAXE8SharedExpat.dll", "module_md5": "000000b5bf63c7d1925599218c6a2a7b", "os_and_software": "Win7x86|Acrobat Reader 15" }, }", "{ "Data": { "module_name": "DeviceHarddiskVolume1Program FilesAdobeAcrobat Reader DCReaderAXE8SharedExpat.dll", "module_md5": "000000b5bf63c7d1925599218c6a2a7b", "os_and_software": "Win7x86|Acrobat Reader 15" }, "Name": "cfg_trigger", "Description": null }"]", "params": "{}", "path": "https://FILE_PATH_IN_SERVER.pdf", "type": "File" } |
API Response Codes
Response Code | Response Body | Response Meaning |
200 | {"scan_id": 123456} | The file or URL were received, the corresponding scan id is in the body |
403 | User not authenticated, probably a token issue | |
50x | Internal server error |
GET https://api.perception-point.io/api/v1/scans/list/<scan_id>/ |
Examples:
The response will be a list of scans:
response = requests.get(“https://<PERCEPTION-POINT-URL>/api/scans/177”, print response { "id": 177, "organization": 1, "parent_organization_name": null, "created_at": "2019-05-28T13:03:50.223119", "finished_at": "2019-05-28T13:04:24.444439", "start_scanning_at": "2019-05-28T13:03:52.347372", "self_finished_at": "2019-05-28T13:04:10.423116", "children_finished_at": "2019-05-28T13:04:24.435917", "verdict": "CLN", "sub_verdict": "CLN", "status": "CMP", "verbose_status": "CMP", "verbose_action": null, "verbose_verdict": "CLN", "verbose_confidence": "HIGH", "origin": "analyze", "verbose_origin": "analyze", "content_type": 31, "object_id": 108, "scan_traces": [], "joesandbox_report": null, "static_signatures": [], "sample_type_str": "url", "sample_title": "http://www.ynet.co.il ", "sample": { "id": 108, "path": "http://www.ynet.co.il ", "scan_id": 177, "md5": "934b64e940a3e8c21ad739fdd28beed5", "sha1": "d47ff1928f0ca4b7be2dc23f439dfa8237412281", "sha256": "20d82f0d02ce46009ac5c6fbfbd4a78932613127a7e0268bcf63e8397e80e905", "sha512": "00c8ada9fb63a091316bcfd045d04eec586d6ab88a1b96365e58a34a2e019173880e7821c94c16cda63d6f375401c7f6102e65c7e67dffaf06d516097ba2bd0c", "status_code": 200, "is_redirect": false, "user_agent_string": "", "click_count": 0, "content_type": "text/html", "origin": "analyze", "domain": "http://www.ynet.co.il " }, "payload_type": null, "sample_file_type": "url", "parent_scan_id": null, "original_scan_id": null, "found_in_cache": false, "children": [ { "verbose_verdict": "CLN", "verbose_status": "CMP", "id": 178, "sample_title": "https://www.ynet.co.il/home/0,7340,L-8,00.html ", "created_at": "2019-05-28T13:04:09.090512", "sample_type_str": "url", "sample_file_type": "url", "sample_from": null, "sample_to": null, "payload_type": null, "organization_id": 1, "origin": "analyze", "verbose_origin": "analyze", "children": [], "has_mal_children": false, "highlighted": false } ], "has_warnings": false, "children_warning_types_json": [], "is_fp": false, "is_fn": false, "has_mal_children": false, "confidence": 0, "user_full_name": "<ADDRESS@perception-point.io>", "summaries": [], "images": [], "highlighted": false, "organization_id": 1, "sample_to": null, "sample_from": "<ADDRESS@perception-point.io>", "sample_from_type": null, "sample_to_type": null, "scan_failures": [], "siblings": [ { "sample_sha256": "020a96f144d569cb92d4aeeb71fc32a23a6df25b034269f7d1334c42881c1c84", "id": 178, "sample_title": "https://www.ynet.co.il/home/0,7340,L-8,00.html " } ], "is_root_scan": true, "evidence": [], "root_evidence": [], "is_ready_to_viewer": true, "uploaded_to_elastic": true } |
API Response Codes
Response Code | Response Body | Response Meaning |
200 | In example | Response will contain requested result |
403 | User not authenticated, probably a token issue | |
404 | Will be returned in one of the following cases:
| |
50x | Internal server error |
Change scan verdict:
In order to change the scan verdict we’ll send a PUT request with the new verdict and a comment
Usage (request body)
Field Name | Field Description | Mandatory/ Read Only | Field Type |
comment | A comment describing reason for changing verdict | Optional | String |
sub_verdict | The new verdict Can be one of CLN, LSP, BLK, SUS, SPM, MAL Verdict code verdict CLN Clean LSP Likely spam BLK Blocked SUS Suspicious SPM Spam MAL Malicious | Required | String |
Example:
PUT https://<PERCEPTION-POINT-URL>/api/v1/scans/handle_scan/<SCAN_ID>/ |
The request body:
PUT /api/v1/scans/handle_scan/<SCAN_ID> { "comment": "I saw him going into a vent", "sub_verdict":"SUS" } |
API Response Codes
Response Code | Response Meaning |
200 | Verdict changed |
400 | The current sub verdict is the same as the new one requested |
Release email:
In order to release email we’ll send GET request to the release from quarantine endpoint
Usage (query params)
Field Name | Field Description | Mandatory/ Read Only | Field Type |
should_mark_as_clean | Set to false if you want to release a mail without marking the scan as clean | Optional (default is true) | Bollean |
Example:
GET https://<PERCEPTION-POINT-URL>/api/v1/quarantine/release/<SCAN_ID>/ |
API Response Codes
Response Code | Response Meaning |
200 | Email released |
400 | Bad scan id or bad input for should_mark_as_clean parameter |
Blacklist / Whitelist API
The blacklist / whitelist API will allow being configured as the following:
Sender Email Address Blacklist / Whitelist.
Sender IP Blacklist / Whitelist.
URL Blacklist / Whitelist.
You are allowed to do the following actions:
Retrieve a single entry.
Retrieve all entries.
Create a new entry.
Modify an existing entry.
Delete an existing entry.
Usage
All the lists are sharing a wide of common attributes. Here is a list of the common attributes:
Attribute | Acceptable format | Description | Read Only |
id | Integer | Entry ID | Yes |
created_by | username <email> | The user who created the entry | Yes |
last_updated_by | username <email> | The user who last modified the entry | Yes |
owner_organization | Foreign Key as Integer | The organization to apply rule on. If not given they the user organization is set. | No |
Possible assignments:
<list_type> might be: blacklist, whitelist
<list_target> might be: email, ip, url
Retrieve a single entry:
In order to retrieve a single entry, we’ll send a GET request specifying the entry id:
GET /api/v1/<list_type>/<list_target>/<entry_id> |
Example:
GET /api/v1/blacklist/url/2/ { "id": 2, "comment": "this is an example and I modified it\r\n!", "created_by": "Nimrod Wagner <nimrod.wagner@perception-point.io>", "last_updated_by": "Nimrod Wagner <nimrod.wagner@perception-point.io>", "owner_organization": 1, "prefix": "example.com" } |
List the entries:
In order to get a list of all items, we’ll send a GET request:
GET /api/v1/<list_type>/<list_target>/ |
Example:
GET /api/v1/blacklist/url/ { "count": 1, "next": null, "previous": null, "results": [ { "id": 1, "comment": "hello world!", "created_by": "Nimrod Wagner <nimrod.wagner@perception-point.io>", "last_updated_by": "Nimrod Wagner <nimrod.wagner@perception-point.io>", "owner_organization": 1, "prefix": "http://hello-world.com " } ] } |
Create a new entry:
In order to create a new entry, we’ll send a POST request:
POST /api/v1/<list_type>/<list_target>/ |
Please see additional data payload in the relevant section.
The successful response will contain your new entry.
Example:
POST /api/v1/blacklist/url/ { "id": 2, "comment": "this is an example!", "created_by": "Nimrod Wagner <nimrod.wagner@perception-point.io>", "last_updated_by": "Nimrod Wagner <nimrod.wagner@perception-point.io>", "owner_organization": 1, "prefix": "example.com" } |
Modify an existing entry:
In order to modify an entry, we’ll send a PUT request with a payload of the new data:
Example:
PUT /api/v1/<list_type>/<list_target>/<entry_id> |
The response will contain the updated entry.
PUT /api/v1/blacklist/url/2/ { "id": 2, "comment": "this is an example and I modified it\r\n!", "created_by": "Nimrod Wagner <nimrod.wagner@perception-point.io>", "last_updated_by": "Nimrod Wagner <nimrod.wagner@perception-point.io>", "owner_organization": 1, "prefix": "example.com" } |
Delete an existing entry:
In order to delete an entry, we’ll send a simple DELETE request specifying the entry id
DELETE /api/v1/<list_type>/<list_target>/<entry_id> |
Example:
DELETE /api/v1/blacklist/url/2/ |
Additional attributes:
BlackList / Whitelist Email Address
Attribute | Acceptable format | Description | Read Only |
address | Email address format | Email address | No |
BlackList / Whitelist IP Address
Attribute | Acceptable format | Description | Read Only |
ip | IPv4 IP Address | IP Address | No |
BlackList URL Address
Attribute | Acceptable format | Description | Read Only |
prefix | IPv4 IP Address | IP Address | No |
WhiteList URL Address
Attribute | Acceptable format | Description | Read Only |
prefix | IPv4 IP Address | IP Address | No |
exact | Boolean (true/ false) | Exact match or not | No |
Completed Jobs Report API
The Completed Jobs Report API is made to allow easy access to summaries of jobs that have been completed.
In the API you will be able to:
List all of your completed jobs, sorted by completion timestamp.
Get a summary (report) for each completed job.
Usage - Completed Job List
To get a completed job list, query the following URL:
GET /api/v1/scans/completed-jobs/ |
Possible GET query params
Param | Format | Description | Optional |
from | 10-digit epoch timestamp | Limits the results where timestamp >= from | YES |
to | 10-digit epoch timestamp | Limits the results where timestamp <= to | YES |
Response pattern
{ "count": <total_queryset_count>, "page_result_count": <page_result_count>, "next": <next_page_link> or null, "results": [ { "verbose_verdict": <CLN|SPM|MAL|BLK>, "created_on_elastic_at": <ISO6081 timestamp>, "id": <Scan ID>, }, … (more <page_result_count> entries>) ] } |
Param | Format | Description |
from | 10-digit epoch timestamp | Limits the results where timestamp >= from |
to | 10-digit epoch timestamp | Limits the results where timestamp <= to |
For Example:
{ "count": 2, "page_result_count": 2, "next": null, "results": [ { "verbose_verdict": "CLN", "created_on_elastic_at": "2019-08-18T11:59:31.120259", "id": 502, "_index": "scans.2019-08.write" }, { "verbose_verdict": "CLN", "created_on_elastic_at": "2019-08-18T11:57:42.456463", "id": 501, "_index": "scans.2019-08.write" } ] } |
Example using the from and to params
GET /api/v1/scans/completed-jobs/?from=1566129480 |
{ "count": 1, "page_result_count": 1, "next": null, "results": [ { "verbose_verdict": "CLN", "created_on_elastic_at": "2019-08-18T11:59:31.120259", "id": 502, "_index": "scans.2019-08.write" } ] } |
The reason is that 1566129480 resolves into August 18, 2019 11:58:00 AM.
You can supply to, from or both params.
Usage - Report Completed Job
To get a detailed job report, query the following URL:
GET /api/v1/scans/report/<scan_id> |
Where scan_id is an id from the above list.
Response Pattern
{ "scan_id": <scan_id>, "timestamp": <completed-job-finish-time>, "name": <file-name-or-url-path>, "type": <”file”|”url”>, "verdict": <"CLN"|”SPM”|”BLK”|”MAL”|”SUS”>, "scan_engines": [<scan engines array>], "scan_layers": [<scan layers array>], "scan_tree": [<child report array>], "evidence": [<evidence array>], "decisions": [<decisions array>], "params": <all given query params as a json> } |
Field | Description |
scan_id | The scan ID queried upon for this response |
timestamp | The time that the analysis was completed by the system |
type | The type of object |
verdict |
|
evidence | Describe breadcrumbs or evidence that were collected during the analysis |
decisions | Represents the decisions that were applied upon the evidence in order to convict the inspected artifact |
scan engines | Describes the engines that triggered during the inspection (and created matching evidence) |
scan layers | Describes the logical layers of the product in which the engines are associated with |
scan tree | Contains children scan IDs that are associated with this scan |
For Example:
GET /api/v1/scans/report/502 |
{ "scan_id": 502, "timestamp": "2019-08-18T11:59:31.120259", "name": "example.docx", "type": "file", "verdict": "CLN", "evidence": [], "params": {} } |
Health Check
You can check the availability of the services by querying the Health Check API
GET /v1/health_check |
You’ll get the following response:
{ "hap”: <”on”|”off”>, “static”: <”on”|”off”>, “status”: <”on”|”off”> } |
Request Investigation
You can request an investigation for a scan.
GET /api/v1/scans/request-investigation/<scan_id>/ |
Possible GET query params
Param | Format | Description | Optional |
option | Text |
| MANDATORY |
comment | Text | An additional comment. | OPTIONAL |
The response will be a blank 200 OK on success;
Or any other appropriate response if an error occurred.
Delete scan:
In order to delete a scan we’ll send a PUT/POST request with the scan id
Example:
PUT https://<PERCEPTION-POINT-URL>/api/v1/scans/delete_scan/<SCAN_ID>/ |
POST https://<PERCEPTION-POINT-URL>/api/v1/scans/delete_scan/<SCAN_ID>/ |
API Response Codes
Response Code | Response Meaning |
204 | Scan deleted |
Scan Search API:
Perception Point exposes an advanced scan search API.
API Endpoint:
GET https://<PERCEPTION-POINT-URL>/api/v1/scans/list/ |
API parameters can have multiple values. In order to use multiple values, append [] to the end of the parameter name. OR condition is applied between options of the same field.
AND condition is applied between fields.
Example
GET https://<PERCEPTION-POINT-URL>/api/v1/scans/list/?channel=email GET https://<PERCEPTION-POINT-URL>/api/v1/scans/list/?channel[]=email,api |
Accepted Parameters:
Param | Description |
start | Lower bound for scan creation time (Inclusive). 10-digit timestamp |
end | Upper bound for scan creation time (Inclusive). 10-digit timestamp |
organization_id | Filters sub-organization id only |
channel | Any of the following: email, internalemail, onedrivebiz, analyze, s3, dropbox, box, gdrive,api, teams, sharepoint, salesforce, browser |
belongs_to_vip | Search for vIP users incidents |
verbose_verdict | Any of the following:
|
handle_status | IR Handling status |
search_descendants.subject | Subject |
search_descendants.original_message_id | Message ID |
verbose_action | One of the following: indelivery, delivered, quarantine, scanned, delivery_error |
sample_from | Sender Address |
search_descendants.sender_domain | Sender Domain |
search_descendants.source_ip | Sender IP |
search_descendants.reply_to | Reply-To Address |
search_descendants.source | Return-Path |
receiver_address | Receiver Address |
sample.to_users.un_region | Region |
sample.to_users.country | Country |
search_descendants.receiver_domain | Receiver Domain |
search_descendants.original_file_path | folder |
search_descendants.envelope_to | Envelope-To |
max_group_size | Min Campaign Size |
search_descendants.original_file_name | File Name |
search_descendants.original_type | File Type |
search_descendants.sample_sha256 | File / URL Sha256 hash |
search_descendants.mime_type | File Mime Type |
search_descendants.path | URL path |
search_descendants.domain | Domain |
search_descendants.url_title | Webpage title |
search_descendants.url_description | URL Description |
evidence.data.brand | Brand Name |
Examples
Get all scans from 01.07.2021:00:00:00 Until 08.07.2021:03:00:00
GET https://<PERCEPTION-POINT-URL>/api/v1/scans/list/?start=1625097600&end=1625713200 |
Get all scans from analyze and api channel:
GET https://<PERCEPTION-POINT-URL>/api/v1/scans/list/?channel[]=email,api |
Get all highlighted clean scans from email or api channels:
GET https://<PERCEPTION-POINT-URL>/api/v1/scans/list/?channel[]=email,api&is_highlighted=true&verbose_verdict=CLN |
Add organization API
POST https://<PERCEPTION-POINT-URL>/api/organizations/ |
Field Name | Field Description | Mandatory/ Default | Field type |
name | Name of the organization you are creating | ✓ | String |
active | whether organization is active or not | ✓ | Boolean |
number_of_seats | Number of email addresses in the organization you are creating | ✓ | Number |
origins | The different services will be monitored for the new organization. Can be any one of the following: office365, gmail, onedrivebiz, sharepoint, gdrive, dropbox, salesforce, s3, teams | [] | List |
email_report_recipients | Email address to receive reports | null | String |
send_malicious_emails | Enable/disable blocking mode for malicious emails | True | Boolean |
send_spam_emails | Enable/disable blocking mode for spam emails | True | Boolean |
send_blocked_emails | Enable/disable blocking mode for blocked emails | True | Boolean |
email_weekly_report | Send weekly reports | True | Boolean |
email_monthly_report | Send monthly reports | True | Boolean |
email_domains_report | Send domain reports | False | Boolean |
email_end_user_on_malicious_alert | Send email to End user when malicious email was blocked | False | Boolean |
client_alert_malicious_to_admin_email | Send an alert to admin when malicious email was detected | False | Boolean |
Response
{ “id”: <created-organization-id> } |
Was this article helpful?
That’s Great!
Thank you for your feedback
Sorry! We couldn't be helpful
Thank you for your feedback
Feedback sent
We appreciate your effort and will try to fix the article