Claude-code-plugins-plus-skills instantly-deploy-integration
install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/instantly-pack/skills/instantly-deploy-integration" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-skills-instantly-deploy-integration && rm -rf "$T"
manifest:
plugins/saas-packs/instantly-pack/skills/instantly-deploy-integration/SKILL.mdsource content
Instantly Deploy Integration
Overview
Deploy Instantly API v2 integrations — primarily webhook receivers and automation services — to cloud platforms. Instantly webhooks require a public HTTPS endpoint that responds within 30 seconds (3 retries on failure). This skill covers Vercel serverless functions, Google Cloud Run containers, and Fly.io deployments.
Prerequisites
- Completed
setupinstantly-install-auth - Working Instantly integration tested locally (see
)instantly-local-dev-loop - Cloud platform account (Vercel, GCP, or Fly.io)
- Domain or HTTPS URL for webhook endpoint
Instructions
Option A: Vercel Serverless Functions
// api/webhooks/instantly.ts — Vercel serverless function import type { VercelRequest, VercelResponse } from "@vercel/node"; export default async function handler(req: VercelRequest, res: VercelResponse) { if (req.method !== "POST") { return res.status(405).json({ error: "Method not allowed" }); } // Validate webhook secret const secret = req.headers["x-webhook-secret"]; if (secret !== process.env.INSTANTLY_WEBHOOK_SECRET) { return res.status(401).json({ error: "Unauthorized" }); } const { event_type, data } = req.body; // Respond immediately — Instantly expects 2xx within 30s res.status(200).json({ received: true }); // Process event asynchronously try { switch (event_type) { case "reply_received": await syncReplyToCRM(data); break; case "email_bounced": await handleBounce(data); break; case "lead_interested": await notifySalesTeam(data); break; case "lead_unsubscribed": await addToBlockList(data); break; } } catch (err) { console.error(`Webhook processing error: ${event_type}`, err); } } async function addToBlockList(data: { lead_email: string }) { await fetch("https://api.instantly.ai/api/v2/block-lists-entries", { method: "POST", headers: { Authorization: `Bearer ${process.env.INSTANTLY_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ bl_value: data.lead_email }), }); }
# Deploy to Vercel vercel env add INSTANTLY_API_KEY vercel env add INSTANTLY_WEBHOOK_SECRET vercel deploy --prod
Option B: Google Cloud Run
# Dockerfile FROM node:20-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci --production=false COPY . . RUN npm run build FROM node:20-alpine WORKDIR /app COPY --from=builder /app/dist ./dist COPY --from=builder /app/node_modules ./node_modules COPY package*.json ./ EXPOSE 8080 ENV PORT=8080 CMD ["node", "dist/server.js"]
// src/server.ts — Express server for Cloud Run import express from "express"; import { instantly } from "./instantly"; const app = express(); app.use(express.json()); app.get("/health", (_, res) => res.json({ status: "ok" })); app.post("/webhooks/instantly", async (req, res) => { const secret = req.headers["x-webhook-secret"]; if (secret !== process.env.INSTANTLY_WEBHOOK_SECRET) { return res.status(401).json({ error: "Unauthorized" }); } res.status(200).json({ received: true }); const { event_type, data } = req.body; console.log(`Webhook: ${event_type}`, JSON.stringify(data).slice(0, 200)); // Process based on event type if (event_type === "reply_received") { // Update lead interest status await instantly("/leads/update-interest-status", { method: "POST", body: JSON.stringify({ lead_email: data.lead_email, campaign_id: data.campaign_id, interest_value: 1, // Interested }), }); } }); const PORT = process.env.PORT || 8080; app.listen(PORT, () => console.log(`Listening on port ${PORT}`));
set -euo pipefail # Deploy to Cloud Run gcloud run deploy instantly-webhooks \ --source . \ --region us-central1 \ --allow-unauthenticated \ --set-env-vars "INSTANTLY_API_KEY=${INSTANTLY_API_KEY},INSTANTLY_WEBHOOK_SECRET=${INSTANTLY_WEBHOOK_SECRET}" \ --min-instances 1 \ --max-instances 10 \ --memory 256Mi \ --cpu 1
Option C: Fly.io
# fly.toml app = "instantly-webhooks" primary_region = "iad" [build] dockerfile = "Dockerfile" [http_service] internal_port = 8080 force_https = true auto_stop_machines = true auto_start_machines = true min_machines_running = 1 [env] NODE_ENV = "production"
set -euo pipefail fly launch --name instantly-webhooks fly secrets set INSTANTLY_API_KEY="your-key" INSTANTLY_WEBHOOK_SECRET="your-secret" fly deploy
Step 2: Register Webhook After Deployment
async function registerProductionWebhook(deployedUrl: string) { const webhook = await instantly<{ id: string; name: string }>("/webhooks", { method: "POST", body: JSON.stringify({ name: "Production CRM Sync", target_hook_url: `${deployedUrl}/webhooks/instantly`, event_type: "all_events", headers: { "X-Webhook-Secret": process.env.INSTANTLY_WEBHOOK_SECRET, }, }), }); console.log(`Webhook registered: ${webhook.id}`); // Test the webhook await instantly(`/webhooks/${webhook.id}/test`, { method: "POST" }); console.log("Test webhook sent — check your endpoint logs"); }
Step 3: Post-Deploy Verification
set -euo pipefail DEPLOY_URL="https://instantly-webhooks-abc123.run.app" # Health check curl -s ${DEPLOY_URL}/health | jq . # Test webhook endpoint curl -X POST ${DEPLOY_URL}/webhooks/instantly \ -H "Content-Type: application/json" \ -H "X-Webhook-Secret: ${INSTANTLY_WEBHOOK_SECRET}" \ -d '{"event_type":"reply_received","data":{"lead_email":"test@example.com"}}'
Error Handling
| Error | Cause | Solution |
|---|---|---|
| Webhook delivery fails | Endpoint returns non-2xx | Ensure 200 response before async processing |
| Cold start timeout | Serverless function too slow | Set or use always-on |
| Secret not available | Env var not set | Verify with or cloud console |
| Webhook retries flooding | Processing takes >30s | Return 200 immediately, process async |
Resources
Next Steps
For webhook event handling patterns, see
instantly-webhooks-events.