Skip to main content
For usage details, see the API Reference and CLI Reference.

0.85.0

  • Paginated list results now expose .pages(), a plain async iterable over pages. Unlike iterating the result directly (which still works but is deprecated), .pages() is not also a promise, so returning it from an async function no longer silently collapses it to the first page. .items() is unchanged and remains the way to iterate individual items across pages. The toIterable() helper is deprecated in favor of .pages() and now logs a deprecation warning.

0.84.4

  • Added a slug field (e.g. "google-sheets") to connection items returned by getConnection, listConnections, findFirstConnection, and findUniqueConnection (and their deprecated listAuthentications / getAuthentication / findFirstAuthentication / findUniqueAuthentication aliases).

0.84.3

  • Dynamic parameter pickers now resume from the pagination cursor on “Load more…” instead of re-fetching the first page. This fixes duplicate items and never-ending lists in the table picker and other paginated pickers. The table picker also notes when shared tables are hidden for the account (the connections picker already did), instead of silently showing fewer tables.

0.84.2

  • This release contains no user-facing changes.

0.84.1

  • Internal refactor of how item-returning methods produce their { data } response envelope. No change to the SDK surface.

0.84.0

  • Code Substrate methods now use the /code-substrate-runner and /code-substrate-workflows API path prefixes across the SDK, the CLI, and the MCP server, and sdk.context.api and the CLI curl command accept paths built on them. The previous /sdkdurableapi and /durableworkflowzaps prefixes remain supported.

0.83.3

  • The app version field is now optional in .zapierrc manifest entries. A versionless entry resolves to the latest implementation at runtime. The CLI’s build-manifest and add commands no longer error when an app has no version, writing a versionless entry instead.

0.83.2

  • This release contains no user-facing changes.

0.83.1

  • getWorkflow and listWorkflows now include a nullable details field on each trigger (e.g. webhook_url for catch-hook triggers). Also corrected the trigger_url field description to note that requests must also be authenticated as the account.

0.83.0

  • createZapierSdk(options) is unchanged in usage; the SDK is now built entirely on the module plugin system internally.
    • Deprecated SDK methods now log a runtime warning when called (once per process).
    • New: disposeSdk(sdk) releases the SDK’s resources (telemetry timers, event listeners) — call it when you’re done with an SDK in a long-lived process.
    • New for plugin authors: zapierSdkPlugin (the SDK’s root plugin), PluginSurface<typeof plugin> (derive a plugin’s surface type instead of hand-writing it), resolvePlugin, declareOptionalProperty, SDK_OPTIONS_ID / sdkOptionsPluginRef, explicit MethodPlugin / PropertyPlugin / AggregatePlugin descriptor types, the PluginSummary / LeafSummary ledger types and EventTransport (so a package exporting plugins can emit their inferred types in declarations), and createController with its Controller* types.
    Changed: getConnection now requires a connection locator — connection (or a deprecated connectionId / authenticationId alias) must be provided. It was previously optional in the type, with nothing sensible to fetch when omitted. Removed without a deprecation cycle (pre-1.0 break):
    • createZapierSdkStack, createOptionsPlugin, createZapierCoreStack — use createZapierSdk(options), or compose module plugins with createSdk.
    • dangerousContextPlugin — import the specific plugin ref you need (apiPluginRef, sdkOptionsPluginRef, …), or use resolvePlugin on a built sdk.
    • The authenticationIdResolver / authenticationIdGenericResolver aliases — use connectionIdResolver / connectionIdGenericResolver.
    Changed: the exported resolvers (appKeyResolver, connectionIdResolver, inputsResolver, …) are now model resolvers — bag-form callbacks whose imports bind at build — instead of objects with fetch(sdk, params) callbacks. Attach them through a defineMethod’s resolvers map; they no longer work on a legacy function plugin’s meta.resolvers.

0.82.1

  • .zapierrc manifest parsing now validates each entry independently, so a single malformed entry no longer discards the entire manifest. Previously one invalid apps entry caused the whole manifest, including a valid connections map, to be dropped, which could surface as a misleading “connection not found” error. Invalid entries are now dropped individually with a warning identifying the section and key.

