Complete Clay integration skill pack with 30 skills covering data enrichment, waterfall workflows, AI agents, and GTM automation. Flagship+ tier vendor pack.
Installation
Open Claude Code and run this command:
/plugin install clay-pack@claude-code-plugins-plus
Use --global to install for all projects, or --project for current project only.
Skills (30)
Deep-debug complex Clay enrichment failures, provider degradation, and data flow issues.
Clay Advanced Troubleshooting
Overview
Deep debugging techniques for complex Clay issues that resist standard troubleshooting. Covers provider-level isolation, waterfall diagnosis, HTTP API column debugging, Claygent failure analysis, and Clay support escalation with proper evidence.
Prerequisites
- Access to Clay table with the failing enrichments
- curl and jq for API testing
- Understanding of Clay's enrichment architecture (providers, waterfall, columns)
- Browser developer tools for network inspection
Instructions
Step 1: Isolate the Failure Layer
#!/bin/bash
# clay-layer-test.sh — test each integration layer independently
set -euo pipefail
echo "=== Layer Isolation Test ==="
# Layer 1: Webhook delivery
echo "Layer 1: Webhook"
WEBHOOK_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST "$CLAY_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{"_debug": true, "domain": "google.com"}')
echo " Webhook: $WEBHOOK_CODE"
# Layer 2: Enterprise API (if applicable)
if [ -n "${CLAY_API_KEY:-}" ]; then
echo "Layer 2: Enterprise API"
API_RESULT=$(curl -s -X POST "https://api.clay.com/v1/companies/enrich" \
-H "Authorization: Bearer $CLAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"domain": "google.com"}')
echo " API response keys: $(echo "$API_RESULT" | jq 'keys')"
fi
# Layer 3: HTTP API callback endpoint
echo "Layer 3: Callback endpoint"
CALLBACK_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST "${CLAY_CALLBACK_URL:-http://localhost:3000/api/clay/enriched}" \
-H "Content-Type: application/json" \
-d '{"_debug_test": true}')
echo " Callback: $CALLBACK_CODE"
echo ""
echo "First failing layer = root cause location"
Step 2: Diagnose Enrichment Column Failures
In the Clay UI, click on red/error cells to see detailed error messages:
# Common enrichment column error patterns and root causes:
errors:
"No data found":
meaning: "Provider has no data for this input"
check:
- Is the input domain valid? (not personal email domain)
- Is the input name spelled correctly?
- Is the provider connected? (Settings > Connections)
fix: "Add more waterfall providers for broader coverage"
"Rate limit exceeded":
meaning: "Provider API rate limit hit"
check:
- How many rows are processing simultaneously?
- Is the provider's rate limit known? (see provider docs)
fix: "Reduce table row count, add delay between batches"
"IChoose and implement Clay integration architecture for different scales and use cases.
Clay Architecture Variants
Overview
Three proven architecture patterns for Clay data enrichment at different scales. Clay is a hosted SaaS -- your architecture decisions focus on how you send data in (webhooks), how you get enriched data out (HTTP API columns, CRM sync, or CSV export), and how you orchestrate the flow.
Prerequisites
- Clay account with appropriate plan tier
- Clear understanding of data volume and latency requirements
- Infrastructure for chosen architecture tier (if queue-based or event-driven)
Instructions
Architecture 1: Direct Integration (Simple)
Best for: Small teams, < 1K enrichments/day, ad-hoc usage.
┌──────────────┐ webhook ┌───────────┐
│ Your App │───────POST─────>│ Clay Table │
│ (or CSV) │ │ (enriches) │
└──────────────┘ └─────┬─────┘
│
CRM action
or CSV export
│
v
┌───────────┐
│ CRM / DB │
└───────────┘
// Direct: send leads synchronously, export results manually
async function directEnrich(leads: Lead[]): Promise<void> {
for (const lead of leads) {
await fetch(process.env.CLAY_WEBHOOK_URL!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(lead),
});
await new Promise(r => setTimeout(r, 250)); // Rate limit
}
console.log(`Sent ${leads.length} leads. Check Clay table for enriched data.`);
// Enriched data reaches CRM via Clay's native CRM action column
}
Pros: Zero infrastructure, 5-minute setup, works on all Clay plans.
Cons: No retry logic, no programmatic access to enriched data, manual export only.
Architecture 2: Webhook-in, HTTP API-out (Standard)
Best for: Growing teams, 1K-10K enrichments/day, CRM integration.
┌──────────────┐ webhook ┌───────────┐ HTTP API col ┌──────────────┐
│ Your App │───────POST─────>│ Clay Table │──────POST──────>│ Your Webhook │
│ │ │ (enriches) │ │ Handler │
└──────────────┘ └───────────┘ └──────┬───────┘
│
Process +
Route
│
┌───────────┼───Configure CI/CD pipelines for Clay integrations with automated testing and validation.
Clay CI Integration
Overview
Set up CI/CD pipelines for Clay-powered applications. Since Clay is a web platform (not a local service), CI focuses on: (1) testing webhook handler code, (2) validating data transformation logic, (3) checking enrichment data schema compliance, and (4) optional live integration tests against Clay's API.
Prerequisites
- GitHub repository with Actions enabled
- Clay webhook URL stored as GitHub secret
- Node.js/Python project with test framework
Instructions
Step 1: Create GitHub Actions Workflow
# .github/workflows/clay-integration.yml
name: Clay Integration Tests
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
CLAY_WEBHOOK_URL: ${{ secrets.CLAY_WEBHOOK_URL }}
CLAY_API_KEY: ${{ secrets.CLAY_API_KEY }}
jobs:
unit-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm test -- --coverage
env:
# No Clay credentials needed for unit tests (use mocks)
CLAY_WEBHOOK_URL: "https://mock.webhook.test"
data-validation:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- name: Validate input data schemas
run: npx tsx scripts/validate-clay-schemas.ts
- name: Check for PII in test fixtures
run: |
if grep -rn '@gmail.com\|@yahoo.com\|@hotmail.com' test/fixtures/; then
echo "ERROR: Real email addresses found in test fixtures"
exit 1
fi
integration-tests:
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
needs: [unit-tests]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- name: Test webhook connectivity
run: |
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST "$CLAY_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{"_ci_test": true, "_run_id": "${{ github.run_id }}"}')
if [ "$HTTP_CODE" != "200" ]; then
echo "Webhook connectivity check failed: HTTP $HTTP_CODE"
exit 1
fi
Step 2: Configure Secrets
# Store Clay credentials as GitHub secrets
gh secret set CLAY_WEBHOOK_URL --body "https://app.clay.com/api/v1/webhooks/your-id"
gh secret set CLAY_APDiagnose and fix the most common Clay errors and integration issues.
Clay Common Errors
Overview
Quick reference for the top 12 most common Clay errors across webhooks, enrichment columns, HTTP API columns, Claygent, and CRM integrations. Each error includes the exact symptom, root cause, and fix.
Prerequisites
- Clay account with an active table
- Access to Clay table error indicators (red cells, exclamation marks)
- Browser developer tools for webhook debugging
Instructions
Error 1: Webhook Returns 422 Unprocessable Entity
Symptom: Data sent to webhook URL but rows never appear in table.
Cause: Invalid JSON payload or missing Content-Type header.
Fix:
# Always include Content-Type header
curl -X POST "$CLAY_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{"email": "test@example.com", "domain": "example.com"}'
# Validate JSON before sending
echo '{"email": "test@example.com"}' | jq . || echo "Invalid JSON!"
Error 2: Webhook URL Returns 404
Symptom: 404 Not Found when POSTing to webhook URL.
Cause: Table was deleted, webhook was replaced, or URL was copied incorrectly.
Fix: Open the Clay table, click + Add > Webhooks > Monitor webhook, and re-copy the URL. Each table has a unique webhook ID.
Error 3: Enrichment Column Shows "No Data Found"
Symptom: Enrichment column returns empty for most rows.
Cause: Input data quality is poor (personal email domains, invalid domains, missing fields).
Fix:
// Pre-validate before sending to Clay
const personalDomains = ['gmail.com', 'yahoo.com', 'hotmail.com', 'outlook.com', 'icloud.com'];
function isEnrichable(row: { domain?: string; email?: string }): boolean {
if (!row.domain || !row.domain.includes('.')) return false;
if (personalDomains.some(d => row.domain!.endsWith(d))) return false;
if (row.email && personalDomains.some(d => row.email!.endsWith(d))) return false;
return true;
}
Error 4: "Credit Balance Insufficient"
Symptom: Enrichment stops mid-table with credit error.
Cause: Monthly credit allowance exhausted.
Fix: Check credit balance in Settings > Plans & Billing. Options:
- Connect your own provider API keys (saves 70-80% credits)
- Reduce waterfall depth (fewer providers = fewer credits per row)
- Upgrade plan for more monthly credits
Error 5: Webhook Submission Limit Reached (50K)
Build a complete lead enrichment pipeline using Clay tables, webhooks, and waterfall enrichment.
Clay Core Workflow A: Lead Enrichment Pipeline
Overview
Primary workflow for Clay: take a list of companies or contacts, push them into a Clay table via webhook, let Clay's enrichment columns fill in missing data (emails, titles, company info, tech stack), and export the enriched results to your CRM or outreach tool. This is the core use case for 90%+ of Clay users.
Prerequisites
- Completed
clay-install-authsetup - Clay table with webhook source configured
- At least one enrichment provider connected (Apollo, Clearbit, Hunter, etc.)
- Destination CRM or outreach tool (HubSpot, Salesforce, Instantly, etc.)
Instructions
Step 1: Design Your Clay Table Schema
In the Clay web UI, create a table with these column types:
| Column | Type | Purpose |
|---|---|---|
domain |
Input (webhook) | Company domain to enrich |
first_name |
Input (webhook) | Contact first name |
last_name |
Input (webhook) | Contact last name |
Company Name |
Enrichment (Clearbit/Apollo) | Auto-filled from domain |
Employee Count |
Enrichment (Clearbit) | Company headcount |
Industry |
Enrichment (Clearbit) | Industry classification |
Work Email |
Enrichment (Waterfall) | Verified work email |
Job Title |
Enrichment (Apollo/PDL) | Current title |
LinkedIn URL |
Enrichment (Apollo) | Profile link |
ICP Score |
Formula | Computed fit score |
Step 2: Set Up Waterfall Email Enrichment
In Clay UI, add a waterfall enrichment column:
- Click + Add Column > Find Work Email (Waterfall)
- Configure provider order (cheapest first):
- Apollo (2 credits) -- highest coverage
- Hunter.io (2 credits) -- strong for smaller companies
- Prospeo (2 credits) -- European coverage
- Map input:
firstname,lastname,domain - Enable Stop on first result to save credits
- Enable Auto-run on new rows
Step 3: Push Leads into Clay via Webhook
// src/workflows/enrich-leads.ts
import { getClayClient } from '../clay/instance';
interface LeadInput {
domain: string;
first_name: string;
last_name: string;
source?: string;
}
async function enrichLeadList(leads: LeadInput[]): Promise<void> Use Claygent AI research and AI-powered personalization to generate outreach copy from enriched data.
Clay Core Workflow B: Claygent AI Research & Personalization
Overview
Complements the enrichment pipeline (clay-core-workflow-a) with AI-powered research and personalization. Uses Claygent (Clay's built-in AI research agent powered by GPT-4) to scrape websites, extract insights, and generate personalized outreach copy for each prospect. 30% of Clay customers use Claygent daily, generating 500K+ research tasks per day.
Prerequisites
- Completed
clay-core-workflow-awith enriched table - Clay Pro plan or higher (Claygent requires Pro+)
- Understanding of prompt engineering basics
Instructions
Step 1: Add a Claygent Research Column
In your Clay table with enriched leads:
- Click + Add Column > Use AI (Claygent)
- Choose model: Claygent Neon (best for data extraction and formatting)
- Write your research prompt referencing table columns:
Research {{Company Name}} ({{domain}}) and find:
1. Their most recent funding round (amount, date, investors)
2. Any recent product launches or major announcements from the last 6 months
3. Their primary competitors
Return results as structured data. If information is not found, return "Not found" for that field.
- Enable Auto-run on new rows
Step 2: Configure Multi-Output Claygent (Neon Model)
Claygent Neon can extract multiple data points into separate columns from a single run:
Research the company at {{domain}} and extract:
Output 1 (Recent News): The most notable company news from the last 90 days. One sentence.
Output 2 (Tech Stack): List the main technologies they use (check job postings, BuiltWith, Wappalyzer data).
Output 3 (Pain Points): Based on their Glassdoor reviews and recent job postings, identify likely operational pain points.
Output 4 (Competitor): Name their primary competitor.
Map each output to a separate column for downstream use in personalization.
Step 3: Build a Personalized Email Opener Column
Add an AI column (not Claygent -- use the faster AI model for text generation):
You are a sales copywriter. Write a personalized 2-sentence email opener for {{first_name}} at {{Company Name}}.
Context about the prospect:
- Title: {{Job Title}}
- Company size: {{Employee Count}} employees
- Industry: {{Industry}}
- Recent news: {{Recent News}}
- Tech stack: {{Tech Stack}}
Rules:
- Reference one specific fact about their company (not generic)
- Do NOT use "I noticed" or "I came across" (overused)
- Keep it under 40 words
- Sound human, not AI-generated
- End with a natural transition to your value prop
Step 4: Quality-Check AI Output Before Campaign Launch
Before using AI-generated copy in outrea
Optimize Clay credit spending with provider key management, waterfall tuning, and budget controls.
Clay Cost Tuning
Overview
Reduce Clay data enrichment spending by connecting your own API keys (70-80% savings), optimizing waterfall depth, improving input data quality, and implementing budget controls. Clay's March 2026 pricing split credits into Data Credits and Actions, changing the optimization calculus.
Prerequisites
- Clay account with visibility into credit consumption
- Understanding of which enrichment columns are in your tables
- Access to Clay Settings > Plans & Billing
Instructions
Step 1: Connect Your Own Provider API Keys (Biggest Savings)
This is the single most impactful cost reduction. Clay charges 0 Data Credits when you use your own API keys:
| Provider | Clay-Managed Cost | Own Key Cost | Annual Savings (10K rows/mo) |
|---|---|---|---|
| Apollo | 2 credits/lookup | 0 credits | ~240K credits/year |
| Clearbit | 2-5 credits | 0 credits | ~360K credits/year |
| Hunter.io | 2 credits | 0 credits | ~240K credits/year |
| Prospeo | 2 credits | 0 credits | ~240K credits/year |
| People Data Labs | 3 credits | 0 credits | ~360K credits/year |
| ZoomInfo | 5-13 credits | 0 credits | ~1M+ credits/year |
Setup: Go to Settings > Connections in Clay, click Add Connection, and paste your provider API key. All enrichments using that provider will consume 0 Clay credits (1 Action is still consumed per enrichment).
Step 2: Optimize Waterfall Enrichment Depth
Each waterfall step costs credits (if using Clay-managed keys) and time:
# Expensive waterfall (5 providers, 10-15 credits/row):
expensive:
- apollo: 2 credits
- hunter: 2 credits
- prospeo: 2 credits
- dropcontact: 3 credits
- findymail: 3 credits
total_max: 12 credits/row
coverage: ~92%
# Optimized waterfall (2 providers, 4 credits/row):
optimized:
- apollo: 2 credits # Highest coverage provider first
- hunter: 2 credits # Strong backup
total_max: 4 credits/row
coverage: ~83%
savings: "67% credit reduction, ~9% coverage loss"
March 2026 change: Failed lookups no longer cost Data Credits. This makes wider waterfalls less expensive than before, since you only pay when data is actually found.
Step 3: Pre-Filter Input Data
Credits wasted on unenrichable rows are the most common cost leak:
// src/clay/cost-filter.ts
function estimateCreditCost(rows: any[], creditsPerRow: number): {
filteredRows: any[];
estimatedCredits: number;
savings: number;
} {
const personImplement GDPR/CCPA-compliant data handling for Clay enrichment pipelines.
Clay Data Handling
Overview
Manage lead data through Clay enrichment pipelines in compliance with GDPR, CCPA, and data privacy best practices. Clay enriches records with PII (emails, phone numbers, LinkedIn profiles, job titles), requiring careful handling of consent, retention, and export controls.
Prerequisites
- Clay account with enriched tables
- Understanding of GDPR/CCPA requirements for B2B data
- Data retention policy defined by your legal team
- CRM or database for enriched data storage
Instructions
Step 1: Classify Enriched Data by Sensitivity
// src/clay/data-classification.ts
enum DataSensitivity {
PUBLIC = 'public', // Company name, industry, employee count
BUSINESS = 'business', // Work email, job title, LinkedIn URL
PERSONAL = 'personal', // Phone number, personal email
RESTRICTED = 'restricted' // Home address, personal phone
}
const FIELD_CLASSIFICATION: Record<string, DataSensitivity> = {
company_name: DataSensitivity.PUBLIC,
industry: DataSensitivity.PUBLIC,
employee_count: DataSensitivity.PUBLIC,
domain: DataSensitivity.PUBLIC,
work_email: DataSensitivity.BUSINESS,
job_title: DataSensitivity.BUSINESS,
linkedin_url: DataSensitivity.BUSINESS,
first_name: DataSensitivity.BUSINESS,
last_name: DataSensitivity.BUSINESS,
phone_number: DataSensitivity.PERSONAL,
personal_email: DataSensitivity.RESTRICTED,
home_address: DataSensitivity.RESTRICTED,
};
function classifyRow(row: Record<string, unknown>): Record<DataSensitivity, string[]> {
const classified: Record<DataSensitivity, string[]> = {
public: [], business: [], personal: [], restricted: [],
};
for (const [field, value] of Object.entries(row)) {
if (value == null) continue;
const sensitivity = FIELD_CLASSIFICATION[field] || DataSensitivity.BUSINESS;
classified[sensitivity].push(field);
}
return classified;
}
Step 2: Validate Input Data Before Enrichment
// src/clay/data-validation.ts
import { z } from 'zod';
const ClayInputSchema = z.object({
domain: z.string().min(3).refine(d => d.includes('.'), 'Invalid domain'),
first_name: z.string().min(1).max(100),
last_name: z.string().min(1).max(100),
email: z.string().email().optional(),
source: z.string().optional(),
consent_basis: z.enum(['legitimate_interest', 'consent', 'contract']).optional(),
});
function validateForEnrichment(rows: unknown[]): {
valid: z.infer<typeof ClayInputSchema>[];
invalid: { row: unknown; errors: string[] }[];
} {
const valid: z.infer<typeof ClayInputSchema>[] = [];
const invalid: { row: unknown; errors: string[] }[] = [];
for (const row of rows) {
const result = ClayInputSchema.safeParse(row);
if (result.succesCollect Clay debug evidence for support tickets and troubleshooting.
Clay Debug Bundle
Current State
!node --version 2>/dev/null || echo 'N/A'
!python3 --version 2>/dev/null || echo 'N/A'
Overview
Collect all diagnostic information needed for Clay support tickets. Clay is a web platform, so debugging focuses on webhook delivery, enrichment column errors, HTTP API responses, and credit consumption -- not pods or clusters.
Prerequisites
- Clay account with access to affected table
- curl for testing webhook/API connectivity
- Browser developer tools for capturing network requests
Instructions
Step 1: Create Debug Bundle Script
#!/bin/bash
# clay-debug-bundle.sh — collect Clay integration diagnostics
set -euo pipefail
BUNDLE_DIR="clay-debug-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$BUNDLE_DIR"
echo "=== Clay Debug Bundle ===" > "$BUNDLE_DIR/summary.txt"
echo "Generated: $(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$BUNDLE_DIR/summary.txt"
echo "" >> "$BUNDLE_DIR/summary.txt"
Step 2: Test Webhook Connectivity
# Test webhook endpoint is reachable
echo "--- Webhook Test ---" >> "$BUNDLE_DIR/summary.txt"
WEBHOOK_URL="${CLAY_WEBHOOK_URL:-not_set}"
if [ "$WEBHOOK_URL" != "not_set" ]; then
HTTP_CODE=$(curl -s -o "$BUNDLE_DIR/webhook-response.txt" -w "%{http_code}" \
-X POST "$WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{"_debug": true, "_test": "debug-bundle"}')
echo "Webhook HTTP Status: $HTTP_CODE" >> "$BUNDLE_DIR/summary.txt"
echo "Webhook URL: ${WEBHOOK_URL:0:50}..." >> "$BUNDLE_DIR/summary.txt"
else
echo "CLAY_WEBHOOK_URL: NOT SET" >> "$BUNDLE_DIR/summary.txt"
fi
Step 3: Capture Environment and Configuration
# Capture environment (redacted)
echo "" >> "$BUNDLE_DIR/summary.txt"
echo "--- Environment ---" >> "$BUNDLE_DIR/summary.txt"
echo "Node: $(node --version 2>/dev/null || echo 'N/A')" >> "$BUNDLE_DIR/summary.txt"
echo "Python: $(python3 --version 2>/dev/null || echo 'N/A')" >> "$BUNDLE_DIR/summary.txt"
echo "OS: $(uname -s -r)" >> "$BUNDLE_DIR/summary.txt"
echo "CLAY_API_KEY: ${CLAY_API_KEY:+[SET]}" >> "$BUNDLE_DIR/summary.txt"
echo "CLAY_WEBHOOK_URL: ${CLAY_WEBHOOK_URL:+[SET]}" >> "$BUNDLE_DIR/summary.txt"
# Capture .env (redacted)
if [ -f .env ]; then
sed 's/=.*/=***REDACTED***/' .env > "$BUNDLE_DIR/config-redactedDeploy Clay-powered applications to Vercel, Cloud Run, or Docker with proper secrets management.
Clay Deploy Integration
Overview
Deploy applications that integrate with Clay (webhook receivers, enrichment processors, CRM sync services) to production platforms. Clay itself is a hosted SaaS -- you deploy the code that interacts with Clay, not Clay itself. The critical requirement is a publicly accessible HTTPS endpoint for Clay's HTTP API columns to call back to.
Prerequisites
- Application code that handles Clay webhooks or HTTP API callbacks
- Platform CLI installed (vercel, gcloud, or docker)
- Clay webhook URL and/or API key stored securely
- HTTPS endpoint accessible from the public internet
Instructions
Step 1: Vercel Deployment (Serverless)
Best for: Webhook receivers, small-scale enrichment handlers.
# Set Clay secrets in Vercel
vercel env add CLAY_WEBHOOK_URL production
vercel env add CLAY_API_KEY production
vercel env add CLAY_WEBHOOK_SECRET production
# Deploy
vercel --prod
// api/clay/callback.ts — Vercel serverless function
import type { VercelRequest, VercelResponse } from '@vercel/node';
import crypto from 'crypto';
export default async function handler(req: VercelRequest, res: VercelResponse) {
if (req.method !== 'POST') return res.status(405).end();
// Validate webhook signature
const signature = req.headers['x-clay-signature'] as string;
const secret = process.env.CLAY_WEBHOOK_SECRET!;
const expected = crypto.createHmac('sha256', secret)
.update(JSON.stringify(req.body))
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(signature || ''), Buffer.from(expected))) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process enriched data from Clay HTTP API column
const enrichedLead = req.body;
console.log('Received enriched lead:', {
email: enrichedLead.email,
company: enrichedLead.company_name,
score: enrichedLead.icp_score,
});
// Push to CRM, database, or outreach tool
await processLead(enrichedLead);
return res.status(200).json({ status: 'processed' });
}
Step 2: Cloud Run Deployment (Container)
Best for: High-volume enrichment pipelines, CRM sync services.
# Dockerfile
FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY dist/ ./dist/
EXPOSE 8080
ENV PORT=8080
CMD ["node", "dist/index.js"]
# Build and deploy to Cloud Run
gcloud builds submit --tag gcr.io/$PROJECT_ID/clay-handler
gcloud run deploy clay-handler \
--image gcr.io/$PROJECT_ID/clay-handler \
--platform managed \
--region us-central1 \
--allow-unauthenticated \
--set-secrets "CLAY_API_KEY=clay-api-key:latest,CLAY_WEBHOOK_SECRET=clay-webhook-secret:laConfigure Clay workspace roles, team access control, and credit budget allocation.
Clay Enterprise RBAC
Overview
Control access to Clay tables, enrichment credits, and integrations at the team level. Clay uses a workspace model where team members are assigned Admin, Member, or Viewer roles. This skill covers role assignment, credit budget allocation, API key isolation, and audit procedures.
Prerequisites
- Clay Team or Enterprise plan
- Workspace admin privileges
- Understanding of team structure and data access needs
Instructions
Step 1: Define Role Matrix
Clay has three built-in roles with fixed permissions:
| Capability | Admin | Member | Viewer |
|---|---|---|---|
| Manage workspace members | Yes | No | No |
| Manage billing and credits | Yes | No | No |
| Create/delete tables | Yes | Yes | No |
| Run enrichments | Yes | Yes | No |
| Configure integrations | Yes | No | No |
| Export data | Yes | Yes | Yes |
| View all tables | Yes | Yes | Yes |
Recommended role assignments:
roles:
admin:
assign_to:
- Revenue Operations Lead
- GTM Engineering Lead
why: "Controls billing, integrations, and team access"
member:
assign_to:
- SDRs building prospect lists
- Growth engineers building pipelines
- Marketing ops running enrichment campaigns
why: "Can create tables and run enrichments but can't change billing or integrations"
viewer:
assign_to:
- Sales managers reviewing lead quality
- Executives checking pipeline metrics
- Finance reviewing credit usage
why: "Read-only access to enriched data and exports"
Step 2: Invite and Manage Team Members
In Clay UI: Settings > Members > Invite
Best practices:
- Use company email addresses (not personal)
- Start new members as Viewers until they complete Clay training
- Audit member list quarterly -- remove departed employees immediately
Step 3: Isolate API Keys by Integration
Create separate API keys for each downstream system to enable independent revocation:
api_keys:
crm-sync-prod:
purpose: "HubSpot CRM sync from Clay"
used_by: "HTTP API column in Outbound Leads table"
rotation: quarterly
outbound-instantly:
purpose: "Push qualified leads to Instantly.ai"
used_by: "HTTP API column for outreach"
rotation: quarterly
internal-dashboard:
purpose: "Pull enrichment metrics for internal dashboard"
used_by: &quoSend your first record to Clay and get enriched data back.
Clay Hello World
Overview
Minimal working example: send a company domain to a Clay table via webhook, let Clay's enrichment columns fill in company data, and retrieve the enriched result. Clay does not have a traditional SDK — you interact with it via webhooks (data in), HTTP API columns (data out), and the web UI.
Prerequisites
- Completed
clay-install-authsetup - Clay workbook with a webhook source configured
- At least one enrichment column added to the table
Instructions
Step 1: Create a Clay Table with Enrichment
In the Clay web UI:
- Create a new workbook
- Add columns:
domain,companyname,employeecount,industry - Click + Add at bottom, select Webhooks > Monitor webhook
- Copy the webhook URL
- Add an enrichment column: + Add Column > Enrich Company (uses the
domaincolumn as input)
Step 2: Send Your First Record via Webhook
# Send a single company domain to your Clay table
curl -X POST "https://app.clay.com/api/v1/webhooks/YOUR_WEBHOOK_ID" \
-H "Content-Type: application/json" \
-d '{"domain": "openai.com"}'
Within seconds, Clay creates a new row and auto-runs the enrichment column. The companyname, employeecount, and industry columns fill in automatically.
Step 3: Send Multiple Records
# Batch send — each object becomes a row
for domain in stripe.com notion.so figma.com linear.app; do
curl -s -X POST "https://app.clay.com/api/v1/webhooks/YOUR_WEBHOOK_ID" \
-H "Content-Type: application/json" \
-d "{\"domain\": \"$domain\"}"
echo " -> Sent $domain"
done
Step 4: Send from Node.js
// hello-clay.ts — send records to Clay via webhook
const CLAY_WEBHOOK_URL = process.env.CLAY_WEBHOOK_URL!;
interface LeadInput {
email?: string;
domain?: string;
first_name?: string;
last_name?: string;
linkedin_url?: string;
}
async function sendToClay(lead: LeadInput): Promise<Response> {
const response = await fetch(CLAY_WEBHOOK_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(lead),
});
if (!response.ok) {
throw new Error(`Clay webhook failed: ${response.status} ${response.statusText}`);
}
return response;
}
// Send a test lead
await sendToClay({
email: 'jane@stripe.com',
first_name: 'Jane',
last_name: 'Doe',
domain: 'stripe.com',
});
console.log('Record sent to Clay — check your table for enriched data.'Execute Clay incident response procedures for enrichment failures, credit exhaustion, and data flow outages.
Clay Incident Runbook
Overview
Rapid response procedures for Clay-related production incidents. Clay is a hosted SaaS platform, so incidents fall into two categories: (1) Clay-side issues (platform outage, provider degradation) and (2) your-side issues (webhook misconfiguration, credit exhaustion, handler failures).
Severity Levels
| Level | Definition | Response Time | Examples |
|---|---|---|---|
| P1 | Complete data flow stopped | < 15 min | Credits exhausted, webhook URL expired, Clay outage |
| P2 | Degraded enrichment | < 1 hour | Low hit rates, slow processing, CRM sync errors |
| P3 | Minor impact | < 4 hours | Single provider down, intermittent webhook failures |
| P4 | No user impact | Next business day | Monitoring gaps, cost optimization needed |
Instructions
Step 1: Quick Triage (2 Minutes)
#!/bin/bash
# clay-triage.sh — rapid diagnostic for Clay incidents
set -euo pipefail
echo "=== Clay Incident Triage ==="
echo "Time: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
echo ""
# 1. Check Clay platform status
echo "--- Clay Platform Status ---"
curl -s -o /dev/null -w "clay.com: HTTP %{http_code}\n" https://www.clay.com
echo ""
# 2. Test webhook delivery
echo "--- Webhook Test ---"
if [ -n "${CLAY_WEBHOOK_URL:-}" ]; then
WEBHOOK_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST "$CLAY_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{"_triage": true, "_ts": "'$(date -u +%s)'"}')
echo "Webhook: HTTP $WEBHOOK_CODE"
if [ "$WEBHOOK_CODE" = "200" ]; then echo " -> Webhook OK"; fi
if [ "$WEBHOOK_CODE" = "404" ]; then echo " -> ISSUE: Webhook URL invalid/expired"; fi
if [ "$WEBHOOK_CODE" = "429" ]; then echo " -> ISSUE: Rate limited"; fi
else
echo "CLAY_WEBHOOK_URL not set!"
fi
echo ""
# 3. Test Enterprise API (if applicable)
echo "--- Enterprise API Test ---"
if [ -n "${CLAY_API_KEY:-}" ]; then
API_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST "https://api.clay.com/v1/people/enrich" \
-H "Authorization: Bearer $CLAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "triage@test.com"}')
echo "Enterprise API: HTTP $API_CODE"
if [ "$API_CODE" = "401" ]; then echo " -> ISSUE: API key invalid/expired"; fi
if [ "$API_CODE" = "403" ]; then echo " ->Set up Clay account access, API keys, webhook URLs, and provider connections.
Clay Install & Auth
Overview
Clay is a web-based data enrichment platform — there is no SDK to install. Integration happens through webhook URLs (inbound data), HTTP API enrichment columns (outbound calls from Clay), and the Enterprise API (programmatic people/company lookups). This skill covers account setup, API key management, provider connections, and webhook configuration.
Prerequisites
- Clay account at clay.com (free tier available)
- For Enterprise API: Enterprise plan subscription
- For webhook integration: HTTPS endpoint or tunneling tool (ngrok)
Instructions
Step 1: Get Your Clay API Key (Enterprise Only)
Navigate to Settings > API in your Clay workspace. Copy your API key. Clay's Enterprise API is limited to people and company data lookups — it is not a general-purpose table API.
# Store your Clay API key securely
export CLAY_API_KEY="clay_ent_your_api_key_here"
# Verify with a test lookup (Enterprise API)
curl -s -X POST "https://api.clay.com/v1/people/enrich" \
-H "Authorization: Bearer $CLAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "test@example.com"}' | jq .
Step 2: Configure Webhook Inbound Source
Every Clay table can receive data via a unique webhook URL. This is the primary way to send data into Clay programmatically.
- Open a Clay workbook (or create one)
- Click + Add at the bottom of the table
- Search for Webhooks and click Monitor webhook
- Copy the generated webhook URL
# Store your table's webhook URL
export CLAY_WEBHOOK_URL="https://app.clay.com/api/v1/webhooks/your-unique-id"
# Send a test record to your Clay table
curl -X POST "$CLAY_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{
"email": "jane@acme.com",
"first_name": "Jane",
"last_name": "Doe",
"company": "Acme Corp",
"title": "VP of Sales"
}'
The record appears as a new row in your Clay table within seconds.
Step 3: Connect Data Provider API Keys
Clay supports 150+ enrichment providers. Connecting your own API keys saves 70-80% on Clay credits.
- Go to Settings > Connections in Clay
- Click Add Connection for each provider
- Paste your API key
Common providers to connect:
| Provider | Key Location | Credit Savings | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Apollo.io | Settings > API Keys | 2 credits/lookup saved<
Identify and avoid the top Clay anti-patterns, gotchas, and integration mistakes.
ReadGrep
Clay Known PitfallsOverviewReal gotchas when using Clay's data enrichment platform. These are the mistakes that cost credits, waste time, or break integrations -- learned from production experience. Each pitfall includes the exact symptom, root cause, and fix. Prerequisites
InstructionsPitfall 1: Webhook 50K Limit SurpriseSymptom: Webhook silently stops accepting new data. No error, no notification. New rows simply don't appear. Root cause: Each Clay webhook has a hard 50,000 submission lifetime limit. This limit persists even after deleting rows from the table. Fix:
Pitfall 2: Waterfall Burns Credits Without "Stop on First Result"Symptom: Credits consumed at 3-5x the expected rate on waterfall enrichment columns. Root cause: By default, waterfall enrichment may query ALL providers even after the first one finds data. You must explicitly enable "stop on first result." Fix: In each waterfall column's settings, ensure the stop condition is configured. Without it, a 5-provider email waterfall costs 10-15 credits per row instead of 2-3. Pitfall 3: Personal Email Domains Waste CreditsSymptom: Company enrichment returns empty for 30-50% of rows. Root cause: Rows contain gmail.com, yahoo.com, hotmail.com domains. Clay's company enrichment can't match personal email domains to companies. Fix:
Pitfall 4: Auto-Update Re-Enriches Entire TableSymptom: Thousands of credits consumed overnight. Enrichment columns re-ran on rows that were already enriched. Root cause: Table-level auto-update was ON, and a column edit or provider reconnection triggered r Scale Clay enrichment pipelines for high-volume processing (10K-100K+ leads/month).
ReadWriteEditBash(curl:*)Bash(node:*)
Clay Load & ScaleOverviewStrategies for processing 10K-100K+ leads through Clay monthly. Clay is a hosted platform -- you can't add servers. Scaling focuses on: table partitioning, webhook management, batch submission pacing, credit budgeting at scale, and multi-table architectures. Prerequisites
InstructionsStep 1: Capacity Planning
Step 2: Implement Batch Queue ArchitectureSet up a local development loop for building and testing Clay integrations.
ReadWriteEditBash(curl:*)Bash(npm:*)Bash(npx:*)Bash(node:*)Bash(python3:*)
Clay Local Dev LoopOverviewClay is a web-based platform with no local runtime. Your local dev loop consists of: (1) scripts that push data into Clay via webhooks, (2) Clay enrichment running in the cloud, and (3) HTTP API columns pushing enriched data back to your local endpoint via ngrok. This skill sets up that feedback loop. Prerequisites
InstructionsStep 1: Expose Your Local Server via ngrokClay's HTTP API enrichment columns need a public URL to call your local endpoints.
Step 2: Create a Local Webhook Receiver
Step 3: Build a Test Data SenderMigrate to Clay from other enrichment tools or consolidate multiple data sources into Clay.
ReadWriteEditBash(curl:*)Bash(npm:*)Bash(node:*)
Clay Migration Deep DiveOverviewComprehensive guide for migrating from standalone enrichment tools (ZoomInfo, Apollo, Clearbit, Lusha) to Clay, or consolidating multiple tools into a single Clay-based pipeline. Clay replaces the need for individual provider subscriptions by aggregating 150+ providers into waterfall enrichment workflows. Prerequisites
Migration Types
InstructionsStep 1: Audit Current Enrichment Stack (Week 1)Configure Clay integrations across development, staging, and production environments.
ReadWriteEditBash(curl:*)Grep
Clay Multi-Environment SetupOverviewConfigure Clay integrations across dev/staging/prod with isolated tables, separate webhook URLs, and environment-specific enrichment settings. Clay is a single workspace per account, so multi-environment isolation requires separate tables, careful naming, and environment-aware application code. Prerequisites
InstructionsStep 1: Create Per-Environment TablesIn Clay, create separate tables for each environment:
Each table gets its own webhook URL. Copy each URL to the appropriate environment's secrets. Step 2: Environment Configuration
Step 3: Environment Variable ManagementMonitor Clay enrichment pipeline health, credit consumption, and data quality metrics.
ReadWriteEditBash(curl:*)
Clay ObservabilityOverviewMonitor Clay data enrichment pipeline health across four dimensions: credit consumption velocity, enrichment success rates (hit rates), data quality scores, and CRM sync reliability. Clay's credit-based pricing model makes observability essential for cost control. Prerequisites
InstructionsStep 1: Instrument Your Clay Webhook HandlerOptimize Clay table enrichment throughput, reduce processing time, and improve hit rates.
ReadWriteEditBash(curl:*)
Clay Performance TuningOverviewOptimize Clay table processing speed, enrichment hit rates, and credit efficiency. Clay processes enrichment columns sequentially per row, and each enrichment column makes external API calls. Performance tuning focuses on reducing wasted enrichments, ordering columns optimally, and managing table auto-run behavior. Prerequisites
InstructionsStep 1: Order Enrichment Columns by SpeedClay runs enrichment columns left-to-right. Place fast columns first:
Why order matters: Fast columns populate data that slow columns may need as input (e.g., company name feeds into Claygent research prompt). Step 2: Add Conditional Run RulesPrevent enrichments from running on rows that won't yield results:
This prevents:
Step 3: Optimize Input Data Before ImportImplement credit spending limits, data privacy enforcement, and input validation guardrails for Clay pipelines.
ReadWriteEditBash(node:*)
Clay Policy GuardrailsOverviewPolicy enforcement and guardrails for Clay data enrichment pipelines. Clay processes personal and business data at scale, requiring strict controls around credit spending, data privacy compliance, input validation, and export restrictions. Prerequisites
InstructionsStep 1: Credit Spending GuardrailsExecute production readiness checklist for Clay integrations.
ReadBash(curl:*)Grep
Clay Production ChecklistOverviewComplete checklist for launching Clay enrichment pipelines in production. Covers table configuration, credit budgeting, webhook reliability, CRM sync validation, and monitoring setup. Prerequisites
InstructionsPhase 1: Table Configuration
Phase 2: Data Quality Gates
Handle Clay rate limits, webhook throttling, and credit pacing strategies.
ReadWriteEditBash(curl:*)
Clay Rate LimitsOverviewClay enforces rate limits at the plan level, webhook level, and enrichment provider level. Understanding these limits prevents data loss, credit waste, and integration failures. Prerequisites
InstructionsStep 1: Understand Clay Rate Limit Tiers
Key insight: The 50K webhook submission limit is per-webhook, not per-table. Once exhausted, create a new webhook on the same table. Step 2: Implement Webhook Rate LimitingDesign production Clay enrichment pipelines with table schemas, waterfall patterns, and CRM sync.
ReadWriteEditGrep
Clay Reference ArchitectureOverviewProduction architecture for Clay-based lead enrichment and go-to-market data operations. Covers the three integration patterns (webhook-only, webhook + HTTP API, and full Enterprise API), table schema design, and CRM synchronization flows. Prerequisites
InstructionsStep 1: Choose Your Integration Pattern
Step 2: Design Table SchemaStandard Lead Enrichment Table: Build fault-tolerant Clay integrations with circuit breakers, dead letter queues, and graceful degradation.
ReadWriteEditBash(curl:*)
Clay Reliability PatternsOverviewProduction reliability patterns for Clay data enrichment pipelines. Clay's async enrichment model, credit-based billing, and dependency on 150+ external data providers require specific resilience strategies: credit budget circuit breakers, webhook delivery tracking, dead letter queues for failed batches, and graceful degradation when Clay is unavailable. Prerequisites
InstructionsStep 1: Credit Budget Circuit BreakerStop processing when credit burn exceeds budget to prevent runaway costs:
Step 2: Dead Letter Queue for Failed SubmissionsApply production-ready patterns for integrating with Clay via webhooks and HTTP API.
ReadWriteEditBash(npm:*)Bash(node:*)
Clay Integration PatternsOverviewProduction-ready patterns for Clay integrations. Clay does not have an official SDK -- you interact via webhooks (inbound), HTTP API enrichment columns (outbound from Clay), and the Enterprise API (programmatic lookups). These patterns wrap those interfaces into reliable, reusable code. Prerequisites
InstructionsStep 1: Create a Clay Webhook Client (TypeScript)Apply Clay security best practices for API keys, webhook secrets, and data access control.
ReadWriteEditGrep
Clay Security BasicsOverviewSecurity best practices for Clay integrations covering API key management, webhook endpoint security, provider credential isolation, and lead data protection. Clay handles sensitive PII (emails, phone numbers, LinkedIn profiles) at scale, making security critical. Prerequisites
InstructionsStep 1: Secure API Key Storage
For production, use your platform's secrets manager:
Step 2: Authenticate Incoming Webhook CallbacksWhen Clay's HTTP API columns call your endpoint, validate the request origin:
Step 3: Isolate Provider API KeysConnect provider keys directly in Clay (Settings > Connections) rather than passing them through your application. This keeps provider credentials out of your codebase:
|