Skip to main content
POST
/
detection
/
list
List threat detection results for organization
curl --request POST \
  --url https://app.chainpatrol.io/api/v2/detection/list \
  --header 'Content-Type: application/json' \
  --header 'X-API-KEY: <api-key>' \
  --data '
{
  "slug": "<string>",
  "cursor": 123,
  "limit": 50,
  "filters": [],
  "query": "",
  "startDate": "<string>",
  "endDate": "<string>"
}
'
import requests

url = "https://app.chainpatrol.io/api/v2/detection/list"

payload = {
    "slug": "<string>",
    "cursor": 123,
    "limit": 50,
    "filters": [],
    "query": "",
    "startDate": "<string>",
    "endDate": "<string>"
}
headers = {
    "X-API-KEY": "<api-key>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.text)
const options = {
  method: 'POST',
  headers: {'X-API-KEY': '<api-key>', 'Content-Type': 'application/json'},
  body: JSON.stringify({
    slug: '<string>',
    cursor: 123,
    limit: 50,
    filters: [],
    query: '',
    startDate: '<string>',
    endDate: '<string>'
  })
};

fetch('https://app.chainpatrol.io/api/v2/detection/list', options)
  .then(res => res.json())
  .then(res => console.log(res))
  .catch(err => console.error(err));
<?php

$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => "https://app.chainpatrol.io/api/v2/detection/list",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => json_encode([
    'slug' => '<string>',
    'cursor' => 123,
    'limit' => 50,
    'filters' => [
        
    ],
    'query' => '',
    'startDate' => '<string>',
    'endDate' => '<string>'
  ]),
  CURLOPT_HTTPHEADER => [
    "Content-Type: application/json",
    "X-API-KEY: <api-key>"
  ],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://app.chainpatrol.io/api/v2/detection/list"

	payload := strings.NewReader("{\n  \"slug\": \"<string>\",\n  \"cursor\": 123,\n  \"limit\": 50,\n  \"filters\": [],\n  \"query\": \"\",\n  \"startDate\": \"<string>\",\n  \"endDate\": \"<string>\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("X-API-KEY", "<api-key>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(string(body))

}
HttpResponse<String> response = Unirest.post("https://app.chainpatrol.io/api/v2/detection/list")
  .header("X-API-KEY", "<api-key>")
  .header("Content-Type", "application/json")
  .body("{\n  \"slug\": \"<string>\",\n  \"cursor\": 123,\n  \"limit\": 50,\n  \"filters\": [],\n  \"query\": \"\",\n  \"startDate\": \"<string>\",\n  \"endDate\": \"<string>\"\n}")
  .asString();
require 'uri'
require 'net/http'

url = URI("https://app.chainpatrol.io/api/v2/detection/list")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["X-API-KEY"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"slug\": \"<string>\",\n  \"cursor\": 123,\n  \"limit\": 50,\n  \"filters\": [],\n  \"query\": \"\",\n  \"startDate\": \"<string>\",\n  \"endDate\": \"<string>\"\n}"

response = http.request(request)
puts response.read_body
{
  "detections": [
    {
      "id": 123,
      "threatContent": "<string>",
      "createdAt": "<string>",
      "asset": {
        "id": 123,
        "content": "<string>"
      }
    }
  ],
  "nextCursor": 123
}
{
  "code": "BAD_REQUEST",
  "message": "Invalid input data",
  "issues": []
}
{
  "code": "UNAUTHORIZED",
  "message": "Authorization not provided",
  "issues": []
}
{
  "code": "FORBIDDEN",
  "message": "Insufficient access",
  "issues": []
}
{
  "code": "INTERNAL_SERVER_ERROR",
  "message": "Internal server error",
  "issues": []
}

Quick Start

Authentication

Include your API key in the X-API-KEY header:
X-API-KEY: <api-key>

Example Request

curl --request POST \
  --url https://api.chainpatrol.io/detection/list \
  --header 'Content-Type: application/json' \
  --header 'X-API-KEY: <api-key>' \
  --data '{
    "slug": "your-org",
    "limit": 50,
    "query": "phishing",
    "filters": [
      {
        "property": "source",
        "operator": "in",
        "value": ["EXTERNAL", "GOOGLE_SEARCH"]
      },
      {
        "property": "assetStatus",
        "operator": "in",
        "value": ["BLOCKED"]
      },
      {
        "property": "confidence",
        "operator": "in",
        "value": ["high", "medium"]
      }
    ]
  }'

Request Schema

Request Body

FieldTypeRequiredDefaultConstraintsDescription
slugstring✅ Yes--Organization slug identifier
cursornumber❌ No--Pagination cursor from previous response
limitnumber❌ No50Min: 1, Max: 100Number of results to return
filtersFilter[]❌ No[]-Array of filter objects
querystring❌ No""-Search query for threat content (case-insensitive)
startDatestring❌ No-ISO 8601 formatStart date for filtering results
endDatestring❌ No-ISO 8601 formatEnd date for filtering results

Filter Schema

Each filter object must have the following structure:
FieldTypeRequiredDescription
propertystring✅ YesFilter property (see options below)
operatorstring✅ Yes"in" or "notIn"
valuestring[]✅ YesArray of values to filter by

Filter Properties

1. Source Filter ("source")
{
  "property": "source",
  "operator": "in" | "notIn",
  "value": ThreatDetectionSourceKey[]
}
  • "ASSET_CHECK" - Asset verification checks
  • "BING_SEARCH" - Bing search results
  • "CERTSTREAM" - Certificate transparency logs
  • "DNS_TWIST" - DNS twist detection
  • "DUCK_DUCK_GO_SEARCH" - DuckDuckGo search results
  • "EXTERNAL" - External threat submissions
  • "GOOGLE_SEARCH" - Google search results
  • "GUESTBOOK" - Guestbook submissions
  • "MEDIUM_TAG_RSS" - Medium RSS feeds
  • "MOZILLA_ADDON_SEARCH" - Mozilla addon searches
  • "REDDIT_SUBREDDIT_SEARCH" - Reddit subreddit searches
  • "TWITTER" - Twitter monitoring
  • "TWITTER_POST_SEARCH" - Twitter post searches
  • "TWITTER_SEARCH" - Twitter search results
  • "URLSCAN" - URLScan.io results
  • "YAHOO_SEARCH" - Yahoo search results
  • "YOUTUBE_SEARCH" - YouTube search results
2. Asset Status Filter ("assetStatus")
{
  "property": "assetStatus",
  "operator": "in" | "notIn",
  "value": AssetStatus[]
}
Available Asset Status Values:
  • "UNKNOWN" - Status not yet determined
  • "ALLOWED" - Asset is legitimate/allowed
  • "BLOCKED" - Asset is blocked/malicious
3. Confidence Filter ("confidence")
{
  "property": "confidence",
  "operator": "in" | "notIn",
  "value": ConfidenceLevel[]
}
Available Confidence Level Values:
  • "none" - No confidence threshold met
  • "low" - Low confidence threat detection
  • "medium" - Medium confidence threat detection
  • "high" - High confidence threat detection
4. Asset Type Filter ("assetType")
{
  "property": "assetType",
  "operator": "in" | "notIn",
  "value": AssetType[]
}
  • "URL" - Website URLs
  • "PAGE" - Web pages
  • "ADDRESS" - Blockchain addresses
  • "TWITTER" - Twitter profiles/posts
  • "FACEBOOK" - Facebook profiles/pages
  • "YOUTUBE" - YouTube channels/videos
  • "REDDIT" - Reddit posts/subreddits
  • "TELEGRAM" - Telegram channels/groups
  • "DISCORD" - Discord servers (deprecated)
  • "DISCORD_USER" - Discord users
  • "LINKEDIN" - LinkedIn profiles
  • "INSTAGRAM" - Instagram profiles
  • "THREADS" - Threads profiles
  • "TIKTOK" - TikTok profiles
  • "MEDIUM" - Medium articles/profiles
  • "EMAIL" - Email addresses
  • "WHATSAPP" - WhatsApp contacts
  • "GOOGLE_APP_STORE" - Google Play Store apps
  • "APPLE_APP_STORE" - Apple App Store apps
  • "AMAZON_APP_STORE" - Amazon App Store apps
  • "MICROSOFT_APP_STORE" - Microsoft Store apps
  • "CHROME_WEB_STORE" - Chrome extensions
  • "MOZILLA_ADDONS" - Firefox addons
  • "OPERA_ADDONS" - Opera addons
  • "PATREON" - Patreon profiles
  • "OPENSEA" - OpenSea collections/profiles
  • "FARCASTER" - Farcaster profiles
  • "IPFS" - IPFS hashes
  • "GOOGLE_FORM" - Google Forms
  • "QUORA" - Quora profiles/posts
  • "GITHUB" - GitHub repositories/profiles
  • "TEACHABLE" - Teachable courses
  • "SUBSTACK" - Substack publications
  • "DEBANK" - DeBank profiles
  • "TAWK_TO" - Tawk.to chat widgets
  • "JOTFORM" - JotForm forms
  • "PRIMAL" - Primal profiles
  • "BLUESKY" - Bluesky profiles
  • "SNAPCHAT" - Snapchat profiles
  • "DESO" - DeSo profiles

Response Schema

Response Body

{
  detections: DetectionResult[];
  nextCursor: number | null;
}

Detection Result Object

Each item in the detections array has the following structure:
FieldTypeDescription
idnumberUnique threat detection result identifier
threatContentstringContent that was detected as threatening
sourcestringSource of the threat detection (ThreatDetectionSourceKey)
createdAtstringISO 8601 timestamp of when threat was detected
confidencestringConfidence level: “none”, “low”, “medium”, or “high”
reportStatusstringReport status: “REPORTED” or “NOT_REPORTED”
assetAssetObjectAssociated asset information

Asset Object

FieldTypeDescription
idnumberUnique asset identifier
contentstringAsset content (URL, address, username, etc.)
typestringAsset type (AssetType enum value)
statusstringCurrent asset status (AssetStatus enum value)

Complete Response Example

{
  "detections": [
    {
      "id": 12345,
      "threatContent": "Phishing site detected mimicking legitimate service",
      "source": "GOOGLE_SEARCH",
      "createdAt": "2024-01-15T10:30:00Z",
      "confidence": "high",
      "reportStatus": "REPORTED",
      "asset": {
        "id": 67890,
        "content": "https://fake-site.com",
        "type": "URL",
        "status": "BLOCKED"
      }
    },
    {
      "id": 12346,
      "threatContent": "Suspicious crypto address found in scam report",
      "source": "EXTERNAL",
      "createdAt": "2024-01-15T09:15:00Z",
      "confidence": "medium",
      "reportStatus": "NOT_REPORTED",
      "asset": {
        "id": 67891,
        "content": "0x1234567890123456789012345678901234567890",
        "type": "ADDRESS",
        "status": "BLOCKED"
      }
    }
  ],
  "nextCursor": 12347
}

Access Control

The API enforces strict access control based on your API key:
  1. Organization API Keys:
    • Can only access detection results for their associated organization
    • Must match the slug parameter exactly
    • Example: An API key for “acme-org” can only query results for “acme-org”
  2. User API Keys:
    • Can access detection results for any organization where the user is a member
    • Requires the user to be an active member of the queried organization
If you attempt to query an organization without proper permissions, you will receive a 403 Forbidden error with the message: “API key does not have access to this organization”

Example Implementation

async function fetchDetectionResults(params) {
  const response = await fetch("https://api.chainpatrol.io/detection/list", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-API-KEY": "<api-key>",
    },
    body: JSON.stringify(params),
  });
  return response.json();
}