0.82.0

  • Graduated Triggers and Trigger Inbox methods from the experimental interface to the stable one. Every trigger method (listTriggers, listTriggerInputFields, createTriggerInbox, ensureTriggerInbox, drainTriggerInbox, watchTriggerInbox, the inbox lifecycle methods, and the message lease/ack/release methods) is now available directly from @zapier/zapier-sdk and the zapier-sdk CLI — no /experimental import, --experimental flag, or ZAPIER_EXPERIMENTAL env var required. On the default MCP server the request/response trigger tools (create-trigger-inbox, list-triggers, the lease/ack/release tools, etc.) are now listed; the callback-driven drainTriggerInbox and watchTriggerInbox remain SDK/CLI-only. They stay available via the experimental subpath and zapier-sdk-experimental binary for backward compatibility.

0.81.1

  • Added --callback-url to zapier-sdk login and zapier-sdk signup for resuming pending non-interactive OAuth flows. Non-interactive login and signup now save pending state and exit immediately; run the same command later with --callback-url <url> to complete authentication from the browser callback URL. Login and signup telemetry now includes used_non_interactive_mode and is_headless on CLI command and auth lifecycle events.

0.81.0

  • Deprecated name in favor of key for trigger inboxes. name continues to work as a deprecated alias.
    • createTriggerInbox now accepts an optional key parameter; name is deprecated.
    • ensureTriggerInbox now takes key as its required idempotency identifier; passing name still works but is deprecated.
    • listTriggerInboxes now accepts a key filter; the name filter is deprecated.
    • Trigger inbox locators (the inbox argument on getTriggerInbox, updateTriggerInbox, and related methods) now resolve non-UUID values by key.
    • Trigger inbox responses now include a key field alongside name (both hold the same value; key may be null when an inbox has no natural key).

