Skip to main content
Technology & EngineeringAutomation Workflow Services192 lines

Zapier

Integrate with the Zapier Platform API to build triggers, actions, and multi-step Zaps programmatically.

Quick Summary15 lines
You are an expert in the Zapier Platform CLI and REST API, building custom integrations, webhook-driven automations, and multi-step Zaps with code steps and dynamic fields.

## Key Points

1. **Missing `id` on trigger records** - Zapier deduplicates by `id`. Omitting it causes repeated triggers or missed events.
2. **Hardcoding API versions in URLs** - Pin versions in config, not scattered across request URLs. Use `bundle.authData` or constants.
3. **Ignoring `bundle.meta.isLoadingSample`** - During Zap setup, Zapier fetches sample data. Respect this flag to avoid side effects in triggers.
4. **Returning unbounded result sets** - Always limit polling trigger results to the most recent 100 items, sorted newest-first.
- Connecting two SaaS apps with no native integration and needing a production-grade bridge
- Building a public Zapier integration for your product's marketplace listing
- Automating internal ops workflows where non-developers need to configure triggers and actions
- Prototyping event-driven data pipelines before committing to a custom solution
- Creating multi-step approval flows that span email, Slack, CRM, and databases
skilldb get automation-workflow-services-skills/ZapierFull skill: 192 lines
Paste into your CLAUDE.md or agent config

Zapier Platform Integration

You are an expert in the Zapier Platform CLI and REST API, building custom integrations, webhook-driven automations, and multi-step Zaps with code steps and dynamic fields.

Core Philosophy

Event-Driven Automation

Zapier operates on a trigger-action model. Every Zap starts with a trigger event and chains one or more actions. Design integrations around discrete events rather than polling loops when possible. Use REST hooks for real-time responsiveness.

Data Mapping Discipline

Fields flow between steps via predictable key-value pairs. Always define explicit input/output fields with human-readable labels, help text, and sample data. Never rely on implicit field discovery in production integrations.

Idempotent Operations

Zapier may replay triggers during testing or error recovery. Every trigger must return a unique id field per record. Actions should be safe to retry without creating duplicate resources.

Setup

# Install Zapier Platform CLI
npm install -g zapier-platform-cli

# Initialize a new integration project
zapier init my-integration --template=typescript
cd my-integration
npm install

# Authenticate with Zapier
zapier login

# Key dependencies in package.json
npm install zapier-platform-core@latest
// index.ts - App definition entry point
import { version as platformVersion } from "zapier-platform-core";

const App = {
  version: require("./package.json").version,
  platformVersion,
  authentication: SessionAuth,
  triggers: { [newRecord.key]: newRecord },
  creates: { [createRecord.key]: createRecord },
  searches: { [findRecord.key]: findRecord },
};

export default App;

Key Patterns

Use REST Hooks Over Polling

// Do: Subscribe to webhooks for real-time triggers
const subscribeHook = async (z: ZObject, bundle: Bundle) => {
  const response = await z.request({
    url: "https://api.example.com/webhooks",
    method: "POST",
    body: { target_url: bundle.targetUrl, event: "record.created" },
  });
  return response.data;
};

// Don't: Poll an endpoint every 5 minutes when webhooks are available
const polling = async (z: ZObject, bundle: Bundle) => {
  const response = await z.request({ url: "https://api.example.com/records" });
  return response.data; // No dedup guarantee, high latency
};

Define Explicit Output Fields

// Do: Declare output fields with labels and types
const outputFields = [
  { key: "id", label: "Record ID", type: "integer" },
  { key: "email", label: "Email Address", type: "string" },
  { key: "created_at", label: "Created At", type: "datetime" },
];

// Don't: Return raw API responses without field definitions

Handle Authentication Refresh

// Do: Implement session auth with automatic refresh
const sessionAuth = {
  type: "session" as const,
  test: { url: "https://api.example.com/me" },
  sessionConfig: {
    perform: async (z: ZObject, bundle: Bundle) => {
      const resp = await z.request({
        url: "https://api.example.com/auth/token",
        method: "POST",
        body: { api_key: bundle.authData.apiKey },
      });
      return { sessionKey: resp.data.token };
    },
  },
};

Common Patterns

Custom Trigger with Deduplication

const newOrder = {
  key: "new_order",
  noun: "Order",
  display: { label: "New Order", description: "Triggers when a new order is created." },
  operation: {
    type: "hook" as const,
    performSubscribe: subscribeHook,
    performUnsubscribe: unsubscribeHook,
    perform: async (z: ZObject, bundle: Bundle) => [bundle.cleanedRequest],
    performList: async (z: ZObject, bundle: Bundle) => {
      const resp = await z.request({ url: "https://api.example.com/orders?limit=5" });
      return resp.data.orders;
    },
    sample: { id: "ord_123", total: 49.99, status: "paid" },
    outputFields: [
      { key: "id", label: "Order ID" },
      { key: "total", label: "Total", type: "number" },
    ],
  },
};

Code Step in a Zap

// Zapier Code by Python or JavaScript step
// Available: inputData object, fetch for HTTP, z.console for logging
const output = [];
const response = await fetch(
  `https://api.example.com/users/${inputData.userId}`
);
const user = await response.json();
output.push({ name: user.name, email: user.email });
return output;

Dynamic Dropdown Fields

const listProjects = {
  key: "list_projects",
  noun: "Project",
  display: { label: "List Projects", hidden: true },
  operation: {
    perform: async (z: ZObject, bundle: Bundle) => {
      const resp = await z.request({ url: "https://api.example.com/projects" });
      return resp.data.map((p: any) => ({ id: p.id, label: p.name }));
    },
  },
};

// Reference in an action's inputFields
const inputFields = [
  { key: "project_id", label: "Project", dynamic: "list_projects.id.label", required: true },
];

Search-or-Create Pattern

const findOrCreateContact = {
  key: "find_or_create_contact",
  display: { label: "Find or Create Contact" },
  search: "find_contact",
  create: "create_contact",
};

Anti-Patterns

  1. Missing id on trigger records - Zapier deduplicates by id. Omitting it causes repeated triggers or missed events.
  2. Hardcoding API versions in URLs - Pin versions in config, not scattered across request URLs. Use bundle.authData or constants.
  3. Ignoring bundle.meta.isLoadingSample - During Zap setup, Zapier fetches sample data. Respect this flag to avoid side effects in triggers.
  4. Returning unbounded result sets - Always limit polling trigger results to the most recent 100 items, sorted newest-first.

When to Use

  • Connecting two SaaS apps with no native integration and needing a production-grade bridge
  • Building a public Zapier integration for your product's marketplace listing
  • Automating internal ops workflows where non-developers need to configure triggers and actions
  • Prototyping event-driven data pipelines before committing to a custom solution
  • Creating multi-step approval flows that span email, Slack, CRM, and databases

Install this skill directly: skilldb add automation-workflow-services-skills

Get CLI access →