// Example usage
fetchDetectionResults({
  slug: "your-org",
  limit: 50,
  query: "phishing",
  filters: [
    {
      property: "assetStatus",
      operator: "in",
      value: ["BLOCKED"],
    },
    {
      property: "assetType",
      operator: "in",
      value: ["URL", "ADDRESS"],
    },
  ],
  startDate: "2024-01-01T00:00:00Z",
  endDate: "2024-03-01T00:00:00Z",
})
  .then((data) => {
    console.log("Detection results:", data.detections);
    console.log("Next cursor:", data.nextCursor);
  })
  .catch((error) => console.error("Error fetching results:", error));
interface DetectionFilter {
  property: "source" | "assetStatus" | "assetType" | "confidence";
  operator: "in" | "notIn";
  value: string[];
}

interface DetectionListParams {
  slug: string;
  cursor?: number;
  limit?: number;
  filters?: DetectionFilter[];
  query?: string;
  startDate?: string;
  endDate?: string;
}

interface AssetObject {
  id: number;
  content: string;
  type: string;
  status: string;
}

interface DetectionResult {
  id: number;
  threatContent: string;
  source: string;
  createdAt: string;
  confidence: "none" | "low" | "medium" | "high";
  reportStatus: "REPORTED" | "NOT_REPORTED";
  asset: AssetObject;
}

