--- name: clay-multi-env-setup description: 'Configure Clay integrations across development, staging, and production environments. Use when setting up per-environment Clay tables, managing webhook URLs per environment, or implementing environment-specific enrichment configurations. Trigger with phrases like "clay environments", "clay staging", "clay dev prod", "clay environment setup", "clay config by env". ' allowed-tools: Read, Write, Edit, Bash(curl:*), Grep version: 1.14.0 license: MIT author: Jeremy Longshore tags: - saas - clay - deployment compatibility: Designed for Claude Code, also compatible with Codex and OpenClaw --- # Clay Multi-Environment Setup ## Overview Configure 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 - Clay account (one workspace can hold multiple tables) - Environment variable management per deployment target - Understanding of Clay table and webhook concepts ## Instructions ### Step 1: Create Per-Environment Tables In Clay, create separate tables for each environment: | Table Name | Environment | Webhook URL | Auto-Enrich | Credit Cap | |------------|-------------|-------------|-------------|------------| | `[DEV] Outbound Leads` | Development | Dev webhook | ON (small batches) | 100 rows | | `[STG] Outbound Leads` | Staging | Staging webhook | ON | 500 rows | | `Outbound Leads` | Production | Prod webhook | ON | 10,000 rows | Each table gets its own webhook URL. Copy each URL to the appropriate environment's secrets. ### Step 2: Environment Configuration ```typescript // src/config/clay.ts — environment-aware Clay configuration interface ClayEnvConfig { webhookUrl: string; apiKey?: string; // Enterprise API (if applicable) maxRowsPerBatch: number; delayBetweenRowsMs: number; enableCRMSync: boolean; tablePrefix: string; } function getClayConfig(): ClayEnvConfig { const env = process.env.NODE_ENV || 'development'; const configs: Record = { development: { webhookUrl: process.env.CLAY_WEBHOOK_URL_DEV!, maxRowsPerBatch: 10, // Small batches to conserve credits delayBetweenRowsMs: 500, // Slow, safe enableCRMSync: false, // Never push dev data to real CRM tablePrefix: '[DEV]', }, staging: { webhookUrl: process.env.CLAY_WEBHOOK_URL_STG!, maxRowsPerBatch: 100, delayBetweenRowsMs: 250, enableCRMSync: false, // Use sandbox CRM if needed tablePrefix: '[STG]', }, production: { webhookUrl: process.env.CLAY_WEBHOOK_URL!, apiKey: process.env.CLAY_API_KEY, maxRowsPerBatch: 1000, delayBetweenRowsMs: 100, enableCRMSync: true, tablePrefix: '', }, }; const config = configs[env]; if (!config) throw new Error(`Unknown environment: ${env}`); if (!config.webhookUrl) throw new Error(`CLAY_WEBHOOK_URL not set for ${env}`); return config; } ``` ### Step 3: Environment Variable Management ```bash # .env.development CLAY_WEBHOOK_URL_DEV=https://app.clay.com/api/v1/webhooks/dev-webhook-id NODE_ENV=development # .env.staging CLAY_WEBHOOK_URL_STG=https://app.clay.com/api/v1/webhooks/stg-webhook-id NODE_ENV=staging # .env.production (never in git — use secrets manager) CLAY_WEBHOOK_URL=https://app.clay.com/api/v1/webhooks/prod-webhook-id CLAY_API_KEY=clay_ent_production_key NODE_ENV=production ``` ```bash # GitHub Actions — per-environment secrets gh secret set CLAY_WEBHOOK_URL_DEV --body "https://app.clay.com/api/v1/webhooks/dev-id" gh secret set CLAY_WEBHOOK_URL_STG --body "https://app.clay.com/api/v1/webhooks/stg-id" gh secret set CLAY_WEBHOOK_URL --body "https://app.clay.com/api/v1/webhooks/prod-id" gh secret set CLAY_API_KEY --body "clay_ent_production_key" ``` ### Step 4: Startup Validation ```typescript // src/config/validate.ts — fail fast if config is wrong import { z } from 'zod'; const ClayConfigSchema = z.object({ webhookUrl: z.string().url().startsWith('https://'), apiKey: z.string().startsWith('clay_ent_').optional(), maxRowsPerBatch: z.number().positive().max(10_000), delayBetweenRowsMs: z.number().min(0), enableCRMSync: z.boolean(), tablePrefix: z.string(), }); export function validateClayConfig(config: unknown) { const result = ClayConfigSchema.safeParse(config); if (!result.success) { console.error('Clay configuration invalid:', result.error.format()); process.exit(1); } console.log(`Clay config validated for ${process.env.NODE_ENV}`); return result.data; } ``` ### Step 5: Environment-Aware Safety Guards ```typescript // src/clay/guards.ts — prevent production data in dev and vice versa function safetyCheck(env: string, rowCount: number): void { if (env === 'development' && rowCount > 50) { throw new Error(`Dev environment: refusing to process ${rowCount} rows (max 50). Use staging or production.`); } if (env === 'staging' && rowCount > 1000) { throw new Error(`Staging environment: refusing to process ${rowCount} rows (max 1000). Use production.`); } } function preventCrossEnvData(env: string, crmPushEnabled: boolean): void { if (env !== 'production' && crmPushEnabled) { throw new Error(`CRM sync is disabled in ${env}. Only production can push to CRM.`); } } ``` ## Error Handling | Issue | Cause | Solution | |-------|-------|----------| | Wrong table receives data | Dev webhook URL in production | Validate webhook URL matches environment | | Dev data in production CRM | CRM sync enabled in dev | Guard CRM sync to production only | | Credit waste in dev/staging | Full enrichment on test data | Set low row caps on dev/staging tables | | Missing webhook URL at startup | Environment variable not set | Add startup validation with Zod | ## Resources - [Clay University -- Table Management Settings](https://university.clay.com/docs/table-management-settings) - [Zod Documentation](https://zod.dev/) ## Next Steps For monitoring and observability, see `clay-observability`.