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
The submission request object containing assets and optional organization targeting. Show AssetSubmitInput Properties
Array of asset strings to submit (maximum 100 per request). Supports domains, URLs, blockchain addresses, and social media profiles.
Optional organization slug for targeted classification. When provided, assets are classified specifically for that organization and may receive immediate scanning.
Returns
Array of submitted asset details with ChainPatrol IDs and scan information. Show Submitted Asset Object
The original asset content that was submitted
ChainPatrol’s internal ID for the asset (used for tracking and future references)
ID of the security scan (only present if scan was immediately created, more common when organizationSlug is provided)
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
With Organization Slug Without Organization Slug 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
Basic Submission
Organization-Specific
Example Response
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
// Express.js webhook handler
app . post ( "/security-alert" , async ( req , res ) => {
const { threats } = req . body ;
try {
await client . asset . submit ({
assets: threats ,
organizationSlug: "webhook-alerts" ,
});
res . json ({ status: "submitted" });
} catch ( error ) {
res . status ( 500 ). json ({ error: error . message });
}
});
import cron from "node-cron" ;
// Daily threat feed processing
cron . schedule ( "0 2 * * *" , async () => {
console . log ( "Processing daily threat feeds..." );
const threatFeeds = await fetchThreatFeeds ();
await processThreatFeed ( threatFeeds );
console . log ( "Daily processing complete" );
});
Real-time Stream Processing
// Process incoming threat stream
async function processThreatsStream ( stream : AsyncIterable < string []>) {
for await ( const batch of stream ) {
try {
const result = await client . asset . submit ({
assets: batch ,
organizationSlug: "stream-processor" ,
});
console . log ( `Processed batch: ${ result . submittedAssets . length } assets` );
} catch ( error ) {
console . error ( "Batch processing failed:" , error );
}
}
}
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