Skip to main content
instantly-data-handling Implement Instantly.ai lead data management, GDPR/CAN-SPAM compliance, and list operations.
Use when handling lead imports, managing block lists, implementing unsubscribe flows,
or ensuring compliance with email regulations.
Trigger with phrases like "instantly leads", "instantly data", "instantly GDPR",
"instantly block list", "instantly lead management", "instantly unsubscribe".
Jump to install Skills Marketplace Discover and explore AI skills built by the community.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Copy promptShow prompt details A direct command skips the review prompt. Inspect the source before running it.
npx skills add https://github.com/jeremylongshore/claude-code-plugins-plus-skills --skill instantly-data-handlingThe command stays on one line. Scroll horizontally to inspect it before copying.
Prefer a local copy? Download the files currently available to SkillsMP.
Download Zip Downloading... More from this repository
Related occupations SOC
Based on SOC occupation classification
name instantly-data-handling description Implement Instantly.ai lead data management, GDPR/CAN-SPAM compliance, and list operations.
Use when handling lead imports, managing block lists, implementing unsubscribe flows,
or ensuring compliance with email regulations.
Trigger with phrases like "instantly leads", "instantly data", "instantly GDPR",
"instantly block list", "instantly lead management", "instantly unsubscribe".
allowed-tools Read, Write, Edit, Bash(npm:*), Bash(curl:*), Grep version 1.12.0 license MIT author Jeremy Longshore <jeremy@intentsolutions.io> tags ["saas","instantly","data-handling","gdpr","compliance","leads"] compatibility Designed for Claude Code, also compatible with Codex and OpenClaw
Instantly Data Handling
Overview
Manage leads, lead lists, block lists, and regulatory compliance in Instantly API v2. Covers lead CRUD operations, list management, bulk import patterns, unsubscribe handling, GDPR right-to-deletion, CAN-SPAM compliance, and block list automation. Cold email has specific legal requirements — this skill ensures your integrations are compliant.
Prerequisites
Completed instantly-install-auth setup
API key with leads:all scope
Understanding of CAN-SPAM / GDPR requirements for cold outreach
Instructions
Step 1: Lead List Management
import { InstantlyClient } from "./src/instantly/client" ;
const client = new InstantlyClient ();
async function createLeadList (name : string ) {
const list = await client.request <{ id : string ; name : string }>("/lead-lists" , {
method : "POST" ,
body : JSON .stringify ({
name,
has_enrichment_task : false ,
}),
});
console .log (`Created list: ${list.name} (${list.id} )` );
return list;
}
async function ( ) {
client. < <{
: ; : ; : ;
}>>( );
}
( ) {
client. ( , { : });
}
getLeadLists
return
request
Array
id
string
name
string
timestamp_created
string
"/lead-lists?limit=50"
async
function
deleteLeadList
listId : string
await
request
`/lead-lists/${listId} `
method
"DELETE"
Step 2: Lead Import with Validation interface LeadImport {
email : string ;
first_name ?: string ;
last_name ?: string ;
company_name ?: string ;
website ?: string ;
phone ?: string ;
custom_variables ?: Record <string , string >;
}
async function importLeads (
campaignId : string ,
leads : LeadImport [],
options = { skipDuplicates: true , verifyEmails: true }
) {
const results = { added : 0 , skipped : 0 , failed : 0 , errors : [] as string [] };
for (const lead of leads) {
try {
if (!lead.email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/ .test (lead.email )) {
results.failed ++;
results.errors .push (`Invalid email: ${lead.email} ` );
continue ;
}
const domain = lead.email .split ("@" )[1 ];
if (BLOCKED_PATTERNS .some ((p ) => domain.includes (p))) {
results.skipped ++;
continue ;
}
await client.request ("/leads" , {
method : "POST" ,
body : JSON .stringify ({
campaign : campaignId,
email : lead.email ,
first_name : lead.first_name ,
last_name : lead.last_name ,
company_name : lead.company_name ,
website : lead.website ,
phone : lead.phone ,
custom_variables : lead.custom_variables ,
skip_if_in_workspace : options.skipDuplicates ,
skip_if_in_campaign : true ,
verify_leads_on_import : options.verifyEmails ,
}),
});
results.added ++;
} catch (e : any ) {
results.failed ++;
results.errors .push (`${lead.email} : ${e.message} ` );
}
}
console .log (`Import: ${results.added} added, ${results.skipped} skipped, ${results.failed} failed` );
return results;
}
const BLOCKED_PATTERNS = [
"noreply" , "no-reply" , "donotreply" ,
"info@" , "admin@" , "support@" , "help@" , "abuse@" ,
"postmaster@" , "webmaster@" , "hostmaster@" ,
];
Step 3: Lead Operations (Move, Update, Delete)
async function moveLeads (opts : {
fromCampaign?: string ;
fromList?: string ;
toCampaign?: string ;
toList?: string ;
limit?: number ;
} ) {
return client.request ("/leads/move" , {
method : "POST" ,
body : JSON .stringify ({
in_campaign : opts.fromCampaign ,
in_list : opts.fromList ,
to_campaign_id : opts.toCampaign ,
to_list_id : opts.toList ,
limit : opts.limit || 1000 ,
check_duplicates : true ,
}),
});
}
async function updateLeadInterest (
email : string ,
campaignId : string ,
status : "interested" | "not_interested" | "meeting_booked" | "closed"
) {
const interestMap : Record <string , number > = {
interested : 1 ,
not_interested : -1 ,
meeting_booked : 2 ,
closed : 3 ,
};
await client.request ("/leads/update-interest-status" , {
method : "POST" ,
body : JSON .stringify ({
lead_email : email,
campaign_id : campaignId,
interest_value : interestMap[status],
}),
});
}
async function updateLead (leadId : string , data : Partial <LeadImport > ) {
await client.request (`/leads/${leadId} ` , {
method : "PATCH" ,
body : JSON .stringify (data),
});
}
async function deleteLeadsFromCampaign (campaignId : string , status ?: number ) {
await client.request ("/leads" , {
method : "DELETE" ,
body : JSON .stringify ({
campaign_id : campaignId,
status,
}),
});
}
Step 4: Block List Management
async function addToBlockList (entries : string [] ) {
for (const entry of entries) {
await client.request ("/block-lists-entries" , {
method : "POST" ,
body : JSON .stringify ({ bl_value : entry }),
});
}
await client.request ("/block-lists-entries/bulk-create" , {
method : "POST" ,
body : JSON .stringify ({ entries }),
});
}
async function seedBlockList ( ) {
const standardBlocks = [
"yourdomain.com" ,
"yourcompany.com" ,
"competitor1.com" ,
"competitor2.com" ,
"gmail.com" ,
"yahoo.com" ,
"hotmail.com" ,
"outlook.com" ,
"spamtrap.com" ,
];
await addToBlockList (standardBlocks);
console .log (`Seeded block list with ${standardBlocks.length} entries` );
}
async function auditBlockList ( ) {
const entries = await client.request <Array <{
id : string ; bl_value : string ;
}>>("/block-lists-entries?limit=100" );
console .log (`Block list: ${entries.length} entries` );
for (const e of entries) {
console .log (` ${e.bl_value} ` );
}
}
Step 5: GDPR / CAN-SPAM Compliance
async function handleDeletionRequest (email : string ) {
console .log (`Processing GDPR deletion request for: ${email} ` );
const campaigns = await client.request <Array <{ id : string }>>(
`/campaigns/search-by-contact?search=${encodeURIComponent (email)} `
);
for (const campaign of campaigns) {
const leads = await client.leads .list ({ campaign : campaign.id });
const matchingLead = leads.find ((l ) => l.email === email);
if (matchingLead) {
await client.leads .delete (matchingLead.id );
console .log (` Deleted from campaign ${campaign.id} ` );
}
}
await addToBlockList ([email]);
console .log (` Added to block list` );
console .log (` Deletion complete. Log this for GDPR records.` );
}
async function handleUnsubscribe (email : string ) {
await addToBlockList ([email]);
console .log (`Unsubscribe processed: ${email} added to global block list` );
}
async function verifyEmail (email : string ) {
await client.request ("/email-verification" , {
method : "POST" ,
body : JSON .stringify ({
email,
webhook_url : "https://api.yourapp.com/webhooks/verification" ,
}),
});
const result = await client.request <{
email : string ; status : string ; reason : string ;
}>(`/email-verification/${encodeURIComponent (email)} ` );
return result;
}
Key API Endpoints Method Path Purpose POST/leadsCreate lead POST/leads/listList/filter leads PATCH/leads/{id}Update lead DELETE/leads/{id}Delete single lead DELETE/leadsBulk delete leads POST/leads/moveMove leads between campaigns/lists POST/leads/update-interest-statusUpdate interest status POST/lead-listsCreate lead list GET/lead-listsList lead lists POST/block-lists-entriesAdd block list entry POST/block-lists-entries/bulk-createBulk add entries POST/email-verificationVerify email GET/campaigns/search-by-contactFind campaigns by lead
Error Handling Error Cause Solution 422 on lead createDuplicate in workspace Use skip_if_in_workspace: true Lead not found in campaign Already deleted or moved Search across campaigns first Block list full Too many entries Remove outdated entries periodically Email verification timeout External service delay Poll status endpoint
Resources
Next Steps For workspace access control, see instantly-enterprise-rbac.