0.80.2

  • Decode JSON-string input on triggerWorkflow and runDurable. Their input field is freeform (z.unknown()), which the CLI surfaces as a raw string flag and never JSON-parses, so --input '{"a":1}' reached the API as a string and was double-encoded (server rejected it with expected object, received string). The input is now normalized at the schema boundary: a {/[-leading JSON string is decoded to its value, while objects and scalar strings pass through unchanged. This also fixes programmatic callers passing a JSON string.

0.80.1

  • This release contains no user-facing changes.

0.80.0

  • Add a resolution controller that completes a method’s partial input into a fully validated one, prompting a host only when needed (createController), along with the defineResolver authoring API and cancellation signals (CoreCancelledSignal, isCoreSignal).

0.79.0

  • Display trusted SDK deprecation notices from Zapier API responses. The SDK sniffs zapier-sdk-deprecation-* response headers (never on relay responses), warns once per notice id per process — with no opt-out — and emits an api:deprecation_notice event for wrappers. The CLI additionally renders notices as a boxed stderr warning after command output, and the MCP server attaches them to every tool result so agents relay the warning to users.

0.78.0

  • Removed the deprecated sdk.addPlugin(...) chain method (and the WithAddPlugin type / chain-style no-arg createSdk() doorway). Extend a built SDK with the top-level addPlugin(sdk, plugin) instead.
  • @zapier/zapier-sdk now re-exports the plugin-authoring helpers (createSdk, defineMethod / definePlugin / declareMethod / etc., selectExports, addPlugin). Note createSdk reuses the old doorway’s name but now takes a root plugin, so a stale no-arg createSdk() call is a compile error rather than silent misbehavior.

0.77.2

  • Fixed published type declarations that caused consumer TypeScript builds to fail with Cannot find module for a bundled-only dev dependency. Also fixed stray per-module declarations being published under dist/src.

0.77.1

  • This release contains no user-facing changes.

0.77.0

  • triggerWorkflow (and trigger-workflow) now authenticates with Zapier credentials and runs the workflow as the authenticated account; triggering is limited to workflows that account can access. Changed the triggerWorkflow response shape: The call is unchanged: pass the workflow id and optional input.

0.76.2

  • This release contains no user-facing changes.

0.76.1

  • This release contains no user-facing changes.

0.76.0

  • The ./define durable context types now match @zapier/zapier-durable: awaiting a callback created with timeoutSeconds is typed as resolving a CallbackResult<T>{ status: "delivered"; value; at } or { status: "expired"; at } — instead of the bare payload. The new CallbackResult and CallbackOptionsWithTimeout types are exported; CallbackOptions no longer carries timeoutSeconds, so deadline call sites type against CallbackOptionsWithTimeout.

0.75.0

  • listWorkflowRuns (and list-workflow-runs) no longer return output on list items. Workflow-run lists no longer carry the (potentially large, soon-externalized) run output; fetch a single run’s output via getWorkflowRun / get-workflow-run. Use status (finished/failed) to know when output is available.

0.74.1

  • Surface trigger claim failure reason and workflow disable reason on the experimental getWorkflow / listWorkflows responses (and therefore the get-workflow / list-workflows CLI commands). Each triggers[] entry gains error (the latest claim’s failure reason, present when status is failed), and the workflow gains a top-level disabled_reason (trigger_claim_failed when system-disabled, otherwise null). The two signals stay independent so an enabled workflow with a failed trigger is representable. Both fields are optional.

0.74.0

  • This release contains no user-facing changes.

0.73.1

  • CamelCase the input params on runDurable and publishWorkflowVersion (sourceFiles, zapierDurableVersion, appVersions, and the nested connection / app-version / trigger fields), keeping the old snake_case names as deprecated aliases. Handlers map them back to the snake_case wire body; output fields are unchanged.

0.73.0

  • This release contains no user-facing changes.

0.72.0

  • listWorkflows now paginates. pageSize (follows the SDK default page size; values above 100 are rejected) and cursor are honored in the SDK, and via the list-workflows --page-size/--cursor CLI flags that were previously no-ops. Iterating still returns all workflows; reading a single page now yields at most pageSize results rather than the full list.

0.71.1

  • Rename createWorkflow’s is_private input to private to match runDurable, keeping is_private as a deprecated alias; the wire field stays is_private. Clarify the run-durable connections param description to show the required object shape.

0.71.0

  • Add createConnection and two lower-level building blocks for connecting an app from code, end to end:
    • createConnection({ app, browser?, timeoutMs?, pollIntervalMs? }) — high-level: mints a connection URL, prints it (and opens it in a browser when it’s safe to do so), waits for the user to finish, and returns the new connection. browser is "auto" (default — opens locally, skips CI / SSH / headless Linux), "always", or "never". The URL is always printed, so a skipped or failed open falls back to copy/paste.
    • getConnectionStartUrl({ app }) — low-level: mints a short-lived, signed start URL bound to the current user/account. Returns { url, startedAt, expiresAt, app }.
    • waitForNewConnection({ app, startedAt, timeoutMs?, pollIntervalMs? }) — low-level: polls until a connection for the app created at or after startedAt appears, then returns { id, app, title? }. Throws ZapierTimeoutError after timeoutMs (default 5 minutes).
    createConnection is the right call for most cases. Reach for the two low-level methods when you want to hand off the URL without blocking (call getConnectionStartUrl alone), or do something custom between minting the URL and waiting — email it, post it to Slack, render a QR code — then call waitForNewConnection.
  • Add private-beta support for streaming auto-mode approval review messages and handling terminal failed approvals through the SDK and CLI. Auto mode is only enabled service-side for approved beta users.

0.70.4

  • Response-field additions to experimental workflow and durable-run methods:
    • updateWorkflow, getWorkflow, listWorkflows responses now include is_private, created_by_user_id, and (where applicable) triggers with live claim status.
    • publishWorkflowVersion, getWorkflowVersion, listWorkflowVersions responses now include trigger, connections, and app_versions.
    • runDurable input accepts notifications (webhook subscribers for run lifecycle events).

0.70.3

  • getDurableRun no longer throws when last_error is null on a successful run.

0.70.2

  • listActions now includes private and unlisted apps the caller can access; results remain access-scoped server-side.

0.70.1

  • Workflow and durable-run responses no longer throw a parse error when the server returns unrecognized enum values.

0.70.0

  • watchTriggerInbox now retries transient drain failures (5xx, 429, network blips) indefinitely with bounded backoff instead of rejecting on the first error; it still rejects immediately on fail-fast handler errors, initialization_failure, and permanent HTTP errors. When those retries persist long enough to saturate the backoff, it warns once on stderr (re-armed on recovery) so a stalled watch isn’t silent. New ApiClient.fetchJsonStream (with the JsonSseMessage type): like fetchStream but JSON-parses each frame, surfacing a malformed frame as { parsed: false, data: null, raw } instead of throwing, so one bad frame can’t kill a long-lived stream. A non-ok response still throws the shared ZapierError subclasses before the first frame. Fixed: a fail-fast handler that throws a falsy value (throw undefined) is no longer silently swallowed, and a handler-thrown AbortError now rejects the watch instead of resolving it cleanly.

0.69.3

  • Restored connections, app_versions, and trigger input fields on publishWorkflowVersion (experimental) that were unintentionally dropped in a prior release, leaving workflows unable to bind connection aliases or wire a trigger. Shape: connections as {alias: {connection_id: ...}}, app_versions as {alias: {implementation_name, version?}}, trigger as a nested object with selected_api + action required.

0.69.2

  • Fixed logout so it reliably clears local authentication state even when the server cannot revoke the credential. Previously a failed revocation could abort logout and strand the user with credentials they could not remove. Re-login flows are unaffected; they still surface revocation failures before replacing credentials.

0.69.1

  • Fix paginated list results silently truncating to page 1 when the same result is consumed twice (iterating pages then .items(), .items() then pages, or iterating either one twice). Pages and items are now two views over one page stream, so consuming either drains the other: the second view yields nothing instead of silently replaying page 1. A paginated result is consumed once; call the method again for a fresh result. Awaiting the result to read just the first page is unaffected: it is a repeatable peek that does not start the stream, so awaiting and then iterating still works.

0.69.0

  • Switched watchTriggerInbox from backoff polling to a Server-Sent Events subscription, so it now wakes on near-real-time inbox notifications instead of repeatedly polling for new messages.
    • The maxDrainIntervalSeconds option now controls a periodic safety drain that backstops the SSE stream — guaranteeing forward progress if events are missed or the connection drops — and its default changed from 60 to 300 seconds.
    • Real-time wake-up health is now reported on stderr: a warning when wake-ups pause and the watch falls back to the safety drain, plus transient reconnect notices in debug mode. stdout (including --json NDJSON output) is unaffected.
    • Added a fetchStream method to the API client, along with an exported SseMessage type, for opening Server-Sent Events connections through the standard request pipeline (auth, base URL, 429 retry, approval, and concurrency).

0.68.1

  • This release contains no user-facing changes.

0.68.0

  • Added zapier-sdk signup for browser-based account setup and local SDK credential provisioning.

0.67.0

  • New stack-based composition surface for building on top of the SDK: createZapierSdkStack(options) (from the root and /experimental) returns the unsealed PluginStack that createZapierSdk materializes, and createPluginStack, createCorePlugin, and addPlugin are re-exported from the root. Build by chaining .use(...) and sealing with .toSdk(), or extend a sealed SDK in place with addPlugin(sdk, plugin). The chain-style createSdk().addPlugin(...) pattern is deprecated (now logs a one-time warning) but still works. One behavior change: normalizeError no longer wraps thrown Error subclasses, so a handler’s TypeError or a userland MyAppError bubbles through unchanged and instanceof works again; only non-Error throws get wrapped.
  • Route all debug, diagnostic, and telemetry log output to stderr (console.error) instead of stdout (console.log) across the SDK and CLI packages. The CLI now reserves stdout exclusively for the program’s data payload — command output, JSON envelopes, response bodies — so callers can safely pipe CLI output through jq, > redirect, or JSON.parse even when --debug is on or telemetry/logging flags are enabled. Interactive terminal users see no change since both streams interleave in a TTY.

0.66.0

  • Added triggerWorkflow (experimental) to fire a workflow’s trigger with a user-supplied JSON payload. Only available via @zapier/zapier-sdk/experimental. The workflow id is UUID-validated at the input boundary; trigger endpoint failures (non-2xx, or workflow with no published version) surface as descriptive errors.
  • Limit approval polling waits to at most 5 seconds while preserving the existing generic polling cadence.
  • Route --debug log output to stderr (console.error) instead of stdout (console.log) in auth.ts and api/debug.ts. This restores stdout’s Unix contract — stdout carries only the program’s data payload — so callers can safely pipe CLI output through jq, redirect to a file, or JSON.parse it even when --debug is on. Debug output still appears in CI logs and developer terminals (both streams interleave there).

0.65.0

  • Added listWorkflowRuns, getWorkflowRun, and getTriggerRun (experimental). All three live behind @zapier/zapier-sdk/experimental only — the stable subpath does not surface them. listWorkflowRuns is paginated; getWorkflowRun looks up a run by id; getTriggerRun walks from a trigger id to its associated run, useful immediately after firing a trigger when the caller has the trigger id but not yet the run id. All ID inputs are UUID-validated at the schema boundary. Consumers see any richer fields the server adds without an SDK release.

0.64.0

  • Added publishWorkflowVersion, listWorkflowVersions, and getWorkflowVersion (experimental). All three are registered only in @zapier/zapier-sdk/experimental; the stable subpath does not expose them. listWorkflowVersions is paginated (cursor + pageSize); publishWorkflowVersion takes source_files (filename → contents) plus optional dependencies, zapier_durable_version, and enabled (defaults to true); getWorkflowVersion returns the full version state including source files. Callers see any richer fields the server adds later without an SDK release. All ID inputs are UUID-validated so non-UUID strings fail with a clear schema error.

0.63.0

  • Added runDurable and cancelDurableRun (experimental). Both are registered only in @zapier/zapier-sdk/experimental; the stable subpath does not expose them. runDurable takes source_files (filename → contents) plus optional input/dependencies/zapier_durable_version/connections/app_versions, and a private flag; returns the run ID immediately in initialized status — callers that need terminal status poll via getDurableRun; no built-in polling. cancelDurableRun returns { id, status: "cancelled" } on success, and propagates ZapierNotFoundError (404) and ZapierConflictError (409 — run already terminal) so callers can distinguish those outcomes.

0.62.0

  • Added listDurableRuns and getDurableRun (experimental). Both are registered only in @zapier/zapier-sdk/experimental; the stable subpath does not expose them. listDurableRuns is paginated (cursor + pageSize); getDurableRun returns the full run state with nested execution and operations journal. Callers see any richer fields the server adds later without an SDK release. The run id input is UUID-validated so non-UUID strings fail with a clear schema error.

0.61.0

  • Added createWorkflow, updateWorkflow, enableWorkflow, disableWorkflow, and deleteWorkflow (experimental). All five are registered only in @zapier/zapier-sdk/experimental; the stable subpath does not expose them. deleteWorkflow requires explicit confirmation before the destructive call. The workflow id input is UUID-validated so non-UUID strings fail with a clear schema error. Callers see any richer fields the server adds later without an SDK release.
  • Fix login/logout reliability bugs. Bug fixes:
    • logout now warns and still clears local keychain/registry state when the server returns 401 during revocation (404 is still silently swallowed; 401 is surfaced as a console warning so users know to verify or revoke the credential manually if needed)
    • Re-login no longer fails with “already exists” when a locally-orphaned registry entry has the same name as the desired new credential
    • logout no longer prompts for confirmation before deleting credentials; it always proceeds immediately, which also fixes hangs in non-TTY/CI environments
    Deprecations:
    • --skip-prompts on login and init is deprecated in favour of --non-interactive. The old flag continues to work with a deprecation warning.

0.60.0

  • Added listWorkflows and getWorkflow (experimental). Both are registered only in @zapier/zapier-sdk/experimental; the stable subpath does not expose them. listWorkflows is paginated with pageSize/cursor/maxItems options so callers can iterate via for await (const page of sdk.listWorkflows()) or toIterable(sdk.listWorkflows()).

0.59.0

  • This release contains no user-facing changes.

0.58.0

  • Export eventEmissionPlugin (and its config/cleanup helpers) from the package root so consumers can compose their own SDK with createSdk. The plugin’s existing helpers and types are now exposed via the plugin module itself instead of being re-listed in the SDK index.

0.57.0

  • Added a trash option to listTableRecords and listTableFields for controlling soft-deleted item visibility. Accepts "exclude" (default, active items only), "include" (active and soft-deleted), or "only" (soft-deleted items only).

0.56.2

  • This release contains no user-facing changes.

0.56.1

  • Clarified the releaseOnError option description for drainTriggerInbox and consumeTriggerInbox: errors release the message when the drain finishes, not immediately.

0.56.0

  • Allow opting into approvals during login

0.55.0

  • Add hint?: string | string[] to PromptConfig.choices. The CLI renders it after the choice’s name as dimmed parens; an unset hint with a primitive value auto-renders the value. All built-in resolvers migrate to the new shape, so existing dropdowns get small visual cleanups (dim parens, no ID: prefix, dash converted to parens, em-dash in tableRecordId gone). Plugin authors who embed the value in name (e.g. "Foo (${id})") should drop the embedded parens; the auto-default appends a second otherwise.

0.54.1

  • Add optional name parameter to createTriggerInbox method

0.54.0

  • Add type-to-filter to interactive single-select dropdowns: dynamic resolvers (apps, connections, tables, table records, etc.) and SELECT-format field choices. (Load more...) remains reachable even when a search yields zero matches, so users can pull the next page and try again. Dynamic resolvers also gain an inputType: "search" mode: the CLI prompts for free-form text, hands it to fetch as search, and either short-circuits on a primitive return (exact match) or renders results as a search-filterable dropdown. Empty results expose (Use "foo" as-is) and (Try a different search) so a required parameter can never strand the user. The built-in appKey resolver now uses this mode (getApp for exact match, listApps --search for fallback). DynamicResolver is now a discriminated union of DynamicListResolver and DynamicSearchResolver. Note for plugin authors: the placeholder field is now typed as never on the list variant, so a classic list resolver that was previously setting an unused placeholder will see a TypeScript error. Move it into a search-mode variant (inputType: "search") or drop it — the CLI never read it on list resolvers.

0.53.0

  • Trigger inbox fixes and additions:
    • Send connection_id: null for trigger inboxes without a connection so connection-less apps (e.g. tables) work correctly.
    • Add listTriggers, a read variant of listActions that lists an app’s triggers.
    • Add interactive resolvers to trigger inbox message methods: ackTriggerInboxMessages and releaseTriggerInboxMessages prompt for messages with a multi-select of leased messages; leaseTriggerInboxMessages prompts for leaseLimit and leaseSeconds.
    • CLI: coerce static prompt input to the schema’s underlying type so numeric/boolean fields (e.g. leaseLimit, leaseSeconds) no longer fail Zod validation with “expected number, received string”.

0.52.0

  • Add a configurable concurrency limit so the SDK queues requests beyond maxConcurrentRequests (FIFO) instead of firing them all at once. Default is 200. Configurable via the createZapierSdk({ maxConcurrentRequests }) option or the ZAPIER_MAX_CONCURRENT_REQUESTS env var (the option wins). Pass Infinity to disable. Slots are held across 429 retries (so server backoff isn’t undermined by extra parallelism) but released as soon as response headers arrive — streaming responses (SSE, long-running chunked reads) do not pin a permit for the lifetime of the body. Queued acquires respect AbortSignal. Queued requests emit api:concurrency_wait_start / api:concurrency_wait_end events for diagnostics.

0.51.0

  • Default SDK auth to client credentials
  • Updated the experimental Triggers notice in all three package READMEs to clarify that the feature is in closed beta, with a link to contact us for access.

0.50.0

  • Collapse the approval-flow surface into a single tri-state approvalMode option. What changed:
    • approvalMode is now "disabled" | "poll" | "throw" (was "poll" | "fail").
    • "disabled" is the default. While the approval flow is alpha, callers must opt in explicitly via approvalMode: "poll" or approvalMode: "throw" (or the ZAPIER_APPROVAL_MODE env var). On an approval-required response, "disabled" throws a ZapierApprovalError with status: "approval_required" without creating an approval.
    • The isInteractive SDK option and the ZAPIER_IS_INTERACTIVE env var have been removed. Their role is subsumed by approvalMode: choosing "poll" / "throw" is the explicit opt-in that previously required isInteractive: true.
    • "fail" has been renamed to "throw" (both the option value and the ZAPIER_APPROVAL_MODE env var value). The behavior is unchanged: throw a ZapierApprovalError carrying the approval URL so the caller can surface it.
    • approvalMode, approvalTimeoutMs, and maxApprovalRetries are now part of the public API (no longer marked internal: true).
    There is no back-compat shim. approvalMode: "fail" and isInteractive: <anything> will fail Zod validation up front.

0.49.0

  • Add experimental support for triggers.

0.48.1

  • This release contains no user-facing changes.

0.48.0

  • Adds an extension mechanism that lets the CLI and MCP server load additional plugin packages at runtime. Set ZAPIER_SDK_EXTENSIONS to a comma-separated list of package specifiers, or pass them via the new extensions option — methods they contribute show up automatically as CLI commands and MCP tools, no per-project wiring required. When a plugin tries to register a method, context field, or meta entry that’s already registered by another plugin in the chain, addPlugin now logs a warning and skips the duplicate plugin’s contribution rather than silently overwriting. This catches the common foot-gun of an extension accidentally shadowing a built-in SDK method. Intentional duplicates can be expressed via composePlugins(...), and meta-only overrides (e.g. tagging a built-in method as deprecated) continue to work unchanged.

0.47.1

  • The approval poll_url and approval_url origin checks are now skipped when baseUrl (or ZAPIER_BASE_URL) points at localhost / 127.0.0.1, so local development works without origin validation errors.

0.47.0

  • Add composePlugins(...subPlugins) for bundling N plugins into a single Plugin<TSdk, TProvides> so a consumer can call addPlugin(combined) once. Bag-mode composition: throws on duplicate root keys or duplicate context.meta keys, intersects each sub-plugin’s TSdk requirements, and flows through the existing single-plugin addPlugin without the type-widening an array overload would impose.

0.46.2

  • This release contains no user-facing changes.

0.46.1

  • Removed custom error handlers and added definePlugin, createPluginMethod, and createPaginatedPluginMethod to reduce plugin boilerplate.

0.46.0

  • Rename the client credentials persistence seam from storage to cache and expose the CLI filesystem/keychain adapter as a best-effort cache.

0.45.2

  • Convert API query params from camelCase to snake_case (appKeysapp_keys, pageSizepage_size) to match the updated API contract.

0.45.1

  • This release contains no user-facing changes.

0.45.0

  • registryPlugin is now deprecated, because getRegistry is built into the SDK and added after each plugin is added. Plugins will always be registered; there is no need to call createZapierSdkWithoutRegistry, add custom plugins, and then .addPlugin(registryPlugin). Because of this, createZapierSdkWithoutRegistry is now deprecated, and calling it will still give you an SDK with getRegistry on it. Calling addPlugin(registryPlugin) on that SDK is a no-op.

0.44.0

  • Allow UUID connection IDs in the .zapierrc connections map. ConnectionEntrySchema.connectionId now accepts either a positive integer (legacy form) or a UUID-format string (returned by the Zapier connections API for newer connections).

0.43.0

  • Add an experimental interactive approval flow for policy-gated actions. When an action requires approval, the SDK detects the approval_required response, prompts for approval in interactive sessions, and automatically retries the original request once approved. Non-interactive sessions receive a clear error explaining that approval is required. This flow is experimental and its behavior may change in future releases.

0.42.1

  • Simplify plugin system: plugins now receive sdk as a positional parameter with context at sdk.context. The Plugin type takes 2 generics (input SDK shape, output provides) instead of 3. Context is shallow-frozen to prevent reassignment of top-level properties. createSdk() is now zero-arg; SDK options are injected via createOptionsPlugin(options) through addPlugin like any other state. Plugins that need options declare it as an explicit context dependency. The addPluginOptions second argument to addPlugin has been removed.

0.42.0

  • Support maxTime for SDK fetch & CLI curl - Relay extended timeout

0.41.2

  • Fix connection resolution for no-auth apps

0.41.1

  • formatErrorMessage now renders ZapierRateLimitError details (limit used, time until retry, retry count) instead of just the bare “Rate limited” message. CLI, MCP, and any consumer using formatErrorMessage now surface which rate-limit window tripped and how long until it resets.

0.41.0

  • Prefer public IDs over numeric IDs in responses

0.40.4

  • Replace Node-only imports (timers/promises, os) with browser-safe alternatives and add browser compatibility test suite

0.40.3

  • Connections - Replace isExpired with expired

0.40.2

  • Make sure CLI only shows non-deprecated positional parameters.

0.40.1

Several top-level method options were renamed so flexible resource references use suffix-less names (app instead of appKey, connection instead of connectionId, and so on). The values you pass are the same as before—slugs, implementation keys, versioned IDs, connection aliases, numeric IDs, and other supported forms. The goal is one obvious parameter per resource and less ambiguity between *Key and *Id now that parameters like connection already accept multiple identifier styles.Note: This is not a breaking change. The old parameter names still work; they are deprecated.