> attio-deploy-integration

Deploy Attio integrations to Vercel, Fly.io, Railway, and Cloud Run with proper secrets, health checks, and webhook endpoint configuration. Trigger: "deploy attio", "attio Vercel", "attio production deploy", "attio Cloud Run", "attio Fly.io", "attio Railway".

fetch
$curl "https://skillshub.wtf/jeremylongshore/claude-code-plugins-plus-skills/attio-deploy-integration?format=md"
SKILL.mdattio-deploy-integration

Attio Deploy Integration

Overview

Deploy Attio-powered applications to production platforms. Covers secrets injection, health check endpoints, webhook URL configuration, and platform-specific configurations for the Attio REST API (https://api.attio.com/v2).

Prerequisites

  • Application code tested locally and in CI
  • Production Attio token with minimal scopes
  • Platform CLI installed

Instructions

Step 1: Vercel Deployment

# Add secrets
vercel env add ATTIO_API_KEY production
vercel env add ATTIO_WEBHOOK_SECRET production

# Deploy
vercel --prod
// vercel.json
{
  "env": {
    "ATTIO_API_KEY": "@attio_api_key",
    "ATTIO_WEBHOOK_SECRET": "@attio_webhook_secret"
  },
  "functions": {
    "api/webhooks/attio.ts": {
      "maxDuration": 30
    }
  }
}

Vercel webhook endpoint:

// api/webhooks/attio.ts (Vercel serverless function)
import type { VercelRequest, VercelResponse } from "@vercel/node";
import crypto from "crypto";

export const config = { api: { bodyParser: false } };

export default async function handler(req: VercelRequest, res: VercelResponse) {
  if (req.method !== "POST") return res.status(405).end();

  const chunks: Buffer[] = [];
  for await (const chunk of req) chunks.push(chunk as Buffer);
  const rawBody = Buffer.concat(chunks);

  // Verify webhook signature before processing
  const signature = req.headers["x-attio-signature"] as string;
  const timestamp = req.headers["x-attio-timestamp"] as string;
  if (!verifySignature(rawBody, signature, timestamp)) {
    return res.status(401).json({ error: "Invalid signature" });
  }

  const event = JSON.parse(rawBody.toString());
  // Process async -- return 200 immediately
  res.status(200).json({ received: true });

  // Handle event in background
  await processAttioEvent(event);
}

Step 2: Fly.io Deployment

# fly.toml
app = "my-attio-app"
primary_region = "iad"

[env]
  NODE_ENV = "production"

[http_service]
  internal_port = 3000
  force_https = true
  auto_stop_machines = "suspend"
  auto_start_machines = true

[[http_service.checks]]
  interval = "30s"
  timeout = "5s"
  grace_period = "10s"
  method = "GET"
  path = "/api/health"
# Set secrets
fly secrets set ATTIO_API_KEY=sk_prod_xyz
fly secrets set ATTIO_WEBHOOK_SECRET=whsec_prod_abc

# Deploy
fly deploy

# Verify
fly status
curl -s https://my-attio-app.fly.dev/api/health | jq .

Step 3: Google Cloud Run

# Store secret in Secret Manager
echo -n "sk_prod_xyz" | gcloud secrets create attio-api-key --data-file=-
echo -n "whsec_prod_abc" | gcloud secrets create attio-webhook-secret --data-file=-

# Build and deploy
gcloud builds submit --tag gcr.io/$PROJECT_ID/attio-service

gcloud run deploy attio-service \
  --image gcr.io/$PROJECT_ID/attio-service \
  --region us-central1 \
  --platform managed \
  --set-secrets="ATTIO_API_KEY=attio-api-key:latest,ATTIO_WEBHOOK_SECRET=attio-webhook-secret:latest" \
  --min-instances=1 \
  --max-instances=10 \
  --allow-unauthenticated

Step 4: Health Check Endpoint

Every deployment should include an Attio health check:

// api/health.ts
export async function GET(): Promise<Response> {
  const checks: Record<string, { status: string; latencyMs?: number }> = {};

  // Attio connectivity
  const start = Date.now();
  try {
    const res = await fetch("https://api.attio.com/v2/objects", {
      headers: { Authorization: `Bearer ${process.env.ATTIO_API_KEY}` },
      signal: AbortSignal.timeout(5000),
    });
    checks.attio = {
      status: res.ok ? "healthy" : `error_${res.status}`,
      latencyMs: Date.now() - start,
    };
  } catch {
    checks.attio = { status: "unreachable", latencyMs: Date.now() - start };
  }

  const overall = Object.values(checks).every((c) => c.status === "healthy")
    ? "healthy"
    : "degraded";

  return Response.json({ status: overall, checks, timestamp: new Date().toISOString() });
}

Step 5: Register Webhook URL in Attio

After deploying, register your webhook endpoint via the API:

// scripts/register-webhook.ts
const webhook = await fetch("https://api.attio.com/v2/webhooks", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.ATTIO_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    target_url: "https://my-attio-app.fly.dev/api/webhooks/attio",
    subscriptions: [
      { event_type: "record.created" },
      { event_type: "record.updated" },
      { event_type: "record.deleted" },
      {
        event_type: "list-entry.created",
        filter: { list: { $eq: "sales_pipeline" } },
      },
    ],
  }),
});

const result = await webhook.json();
console.log("Webhook registered:", result.data?.id?.webhook_id);

Step 6: Environment Configuration Pattern

// src/config.ts
interface AppConfig {
  attio: {
    apiKey: string;
    webhookSecret: string;
    baseUrl: string;
  };
  port: number;
  environment: string;
}

export function loadConfig(): AppConfig {
  const env = process.env.NODE_ENV || "development";
  return {
    attio: {
      apiKey: requireEnv("ATTIO_API_KEY"),
      webhookSecret: requireEnv("ATTIO_WEBHOOK_SECRET"),
      baseUrl: "https://api.attio.com/v2",
    },
    port: parseInt(process.env.PORT || "3000", 10),
    environment: env,
  };
}

function requireEnv(key: string): string {
  const val = process.env[key];
  if (!val) throw new Error(`Missing required env: ${key}`);
  return val;
}

Error Handling

IssueCauseSolution
Webhook never firesWrong URL or not registeredVerify with GET /v2/webhooks
401 on health checkToken not injectedCheck platform secrets config
Cold start timeoutAttio API slow on first callSet min-instances=1
Webhook signature failsSecret mismatchVerify secret matches dashboard value
Deploy succeeds, API failsWrong env variable nameCheck exact key name in platform UI

Resources

Next Steps

For webhook event handling, see attio-webhooks-events.

┌ stats

installs/wk0
░░░░░░░░░░
github stars1.7K
██████████
first seenMar 23, 2026
└────────────

┌ repo

jeremylongshore/claude-code-plugins-plus-skills
by jeremylongshore
└────────────