interface DetectionListResponse {
  detections: DetectionResult[];
  nextCursor: number | null;
}

async function fetchDetectionResults(
  params: DetectionListParams
): Promise<DetectionListResponse> {
  const response = await fetch("https://api.chainpatrol.io/detection/list", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-API-KEY": "<api-key>",
    },
    body: JSON.stringify(params),
  });
  return response.json();
}

// Example usage
fetchDetectionResults({
  slug: "your-org",
  limit: 50,
  filters: [
    {
      property: "source",
      operator: "in",
      value: ["GOOGLE_SEARCH", "EXTERNAL"],
    },
    {
      property: "assetStatus",
      operator: "in",
      value: ["BLOCKED"],
    },
  ],
})
  .then((data) => {
    console.log(`Found ${data.detections.length} detection results`);
    data.detections.forEach((item) => {
      console.log(`Threat: ${item.threatContent}`);
      console.log(`Asset: ${item.asset.content} (${item.asset.type})`);
      console.log(`Status: ${item.asset.status}`);
      console.log(`Confidence: ${item.confidence}`);
      console.log(`Report Status: ${item.reportStatus}`);
      console.log("---");
    });

    if (data.nextCursor) {
      console.log("More results available with cursor:", data.nextCursor);
    }
  })
  .catch((error) => console.error("Error fetching results:", error));

Authorizations

X-API-KEY
string
header
required

Your API key. This is required by most endpoints to access our API programatically. Reach out to us at support@chainpatrol.io to get an API key for your use.

Body

application/json
slug
string
required
cursor
number
limit
number
default:50
Required range: 1 <= x <= 100
filters
object[]
query
string
default:""
startDate
string
endDate
string

Response

Successful response

detections
object[]
required
nextCursor
number