Why Close CRM for Developer Leads?
Close CRM is built for inside sales teams that do high-velocity outreach. Its built-in email sequencing, calling, and SMS make it ideal for teams selling developer tools who want to run outbound directly from their CRM — no additional sales engagement tool required. Combined with GitHub signal data from GitLeads, Close becomes a developer-focused outreach engine where every new contact has a known intent signal attached.
Architecture: GitLeads to Close via Webhook
GitLeads fires a signed webhook for every new developer signal. Your webhook endpoint calls the Close REST API to create or update a lead and contact record. The signal context — which repo, which keyword, when — gets stored as a note on the Close lead.
# Flow overview
GitLeads signal fires
→ POST /webhook (your endpoint, HMAC verified)
→ Close API: POST /lead (create with embedded contact)
→ Close API: POST /activity/note (signal context)
→ [Optional] Close API: POST /sequence_subscriptionStep 1: Configure GitLeads Webhook
In GitLeads dashboard → Integrations → Webhooks, add your endpoint URL and copy the signing secret. GitLeads signs every payload with HMAC-SHA256 via the x-gitleads-signature header.
Step 2: Create the Webhook Receiver
import express from 'express';
import crypto from 'crypto';
const app = express();
app.use(express.json());
const GITLEADS_SECRET = process.env.GITLEADS_WEBHOOK_SECRET!;
const CLOSE_API_KEY = process.env.CLOSE_API_KEY!;
const CLOSE_BASE = 'https://api.close.com/api/v1';
function verifySignature(payload: string, signature: string): boolean {
const expected = crypto
.createHmac('sha256', GITLEADS_SECRET)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from('sha256=' + expected)
);
}
app.post('/gitleads/close', async (req, res) => {
const raw = JSON.stringify(req.body);
const sig = req.headers['x-gitleads-signature'] as string;
if (!verifySignature(raw, sig)) {
return res.status(401).json({ error: 'Invalid signature' });
}
await processLead(req.body);
res.json({ ok: true });
});Step 3: Create a Lead in Close
interface GitLeadsPayload {
signal_type: 'stargazer' | 'keyword';
repo?: string;
keyword?: string;
developer: {
github_username: string;
name: string;
email?: string;
company?: string;
bio?: string;
followers: number;
top_languages: string[];
};
}
async function processLead(payload: GitLeadsPayload) {
const dev = payload.developer;
const auth = Buffer.from(CLOSE_API_KEY + ':').toString('base64');
const headers = {
'Authorization': `Basic ${auth}`,
'Content-Type': 'application/json',
};
// Create lead with embedded contact
const leadRes = await fetch(`${CLOSE_BASE}/lead/`, {
method: 'POST',
headers,
body: JSON.stringify({
name: dev.company || dev.name,
contacts: [{
name: dev.name,
emails: dev.email ? [{ email: dev.email, type: 'office' }] : [],
urls: [{ url: `https://github.com/${dev.github_username}`, label: 'GitHub' }],
}],
custom: {
'GitHub Username': dev.github_username,
'Followers': dev.followers,
'Top Languages': dev.top_languages.join(', '),
'Signal Type': payload.signal_type,
'Signal Source': payload.repo || payload.keyword,
},
}),
});
const lead = await leadRes.json();
// Add note with signal context
await fetch(`${CLOSE_BASE}/activity/note/`, {
method: 'POST',
headers,
body: JSON.stringify({
lead_id: lead.id,
note: `GitLeads: ${payload.signal_type} on ${payload.repo || payload.keyword}. ${dev.followers} followers. Bio: ${dev.bio || 'n/a'}`,
}),
});
}Step 4: Enroll in a Close Sequence
// Enroll contact in a Close email sequence
async function enrollInSequence(
contactId: string,
sequenceId: string,
senderEmail: string
) {
const auth = Buffer.from(CLOSE_API_KEY + ':').toString('base64');
await fetch(`${CLOSE_BASE}/sequence_subscription/`, {
method: 'POST',
headers: {
'Authorization': `Basic ${auth}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
contact_id: contactId,
sequence_id: sequenceId,
sender_account: { email: senderEmail },
}),
});
}
// Only enroll leads with email + company (higher qualification)
if (dev.email && dev.company) {
await enrollInSequence(contactId, SEQUENCE_ID, 'outreach@yourco.com');
}Using Zapier or n8n Instead
GitLeads also supports native Zapier and n8n integrations. Connect GitLeads → Zapier → Close via Close's Zapier app and configure field mapping in the editor. This covers the most common case: create a Close lead for every new GitHub stargazer without writing any code.