Push GitHub Leads to Woodpecker.co: Cold Email Developer Prospects Automatically

Send GitLeads GitHub signal leads directly into Woodpecker.co cold email campaigns. Integration guide with webhook handler and Woodpecker API.

Published: May 5, 2026Updated: May 5, 20266 min read

Woodpecker.co is a cold email platform built for B2B SaaS sales — sequences, follow-ups, A/B testing, and team inbox rotation. GitLeads plugs directly into Woodpecker via its REST API: every developer who shows a GitHub buying signal (new star, keyword mention) becomes a Woodpecker prospect, enriched and ready for your sequence.

What You Get in Each Lead

  • GitHub username, name, email (if public), company, location
  • Signal type: stargazer (starred your or a competitor repo) or keyword (mentioned your target term in an issue/PR/discussion)
  • Signal context: the exact repo or keyword that triggered the lead
  • Top programming languages — useful for sequence personalization
  • Follower count — a proxy for developer influence

Woodpecker API Integration

Woodpecker exposes a REST API for adding prospects to campaigns. The flow: GitLeads fires a webhook → your handler validates the payload → calls Woodpecker API to add the prospect → Woodpecker starts the email sequence automatically.

import crypto from 'crypto';

interface GitLeadsLead {
  name: string;
  email?: string;
  githubUsername: string;
  profileUrl: string;
  bio?: string;
  company?: string;
  location?: string;
  followers: number;
  topLanguages: string[];
  signalType: 'stargazer' | 'keyword';
  signalContext: string;
}

function verifyGitleadsSignature(body: string, sig: string, secret: string) {
  const expected = crypto.createHmac('sha256', secret).update(body).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}

async function addProspectToWoodpecker(lead: GitLeadsLead): Promise<void> {
  const WOODPECKER_API_KEY = process.env.WOODPECKER_API_KEY!;
  const CAMPAIGN_ID = parseInt(process.env.WOODPECKER_CAMPAIGN_ID!, 10);

  const res = await fetch('https://api.woodpecker.co/rest/v1/prospects_lists', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${WOODPECKER_API_KEY}`,
    },
    body: JSON.stringify({
      update: false, // don't overwrite existing prospects
      campaign: { id: CAMPAIGN_ID },
      prospects: [
        {
          email: lead.email!,
          first_name: lead.name.split(' ')[0] ?? lead.githubUsername,
          last_name: lead.name.split(' ').slice(1).join(' ') || '',
          company: lead.company ?? '',
          // Woodpecker custom variables — map to {{VAR}} in templates
          snippet1: lead.githubUsername,               // {{SNIPPET1}} = GitHub username
          snippet2: lead.topLanguages.join(', '),      // {{SNIPPET2}} = top languages
          snippet3: lead.signalContext,                // {{SNIPPET3}} = signal context
          snippet4: lead.signalType,                   // {{SNIPPET4}} = signal type
          snippet5: String(lead.followers),            // {{SNIPPET5}} = follower count
        },
      ],
    }),
  });

  if (!res.ok) {
    const err = await res.text();
    throw new Error(`Woodpecker API error: ${err}`);
  }
}

export async function POST(req: Request): Promise<Response> {
  const rawBody = await req.text();
  const sig = req.headers.get('x-gitleads-signature') ?? '';

  if (!verifyGitleadsSignature(rawBody, sig, process.env.GITLEADS_WEBHOOK_SECRET!)) {
    return new Response('Unauthorized', { status: 401 });
  }

  const { event, lead } = JSON.parse(rawBody) as {
    event: string;
    lead: GitLeadsLead;
  };

  if (event === 'lead.created' && lead.email) {
    await addProspectToWoodpecker(lead);
  }

  return new Response('ok');
}

Personalizing Woodpecker Templates with GitHub Data

Woodpecker supports custom snippet variables in email templates. Map GitLeads fields to snippets and reference them in subject lines and body copy:

  • Subject: "Quick question about your work on {{SNIPPET3}}" — references the repo or keyword
  • Opener: "Noticed you're working in {{SNIPPET2}} — we built something that might save you a few hours..."
  • Social proof: "{{SNIPPET5}} developers on GitHub are already using [your product]..."
  • CTA variation: star signals → evaluation angle; keyword signals → pain-point angle

Routing Leads to the Right Campaign

Use different CAMPAIGN_IDs based on signal type. Stargazers are evaluating — use a shorter, more direct sequence. Keyword mentions signal a specific pain point — use a solution-focused sequence.

const CAMPAIGN_MAP: Record<string, number> = {
  stargazer: parseInt(process.env.WOODPECKER_STARGAZER_CAMPAIGN_ID!, 10),
  keyword: parseInt(process.env.WOODPECKER_KEYWORD_CAMPAIGN_ID!, 10),
};

// In your webhook handler:
const campaignId = CAMPAIGN_MAP[lead.signalType] ?? CAMPAIGN_MAP.stargazer;
GitLeads captures developer buying signals on GitHub and pushes enriched leads into Woodpecker.co automatically. Free plan: 50 leads/month. Sign up at gitleads.app. Related: push GitHub leads to Instantly, push GitHub leads to Smartlead, push GitHub leads to Lemlist.

Want more like this? Get the weekly developer lead playbook.

No spam. 5 emails over 2 weeks. Unsubscribe anytime.

Related Articles

How to Find Leads on GitHub: The Complete Guide (2026)
10 min read
GitHub Leads vs LinkedIn Leads: When to Use Which (2026)
9 min read
GDPR Compliance for GitHub Lead Scraping: What You Must Know
8 min read