The asset.submit method allows you to bulk submit assets (domains, URLs, social profiles, blockchain addresses) to ChainPatrol for automated threat classification and assignment to appropriate organizations.

API Reference

Method Signature

client.asset.submit(request: AssetSubmitInput): Promise<AssetSubmitOutput>

Parameters

request
AssetSubmitInput
required
The submission request object containing assets and optional organization targeting.

Returns

submittedAssets
array
required
Array of submitted asset details with ChainPatrol IDs and scan information.

Supported Asset Types

Domains & URLs

  • malicious-site.com
  • https://phishing-page.net/login
  • subdomain.suspicious-domain.org

Crypto Addresses

  • 0x1234...abcd (Ethereum) - bc1q... (Bitcoin) - cosmos1abc... (Cosmos)

Social Profiles

  • @scammer_account - https://twitter.com/fake_support - discord.gg/phishing_server

Other Assets

  • Email addresses
  • Phone numbers
  • Custom identifiers

Organization Behavior

When organizationSlug is provided: ✅ Assets are classified specifically for that organization ✅ Immediate scanning workflow is triggered ✅ scanId is more likely to be returned ✅ Results are optimized for the organization’s threat profile ✅ Faster processing and priority handling

Getting Started

Quick Start

import { ChainPatrolClient } from "@chainpatrol/sdk";

const client = new ChainPatrolClient({
apiKey: "cp_live_your_api_key_here",
});

const result = await client.asset.submit({
assets: [
"suspicious-domain.com",
"https://fake-site.net",
"0x1234567890abcdef1234567890abcdef12345678",
],
});

console.log(`Submitted ${result.submittedAssets.length} assets`);

Basic Usage Patterns

// Simple threat submission
async function submitThreats(assets: string[]) {
  const result = await client.asset.submit({ assets });

  console.log(`✅ Submitted ${result.submittedAssets.length} assets`);

  const withScans = result.submittedAssets.filter((a) => a.scanId);
  if (withScans.length > 0) {
    console.log(`🔬 ${withScans.length} assets have immediate scans`);
  }

  return result;
}

// Organization-specific submission
async function submitForOrganization(assets: string[], orgSlug: string) {
  return await client.asset.submit({
    assets,
    organizationSlug: orgSlug,
  });
}

Implementation Guide

Bulk Threat Intelligence Processing

async function processThreatFeed(threatFeed: string[]) {
  const chunkSize = 100; // API limit
  const results = [];

  for (let i = 0; i < threatFeed.length; i += chunkSize) {
    const chunk = threatFeed.slice(i, i + chunkSize);

    try {
      const result = await client.asset.submit({
        assets: chunk,
        organizationSlug: "security-team",
      });

      results.push(result);
      console.log(`Processed chunk ${Math.floor(i / chunkSize) + 1}`);

      // Rate limiting - wait between requests
      await new Promise((resolve) => setTimeout(resolve, 1000));
    } catch (error) {
      console.error(`Failed to process chunk starting at ${i}:`, error);
    }
  }

  return results;
}

Automated Security Monitor

import { ChainPatrolClient } from "@chainpatrol/sdk";

class SecurityMonitor {
  private client: ChainPatrolClient;

  constructor(apiKey: string) {
    this.client = new ChainPatrolClient({
      apiKey,
      fetchOptions: {
        headers: {
          "User-Agent": "SecurityMonitor/1.0",
        },
      },
    });
  }

  async submitNewThreats(assets: string[], source: string) {
    try {
      const result = await this.client.asset.submit({
        assets,
        organizationSlug: "internal-security",
      });

      // Log successful submission
      console.log(
        `[${source}] Submitted ${result.submittedAssets.length} assets`
      );

      // Track assets with immediate scans
      const withScans = result.submittedAssets.filter((a) => a.scanId);
      if (withScans.length > 0) {
        console.log(`${withScans.length} assets have immediate scans`);
      }

      return result;
    } catch (error) {
      console.error(`[${source}] Failed to submit assets:`, error);
      throw error;
    }
  }
}

Integration Examples

Technical Details

Rate Limits & Constraints

Important Limits - Max assets per request: 100 - Asset string length: 1-1000 characters - Recommended delay: 500-1000ms between requests - Daily limits: Contact support for high-volume usage plans
Performance Tips - Batch submissions for efficiency - Use organization slug for faster processing - Implement proper error handling and retries - Monitor API quotas and rate limits

Error Handling

import {
  ChainPatrolClientError,
  ChainPatrolClientErrorCodes,
} from "@chainpatrol/sdk";

async function safeAssetSubmit(assets: string[]) {
  try {
    return await client.asset.submit({ assets });
  } catch (error) {
    if (error instanceof ChainPatrolClientError) {
      switch (error.code) {
        case ChainPatrolClientErrorCodes.MISSING_API_KEY:
          console.error("API key is missing or invalid");
          break;
        case ChainPatrolClientErrorCodes.API_ERROR:
          console.error("API error:", error.message);
          break;
      }
    } else {
      console.error("Unexpected error:", error);
    }
    throw error;
  }
}

Testing

Use this pattern to test the asset submit functionality:
async function testAssetSubmit() {
  const timestamp = Date.now();
  const testAssets = [
    `https://test-${timestamp}-1.example.com`,
    `https://test-${timestamp}-2.example.org`,
  ];

  const result = await client.asset.submit({
    assets: testAssets,
    organizationSlug: "your-org-slug", // Optional
  });

  console.log("✅ Test successful:", result);
  return result;
}

Additional Documentation