# @zapier/zapier-sdk

## 0.119.0

### Minor Changes

- 253d3e5: The Next Gen Zaps methods (workflows, drafts, versions and runs, such as `listWorkflows`, `createWorkflowDraft`, `runWorkflowDraft` and `getWorkflowRun`) are now beta. Import them from `@zapier/zapier-sdk/beta`. They are still available from `@zapier/zapier-sdk/experimental`, which includes every beta method, so existing imports keep working. Beta changes ship in minor releases with a migration note.
- 253d3e5: Added `runWorkflow` (beta) to run a published workflow and wait for its result. It fires the workflow's trigger, then returns the run as soon as it is finished, failed or cancelled, with `output` set when it finished. A failed run is returned with its `error` rather than thrown. A run still going after `waitSeconds` (default 60) is returned with its current status. If no run has been created by then, it throws `ZapierTimeoutError`; check it later with `getTriggerRun`.

  Added `waitSeconds` to `runWorkflowDraft`, `getTriggerRun` and `getWorkflowRun`. With it, the method returns the run once it ends, or as it stands when the wait runs out, instead of returning at once.

## 0.118.0

### Minor Changes

- 6397776: Added the `idempotencyKey` option to `createActionRun`, `runAction`, and app action calls (`zapier.apps.<app>.<actionType>.<action>(...)`) for retrying an action without running it twice. A run started with a key already used in the last 72 hours returns the original run instead of starting a new one, even if the inputs differ, so use a fresh key for each distinct run. Keys are up to 255 characters. One key covers every page: a run for a later page (a `page` on `createActionRun`, or a later page of `runAction`) is sent with a key derived from yours and the page, so retrying a page replays that page's run.

## 0.117.0

### Minor Changes

- 5e4e5fc: Added `taxonomy`, the SDK's shared vocabulary. It currently holds `taxonomy.categories`, the registry category definitions, so a plugin can join an existing category with the same title and overview. Every category returned by `getRegistry()` now includes a `description`, an overview of what that group of methods is for, and the generated reference opens each section with it.

### Patch Changes

- Updated dependencies [5e4e5fc]
  - @zapier/kitcore@0.22.0

## 0.116.2

### Patch Changes

- 8513d4c: `runAction` and `createActionRun` now look up an app slug that isn't pinned in your `.zapierrc` once instead of twice, removing one API request before the run starts. The app version used for the run is unchanged.

## 0.116.1

### Patch Changes

- 374f7c4: `ZapierActionError` and `ZapierRelayError` now carry a `connectionId` field naming the connection the failed call ran against, when one was used.

## 0.116.0

### Minor Changes

- db3e28a: Added the `idempotencyKey` option to `fetch` for retrying API Proxy requests without repeating side effects.

## 0.115.2

### Patch Changes

- 5bb041a: _This release contains no user-facing changes._

## 0.115.1

### Patch Changes

- 3467793: _This release contains no user-facing changes._

## 0.115.0

### Minor Changes

- c13de58: `runAction` (and other approval-capable calls) now automatically retries with the one-time approval token attached after an approval is granted, instead of requiring a second approval round for the same request. Previously the retry could exhaust `maxApprovalRetries` and throw `max_retries_exceeded` even after the approval had already succeeded.

  Added `"approval_token_invalid"` to the `ApprovalStatus` union, thrown as a `ZapierApprovalError` when a retried request's token was rejected (already used, expired, or no longer valid for the request). This is terminal — a new approval must be requested rather than the same request being retried again.

## 0.114.5

### Patch Changes

- 1726c30: The API reference now describes the `inputs` option of typed app actions (`zapier.apps.<app>.<type>.<action>({ inputs })`), which was listed without a description.

## 0.114.4

### Patch Changes

- ee8028e: `getDurableRun` now accepts `null` for operation date fields (`next_retry_at`, `resume_at`, `expires_at`, `completed_at`) instead of throwing a validation error.
  - Operations now include `timeout_seconds`, the requested callback timeout in seconds.
  - `status` now documents `expired`, for callbacks whose deadline passed without delivery.

## 0.114.3

### Patch Changes

- fe092c8: Errors returned by `fetch` now use the title `Proxy API Error` (previously
  `API Proxy Error`) in `errors[].title`. The error `code`, `statusCode`,
  `retryable`, and `detail` fields are unchanged.

## 0.114.2

### Patch Changes

- 52a887b: Added `meta.id` to successful `runAction` source pages so callers can log the action run ID, including when results are empty. Buffered pages omit the ID when they combine different or unknown source IDs. Existing data and pagination behavior are unchanged.
- Updated dependencies [52a887b]
  - @zapier/kitcore@0.21.3

## 0.114.1

### Patch Changes

- 222dc8a: Describe `runDurable` as taking a complete source-files map rather than "a workflow source file". Send every file the workflow needs, not only its entry point.

## 0.114.0

### Minor Changes

- fdb11e0: `listActions` and `listTriggers` no longer return hidden actions (`is_hidden: true`). These are actions an app has superseded or keeps for internal use, often under the same title as their replacement. `getAction`, `runAction` and the input-field methods still accept a hidden action's key, so code that already runs one keeps working.

## 0.113.0

### Minor Changes

- 1c1a95d: Added `@zapier/zapier-sdk/beta`, a second non-stable import path alongside `@zapier/zapier-sdk/experimental`. Every method now belongs to one of three tiers, chosen by import path, and each tier states what the SDK commits to:

  | Tier             | Import                            | Contract                                                                                                                                                                                                                      |
  | ---------------- | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  | **Stable**       | `@zapier/zapier-sdk`              | The surface we intend to keep. While the SDK is in Open Beta (0.x), a breaking change can still land in a minor release; we deprecate first where we can, and every one is called out in the changelog with a migration note. |
  | **Beta**         | `@zapier/zapier-sdk/beta`         | Functionally complete and ready to build against, but the shape may still change as it settles. Changes land in minor releases with a changelog migration note, without a deprecation period.                                 |
  | **Experimental** | `@zapier/zapier-sdk/experimental` | Still being designed; may change shape or disappear in any release, without notice.                                                                                                                                           |

  A tier is a promise about the SDK surface, not a status report on the service behind it.

  The beta tier ships empty, so `/beta` currently exposes exactly the stable surface. Nothing moved out of `/experimental` — the subpaths nest, so each one includes everything from the tiers below it, and a method can only ever move toward stable.

  The first call to any non-stable method now logs a once-per-process warning naming the tier and quoting its contract:

  ```
  [zapier-sdk] listWorkflows() is marked experimental. Still being designed; may change shape or disappear in any release, without notice.
  ```

### Patch Changes

- Updated dependencies [1c1a95d]
  - @zapier/kitcore@0.21.2

## 0.112.6

### Patch Changes

- 5a62cba: `listApps` no longer throws when a page of results contains an app with no
  recorded age. Such an app failed validation and rejected the whole page rather
  than the single record, so the same call succeeded or failed depending on which
  apps landed on the page. `age_in_days` is now absent for those apps. An app
  returned without a version no longer rejects its page either.

## 0.112.5

### Patch Changes

- 51116a0: Added a `permissions` field to actions returned by `listActions`, `getAction` and `listTriggers`. It passes through every flag the API returns, including `can_use`, which is `false` when an account admin has restricted the action.

## 0.112.4

### Patch Changes

- e158b76: List methods now hand back a `nextCursor` that advances even when the endpoint
  returns a bigger page than your `pageSize` asked for. Pass each `nextCursor`
  back in and the loop reaches the end of the list.
- Updated dependencies [e158b76]
  - @zapier/kitcore@0.21.1

## 0.112.3

### Patch Changes

- 975efb9: The experimental agentic management methods (`enableAgenticManagement`,
  `disableAgenticManagement`, `getAgenticManagementConfig`,
  `updateAgenticManagementConfig`, `getAgenticManagementIntent`, and
  `updateAgenticManagementIntent`) now work for any account.

## 0.112.2

### Patch Changes

- 0318d77: _This release contains no user-facing changes._

## 0.112.1

### Patch Changes

- 218c461: Added an `is_managed` field to the connections returned by `listConnections`. It indicates whether a connection is managed by account admins (no individual owner) rather than owned by an individual user.

## 0.112.0

### Minor Changes

- 2102c00: **Removed the legacy function-plugin surface.** A plugin is now always a
  descriptor built by `define*` / `declare*`, never a `(sdk) => provides`
  function. These exports shipped deprecated with runtime warnings and are now
  gone:

  | Removed                                              | Use instead                                                             |
  | ---------------------------------------------------- | ----------------------------------------------------------------------- |
  | `createPluginStack`, `composePlugins`                | `definePlugin({ name, exports })` and `createSdk(root)`                 |
  | `createPluginMethod`, `createPaginatedPluginMethod`  | `defineMethod({ output: "item" })` / `defineMethod({ output: "list" })` |
  | `createCorePlugin(options)`                          | `createSdk(root, { configuration: { [CORE_OPTIONS_ID]: options } })`    |
  | `fromFunctionPlugin`, `defineLegacyMerge`            | `createSdk(root)` on a descriptor root                                  |
  | `definePlugin(fn)` (the function form)               | `defineMethod` / `defineProperty` / `definePlugin({ ... })`             |
  | `registryPlugin`                                     | nothing: `createZapierSdk` already surfaces `getRegistry`               |
  | `Plugin<TSdk, TProvides>` (the function-plugin type) | `Plugin` now names the descriptor a `define*` call returns              |
  | `PluginProvides` type                                | `PluginSurface<typeof plugin>` for a plugin's own surface               |
  | `OutputFormatter` type                               | `defineFormatter`, whose result is a `Formatter`                        |

  Also removed, with no deprecation warning: `createFunction` and
  `createPaginatedFunction`. Only a function plugin could use their output. Author
  with `defineMethod({ output: "item" })` or `defineMethod({ output: "list" })`
  instead.
  - `addPlugin(sdk, plugin)` refuses a function argument.
  - `sdk.context.meta` is gone. Read `sdk.getRegistry()` instead.
  - `sdk.context` has no index signature, so `sdk.context.anything` no longer
    typechecks.

  `sdk.getRegistry()` is unchanged.

  Added `getRegistry(sdk, packageFilter?)`, a free function that reads the same
  registry without the accessor being on the surface, and its `RegistryResult`
  type. Added `formatExtensionPluginFailure(error)`, the message a host shows when
  `addPlugin` refuses an extension. Re-exported `Plugin` from kitcore, the type of any `define*` result.

  Re-exported `MethodMeta` and `PropertyMeta`, the description fields a method
  or a property carries. `PluginMeta` stays as a deprecated alias of `MethodMeta`,
  now an exact field list with no index signature, so a `satisfies
Partial<PluginMeta>` that sets a field outside it no longer compiles.

### Patch Changes

- Updated dependencies [2102c00]
  - @zapier/kitcore@0.21.0

## 0.111.2

### Patch Changes

- 0535d52: Approval-flow requests now use an updated internal endpoint. No caller-visible behavior has changed.

## 0.111.1

### Patch Changes

- 79b9be9: _This release contains no user-facing changes._

## 0.111.0

### Minor Changes

- 604bf7d: Added `"dismissed"` to the exported `ApprovalStatus` union. Approval polls that encounter a dismissed request now throw a `ZapierApprovalError` with `approvalStatus: "dismissed"` and emit an `approval:dismissed` event, instead of failing with an unparseable-response error. `dismissed` is terminal and does not grant access.

## 0.110.2

### Patch Changes

- 545562b: Experimental `createWorkflow` now supports optional creation-attribution metadata. Created, retrieved, and listed workflows retain attribution returned by the server.

## 0.110.1

### Patch Changes

- 58bd3f7: `listApps` and `getApp` now surface API errors as they are returned:
  - Status codes and messages are preserved. Previously, some 4xx messages were
    replaced with generic text and some 5xx responses were reported as generic
    502 errors.
  - A malformed response now throws `ZapierValidationError` instead of a generic
    `TypeError`.

## 0.110.0

### Minor Changes

- f8637ed: Added `runWorkflowDraft` (experimental), exposed in the CLI as `run-workflow-draft`. Launches a draft test run: executes a workflow draft's current source without publishing it.
  - Pass `workflow`, `draft`, and `draftRevision` (from the last read of the draft). The run is rejected with a conflict error if the draft changed since. In interactive CLI use, `draftRevision` resolves via a picker that reads the draft's current revision, so it never has to be typed by hand.
  - Optionally pass `input` for workflows that take input.
  - Draft runs are free (not task-charged) and rate limited per user.
  - The run is accepted asynchronously and returned with `kind: "draft"` and status `initialized`; follow it with `getWorkflowRun`, or list draft runs via `listWorkflowRuns` with `kind: "draft"`.

- f8637ed: Workflow runs now carry a `kind` discriminator (`"live"` or `"draft"`), and `listWorkflowRuns` (CLI: `list-workflow-runs`) accepts a `kind` filter — omit it for both kinds interleaved by recency. The `getWorkflowRun` and `listWorkflowRuns` response schemas are discriminated unions on `kind`, so TypeScript narrows kind-specific fields after a `run.kind === "draft"` check, and each kind carries only its own fields:

  | Kind    | Fields                                                      |
  | ------- | ----------------------------------------------------------- |
  | `live`  | `trigger_id`, `workflow_version_id` (absent on draft runs)  |
  | `draft` | `workflow_draft_id`, `draft_revision` (absent on live runs) |

  This also fixes `listWorkflowRuns` rejecting responses for workflows that have draft runs: draft rows omit the live-only fields, which the previous response schema treated as required.

  `getWorkflowRun` responses now also include `workflow_id` (always returned by the API, previously stripped by the SDK's response schema).

## 0.109.1

### Patch Changes

- c970d16: Corrected the draft `slug` descriptions: slugs are no longer unique among a workflow's open drafts, and the `listWorkflowDrafts` `slug` filter can return more than one draft. Documentation only — no behaviour change. These descriptions surface as MCP tool schemas, so agents were previously told the filter returns at most one match.

## 0.109.0

### Minor Changes

- f56765a: Deprecated `createZapierApi` and `getOrCreateApiClient` in favor of building an SDK with `createSdk` and accessing `apiPluginRef` with `resolvePlugin`. Both functions continue to work with a once-per-process warning.

### Patch Changes

- f56765a: `createZapierSdk({ cache })` now uses the caller-supplied cache for client-credentials access tokens instead of silently falling back to the default cache (the CLI's filesystem and keychain cache when installed, otherwise in-memory).

## 0.108.1

### Patch Changes

- 47a61ba: `listConnections` and `waitForNewConnection` now:
  - Raise a `ZapierValidationError` (`ZAPIER_VALIDATION_ERROR`) when a response or
    connection row doesn't match the expected shape; previously the list path
    did not validate rows. `waitForNewConnection` surfaces it on the first
    malformed successful response — any number of pending responses may precede
    it — rather than after exhausting its poll retries.
  - Preserve error status codes and messages. Previously, some 4xx messages were
    replaced with generic text and some 5xx responses were reported as generic
    502 errors.
  - Match an `app` filter with an explicit version (e.g. `"github@1.2.3"`) even
    when it can't be resolved through the manifest, instead of failing to match
    anything.

  `waitForNewConnection` now checks the most recently created connection.
  Previously the row it checked was not the newest, so it could keep waiting past
  a connection that had already been created, or settle on a different one.

  `ApiClient.poll` now propagates a throw from a caller's `isPending` or
  `resultExtractor` unchanged and stops polling, instead of retrying it three
  times and rebranding it as a JSON parse failure. Return `true` from `isPending`
  to keep polling; throw only to abandon the poll. An unreadable response body
  still retries, now reported as "Poll response body was not valid JSON".
  Consecutive HTTP error responses that exhaust polling retries now preserve
  the upstream status code and are no longer counted and wrapped twice.

  Output is unchanged for conforming responses.

## 0.108.0

### Minor Changes

- cd1cafb: Added nine experimental Virtual File System (VFS) methods to `@zapier/zapier-sdk/experimental` for reading and managing a user's stored files and directories: `readVfsFile`, `writeVfsFile`, `appendVfsFile`, `copyVfsFile`, `listVfsDirectory`, `createVfsDirectory`, `statVfsPath`, `deleteVfsPath`, and `moveVfsPath`.

  Paths are absolute and must start with `/`. A missing path throws `ZapierResourceNotFoundError`; a policy denial throws `ZapierAuthenticationError`.

## 0.107.2

### Patch Changes

- 48996ac: _This release contains no user-facing changes._

## 0.107.1

### Patch Changes

- 274d411: `getConnection` now:
  - Raises a `ZapierValidationError` (`ZAPIER_VALIDATION_ERROR`) when the response
    does not match the connection schema; previously some malformed responses
    surfaced as `ZapierApiError`.
  - Preserves error status codes and messages. Previously, some 4xx messages were
    replaced with generic text and some 5xx responses were reported as generic
    502 errors.

  Output is unchanged for conforming responses.

## 0.107.0

### Minor Changes

- 17927b2: Added six experimental methods for putting a workflow under agentic management,
  available from `@zapier/zapier-sdk/experimental`:
  - `enableAgenticManagement` / `disableAgenticManagement` — turn management on or
    off for one workflow. Disabling keeps the workflow's settings rather than
    deleting them, so enabling it again resumes with the modes and approval choice
    it had before.
  - `getAgenticManagementConfig` / `updateAgenticManagementConfig` — read or change
    the modes a workflow runs and whether fixes need approval. A `modes` list
    replaces the whole current set in one step rather than adding to it; omit it to
    change only the approval setting.
  - `getAgenticManagementIntent` / `updateAgenticManagementIntent` — read or record
    what a workflow version is meant to do. Each version stores its own intent and
    never picks up another version's, so a newly published version starts with
    none.

  These operate on the same workflow `getWorkflow` and `listWorkflows` return, so
  `workflow` accepts the id from either, and the methods resolve it the way the
  other workflow methods do.

  A workflow runs one or more modes — `heal`, `expand`, or `harden` — each
  described on the `modes` parameter. `autoApprove` decides whether proposed fixes
  are applied without prompting. Omit it and they are: a first enable applies
  fixes without asking, and an update leaves the setting alone — so `false` is a
  distinct third state rather than the same as leaving it out.

## 0.106.0

### Minor Changes

- 4b9d735: Callers who use the SDK's own methods rather than authoring plugins are
  unaffected by everything below.

  `createSdk` now checks that a plugin declared by id is satisfied by a provider
  whose types match, not only that some provider exists. Building a graph from
  `declareMethod` / `declareProperty` references and `defineMethod` /
  `defineProperty` providers used to compile on the strength of the id string
  alone, so a provider that contradicted the reference reached the consumer and
  broke at runtime.

  ```ts
  const doubleRef = declareMethod<"double", { value: number }, number>({
    id: "double",
  });
  // Written for a display surface: it formats instead of computing.
  const formatsIt = defineMethod({
    name: "double",
    run: ({ input }: { input: { value: number } }) => `${input.value * 2}`,
  });
  // Compiled clean before. Rejected at createSdk now.
  ```

  A provider may accept **wider** input and must return a **subtype** of the
  declared output, since the comparison is on the call a consumer makes. **This
  can surface an error in a graph that compiled before**, which is the point:
  correct the provider, or widen the reference to what the provider offers.

  Added `ContractEntry`, `MethodContract`, `DeclarationSummary`, and
  `OptionalDeclarationSummary`, for annotating a plugin by hand instead of letting
  `define*` infer it. If you already annotate one, update it: `LeafSummary` now
  requires the surfaced binding as a fourth argument, and a two-argument
  `PluginSummary` still compiles while declaring no contract, which drops that
  plugin out of the check silently.

### Patch Changes

- Updated dependencies [4b9d735]
  - @zapier/kitcore@0.20.0

## 0.105.0

### Minor Changes

- ef3540d: Added `correlationId` and `causationId` options on `createZapierSdk`, matching
  `--correlation-id` and `--causation-id` CLI flags, and the `ZAPIER_CORRELATION_ID`
  and `ZAPIER_CAUSATION_ID` environment variables. When set, they are emitted as
  `zapier-correlation-id` and `zapier-causation-id` headers on every outbound
  Zapier API request. Precedence for both ids is: explicit option, then
  environment variable, and for correlation the SDK falls back to its per-call
  id so requests still carry a trace identifier. Precedence is: explicit option,
  then environment variable. Empty strings at either layer are treated as unset.

## 0.104.0

### Minor Changes

- 1ec9410: SDK HTTP requests now automatically retry HTTP 500, 502, 503, and 504 responses for idempotent methods; HTTP 429 responses continue to retry for any method. All retryable responses share the budget set by `maxNetworkRetries`, with exponential backoff capped by `maxNetworkRetryDelaySeconds`; set `maxNetworkRetries: 0` to disable retries. Callers that pass a custom `sendHttpRequest` transport to `createZapierApi` remain responsible for its retry behavior.

### Patch Changes

- Updated dependencies [1ec9410]
- Updated dependencies [1ec9410]
  - @zapier/kitcore@0.19.0

## 0.103.0

### Minor Changes

- 8ab4e96: _This release contains no user-facing changes._

## 0.102.4

### Patch Changes

- 2c8ea56: _This release contains no user-facing changes._
- Updated dependencies [2c8ea56]
  - @zapier/kitcore@0.18.0

## 0.102.3

### Patch Changes

- 4a51b07: Added `editor_url` to the experimental create, get, list, update, and import workflow responses in the SDK and CLI.

## 0.102.2

### Patch Changes

- b6dfdf9: `runDurable`, `publishWorkflowVersion` and `updateWorkflowDraft` document that `"latest"` is accepted for the durable runtime version and, in `dependencies`, for `@zapier/zapier-durable` and `@zapier/zapier-sdk`. The server resolves those to the newest release old enough to install — not npm's `"latest"` tag, which can point at a release too new to install. A `"latest"` on any other package is passed to the install unchanged. On a draft the value is stored verbatim and resolved when the draft is published.

## 0.102.1

### Patch Changes

- 173df80: `ZapierRateLimitError` now surfaces the server's explanatory message — quota used, when the window resets, and how to request a higher limit — instead of the bare string "Rate limited". When the response body is empty or unreadable, the message falls back to "Rate limited" as before.

  `rateLimit.resetMs` on the error is now a real epoch timestamp when the server sends `X-RateLimit-Reset` as seconds-until-reset (the IETF draft convention) instead of a date in 1970. This also fixes the retry delay computed from that header when `Retry-After` is absent, which previously collapsed to zero and retried immediately.

- Updated dependencies [173df80]
  - @zapier/kitcore@0.17.2

## 0.102.0

### Minor Changes

- 52b672a: `@zapier/zapier-sdk` now installs `@zapier/kitcore` as a regular dependency instead of bundling a copy of it into its own build. Package managers pull it in automatically, so installs and imports keep working unchanged.

  Three things this affects:
  - Plugin, resolver, and formatter authors can import `definePlugin`, `defineMethod`, `createSdk`, and the rest from `@zapier/kitcore` directly, and those names stay re-exported from `@zapier/zapier-sdk`. To import it directly, add `@zapier/kitcore` to your own dependencies at the version `@zapier/zapier-sdk` depends on, because pnpm and Yarn PnP won't resolve an undeclared package, and a different version resolves to a second copy. Given a single resolved copy, the two import paths are the same module; across a duplicate install or a CJS/ESM split they aren't, so keep using the brand-based guards, `isCoreError` and `isCoreSignal`, for checks that have to survive that.
  - If you **publish** a package that exports a plugin, its declarations decide whether you need `@zapier/kitcore` in your own dependencies. Left to inference, a `define*` result's type resolves to where kitcore declares it, so your published types name `@zapier/kitcore` and it has to be installable for anyone consuming them. Annotating the export with `MethodPlugin` and `LeafSummary` from `@zapier/zapier-sdk` keeps the reference on the SDK instead, and no kitcore dependency is required. Calling SDK methods, using its schemas, or building plugins you don't publish types for needs nothing either way.
  - Browser bundlers pick up the `node:async_hooks` stub from `@zapier/kitcore`'s own `browser` field rather than `@zapier/zapier-sdk`'s. A bundler config that hand-aliased that import through `@zapier/zapier-sdk` may need updating.

### Patch Changes

- Updated dependencies [52b672a]
  - @zapier/kitcore@0.17.1

## 0.101.2

### Patch Changes

- 6bfea6d: Clarified that `pageSize` on `listConnections`, `listAuthentications`, and `listApps` may be capped by the upstream API — values above its limit are rejected rather than forwarded unbounded.

## 0.101.1

### Patch Changes

- e0fcb04: `sdk.apps` now runs actions for apps that do not require a connection without rejecting the call before execution.

## 0.101.0

### Minor Changes

- cfc7020: Added `importWorkflow` (experimental), exposed in the CLI as `import-workflow`. Converts an existing Zap into a durable workflow: pass `zap` (the Zap ID) and optionally `name` and `private`. Returns `{ workflow, draft, issues }`. The workflow is created disabled with no published version; publish the draft to make it live, once any blocking `issues` are resolved. The original Zap is untouched.

## 0.100.0

### Minor Changes

- 22a885c: Added `validateWorkflow` (experimental) to check durable workflow source without publishing it. Pass `sourceFiles` (absolute logical path → TypeScript source) and an optional `entrypointFile`, which defaults to `/workflow.ts`. The response carries an `issues` array that is empty when the source is valid; each issue has a `kind`, a `message`, a `severity` (`error`, `warning`, `info`, or `hint`), an optional `suggestion`, and usually the `source` location it points at. New `kind` values are added over time, so treat an unfamiliar one as a diagnostic rather than an error.

## 0.99.0

### Minor Changes

- 9cde1f6: Item and list methods accept `skipOutputDataValidation: true` alongside their
  input, bypassing output validation for that one call. Most methods here opt out
  of validation at authoring time, where a caller's flag does nothing, so it
  applies to `createActionRun` and `getActionRun`. Both build their response field
  by field, so nothing is stripped either way, and the visible difference is a
  `meta.outputDataValidation` sidecar on a call that passes it.

  `ResponseMeta` gains `outputDataValidation`, a union discriminated on `skipped`,
  which supersedes the deprecated `outputValidation`. That field is still written,
  with the same `{ droppedPaths }` shape.

  `defineOverride` is re-exported, so a head can patch how a surface presents an
  SDK method without importing kitcore. `defineMethodOverride` is deprecated in
  its favour and still works.

## 0.98.1

### Patch Changes

- cd0616e: _This release contains no user-facing changes._

## 0.98.0

### Minor Changes

- 9a5ae37: Added `status` to `listConnections`, `findFirstConnection`, and `findUniqueConnection` to filter connections by expiry: `active` (the default, and the existing behaviour), `expired`, or `all` for both. Previously only non-expired connections were returned by default and `expired: true` returned only expired ones, so a single call could never cover both. `expired` and `isExpired` are now deprecated in favour of `status` and still work; combining `status` with either throws a validation error.

## 0.97.1

### Patch Changes

- e45f03b: _This release contains no user-facing changes._

## 0.97.0

### Minor Changes

- abbeb60: Added a `manual` option (experimental) to `publishWorkflowDraft` and `updateWorkflowDraft`, exposed in the CLI as `--manual` on `publish-workflow-draft` and `update-workflow-draft`. Pass `manual: true` to declare a draft (or its publish) on-demand and triggerless; pass `trigger` for a triggered one. The two are mutually exclusive — sending both is rejected with a 400. This extends the `manual` flag `publishWorkflowVersion` already supports (see the previous release) to the draft path.

## 0.96.0

### Minor Changes

- 2726599: Added `createForm` (experimental) to create Zapier Forms from a title, optional description, and typed field list. Forms publish by default and return a shareable `hosted_url`; pass `draft: true` to save without publishing. A complete `document` can be supplied for layouts the field list cannot express.

## 0.95.0

### Minor Changes

- 80dc74a: Auto-mode approvals that are escalated to a human reviewer now open the approval URL in the browser automatically and continue polling until the reviewer decides.
- 6e5189c: Added a `manual` option (experimental) to `publishWorkflowVersion`, exposed in the CLI as `--manual` on `publish-workflow-version`. Pass `manual: true` to publish an on-demand, triggerless workflow version explicitly; pass `trigger` for a triggered one. The two are mutually exclusive — sending both is rejected with a 400.

## 0.94.1

### Patch Changes

- 59a8180: `fetch()` now populates`ZapierRelayError.retryable` (boolean) and `ZapierRelayError.errors` (structured error code array) when the proxy provides machine-readable error metadata.

## 0.94.0

### Minor Changes

- d700196: Added `createActionRun` and `getActionRun`, the two halves of `runAction` as separately callable methods:
  - `createActionRun({ app, actionType, action, connection?, inputs?, page?, callbackUrl? })` — starts an action run and returns `{ id, implementation_id }` right away, without waiting for it to finish. `implementation_id` is the versioned implementation the run was started against, matching `implementation_id` on an app from `getApp` / `listApps`.
  - `getActionRun({ run })` — returns that run's state: `{ id, status, results, errors, next_page? }`. It is a point-in-time read that answers immediately, so a run that is still executing comes back with `status: "waiting"` and it is up to the caller to check again. Unlike `runAction`, a failed run is reported as `status: "error"` with the details in `errors` rather than thrown.

  To page a bulk read, pass the `next_page` from `getActionRun` back as the `page` for the next `createActionRun`. The pair uses the same page terminology in both directions, and `next_page` is always a string so it can be handed straight back. `runAction` is a paginated list method, so it keeps the SDK's usual `cursor` / `nextCursor` pair.

  Pass `callbackUrl` to `createActionRun` to skip polling altogether: Zapier posts the finished run to that URL. It must use HTTPS and resolve to a public host. The delivered body matches what `getActionRun` returns, and carries a `Zapier-Callback-Signature` header holding an RS256 JWT you can verify against `https://zapier.com/.well-known/jwks.json`. Delivery is retried, so the same run can arrive more than once.

  `runAction` is unchanged and is still the right call for most cases — it starts a run and waits for the result in one step. Reach for the pair when you don't want to block on the result: fan out many runs and collect them later, hand a run ID to another process, or pick a run back up after a restart. Run results are retained for seven days.

## 0.93.0

### Minor Changes

- bc7405e: `@zapier/kitcore`: added `NegatableMetadata` and a `getNegatable` reader for marking optional boolean schema fields where omission is distinct from false (omitting means "use the server default" or "keep the current value"). Tooling built on kitcore can read the marker to offer an explicit disable affordance — for example, the CLI generates a `--disabled` flag from it.

  `@zapier/zapier-sdk`: the `publishWorkflowVersion` and `publishWorkflowDraft` `enabled` parameter descriptions now state what omitting the parameter does (uses the server default / preserves the current state) without naming CLI-specific flags. `NegatableMetadata` and `getNegatable` are re-exported from `@zapier/kitcore` for schema-metadata consumers.

## 0.92.1

### Patch Changes

- 67db455: Documented the guided `zapier-sdk setup` command in the SDK quick start.

## 0.92.0

### Minor Changes

- 56f0789: Added an `ignoreOpenDrafts` option (experimental) to `publishWorkflowVersion`, exposed in the CLI as `--ignore-open-drafts` on `publish-workflow-version`. Publishing a version directly is rejected with a 409 conflict while the workflow has open draft(s), since publishing a draft later would ship its stale content over the new version; set this option to publish anyway.

  Every 409 from `publishWorkflowVersion` now surfaces as a `ZapierConflictError` (matching `publishWorkflowDraft`) instead of a generic API error. The open-draft 409 additionally lists the blocking drafts (id, slug, last edited) and the remediations — publish the draft (`publishWorkflowDraft`), discard it (`discardWorkflowDraft`), or force with `ignoreOpenDrafts`. The structured draft list rides on the error's `meta.open_drafts` (typed via the new `OpenDraftRef` export on `@zapier/zapier-sdk/experimental`), and the CLI's `--json` error envelope includes it, so agents can resolve the conflict without parsing the message.

### Patch Changes

- 87e634f: Methods that return a single record now type their result as `{ data, meta? }`, where the optional `meta` is a framework sidecar. This matches the shape list methods' pages already had. Nothing populates `meta` in this release, so no runtime behavior changes and no caller code needs to react.

## 0.91.1

### Patch Changes

- 4886b5b: `runAction` failures now carry the action's structured errors on the thrown
  `ZapierActionError`. `error.errors` (and its `actionErrors` alias) previously
  stayed `undefined` for a failed action run, because the API reports that failure
  in the body of a `200` response rather than as an HTTP error. Each entry now
  exposes the machine-readable `code` — for example `authentication_error` when a
  connection has expired — so callers can branch on the failure instead of
  matching against the message text.

## 0.91.0

### Minor Changes

- 5935b7e: Added `publishWorkflowDraft` (experimental) to publish an open workflow draft as a new immutable version.
  - Publishing advances the workflow's live pointer and **discards the draft** — publish consumes it, so an open draft always means unpublished work. Returns both the new `version` and the consumed `draft` (`status: "discarded"`, `base_version_id` still recording the version it was forked from). Prefer it over `publishWorkflowVersion` once a draft exists, so the open draft is never orphaned; continue editing by creating a new draft off the new version.
  - Accepts optional `enabled` (set the workflow's enabled state as part of the publish; preserved if omitted) and `draftRevision` (optimistic concurrency: publish exactly the revision last read).
  - Failure modes stay distinct: a concurrent-edit or trigger-switchover conflict surfaces as `ZapierConflictError` (retryable after re-reading the draft), a trigger-catalog validation outage surfaces as a retryable 503 API error, and invalid `zapier_durable_version` or trigger config surfaces as a validation error.

## 0.90.0

### Minor Changes

- f6eac6f: Added `createWorkflowDraft`, `updateWorkflowDraft`, and `discardWorkflowDraft` (experimental), completing the draft lifecycle alongside the existing read methods.
  - `createWorkflowDraft` forks a new draft from the workflow's live version, with an optional `slug`.
  - `updateWorkflowDraft` saves draft edits — source files, dependencies, trigger, connections, and app-version pins. Pass `draftRevision` to reject the save with a `ZapierConflictError` if the draft changed since it was last read; pass `null` for `trigger`, `connections`, or `appVersions` to clear the stored value, or omit them to leave it unchanged.
  - `discardWorkflowDraft` soft-deletes a draft and returns it with status `discarded`.

  All ID inputs are UUID-validated at the boundary.

## 0.89.0

### Minor Changes

- e24c236: Added `listWorkflowDrafts` and `getWorkflowDraft` (experimental). `listWorkflowDrafts` is paginated (cursor + pageSize), returns a workflow's drafts most recently edited first, and filters by `status` (server default: open) or exact `slug`. `getWorkflowDraft` returns the full draft state including `source_files` and `draft_revision`, the draft's optimistic-concurrency counter. CLI commands taking a draft id present an interactive picker. All ID inputs are UUID-validated at the boundary.

## 0.88.1

### Patch Changes

- 60892be: _This release contains no user-facing changes._

## 0.88.0

### Minor Changes

- 0e49ffa: Renamed time-duration options and parameters so every one carries its unit as a full-word suffix. Coarse durations (timeouts, waits, the retry-delay cap) now take **seconds**; genuinely sub-second knobs (poll cadence, the low-level `poll` primitive) take **milliseconds**. The old names still work but are deprecated — a caller passing a deprecated `*Ms` name keeps its millisecond meaning, so nothing changes silently; only the new names adopt the new unit.

  | Before                                                                      | After                                                     |
  | --------------------------------------------------------------------------- | --------------------------------------------------------- |
  | `createZapierSdk({ maxNetworkRetryDelayMs })`                               | `createZapierSdk({ maxNetworkRetryDelaySeconds })`        |
  | `createZapierSdk({ approvalTimeoutMs })`                                    | `createZapierSdk({ approvalTimeoutSeconds })`             |
  | `runAction({ timeoutMs })` (and `sdk.apps.<app>.<action>`)                  | `runAction({ timeoutSeconds })`                           |
  | `sdk.fetch(url, { maxTime })`                                               | `sdk.fetch(url, { maxTimeSeconds })`                      |
  | `createConnection` / `waitForNewConnection` `{ timeoutMs, pollIntervalMs }` | `{ timeoutSeconds, pollIntervalMilliseconds }`            |
  | `ApiClient.poll({ timeoutMs, initialDelay })`                               | `poll({ timeoutMilliseconds, initialDelayMilliseconds })` |
  | env `ZAPIER_MAX_NETWORK_RETRY_DELAY_MS`                                     | env `ZAPIER_MAX_NETWORK_RETRY_DELAY_SECONDS`              |

## 0.87.1

### Patch Changes

- 920d571: _This release contains no user-facing changes._

## 0.87.0

### Minor Changes

- 4e560c0: Added brand-based type guards for recognizing SDK errors and signals without `instanceof`: `isZapierError`, per-subclass guards (`isZapierValidationError`, `isZapierApprovalError`, `isZapierNotFoundError`, `isZapierBundleError`, `isZapierTimeoutError`, and the rest), `isZapierSignal`, and the trigger-inbox signal guards `isZapierReleaseTriggerMessageSignal` and `isZapierAbortDrainSignal`.

  Prefer these over `instanceof` when handling SDK errors. `instanceof` compares class identity, which silently returns `false` when more than one copy of the SDK is loaded — for example a bundle that includes both the ESM and CommonJS builds, or a project that installs two versions. The guards match on a stable brand and the error `code`, so they keep working across those boundaries.

## 0.86.0

### Minor Changes

- afa9c95: The experimental `publishWorkflowVersion` and `runDurable` methods can now have their `sourceFiles` map filled interactively, one file at a time (name, then contents), when resolved through the CLI or MCP. Calling the methods directly with a `sourceFiles` object is unchanged.

## 0.85.0

### Minor Changes

- 769751e: 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

### Patch Changes

- 840aca3: 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

### Patch Changes

- e6b22fb: 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

### Patch Changes

- e1c327d: _This release contains no user-facing changes._

## 0.84.1

### Patch Changes

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

## 0.84.0

### Minor Changes

- e1896a3: 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

### Patch Changes

- 90ac367: 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

### Patch Changes

- bf0d056: This release contains no user-facing changes.

## 0.83.1

### Patch Changes

- 6201fd4: `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

### Minor Changes

- 5f5f028: `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

### Patch Changes

- ce612ee: `.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

### Minor Changes

- d09592b: 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

### Patch Changes

- d96b5f6: 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

### Minor Changes

- 8d232d2: 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

### Patch Changes

- 072fe2b: 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

### Patch Changes

- 4fd8dce: _This release contains no user-facing changes._

## 0.80.0

### Minor Changes

- 5e2cf0d: 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

### Minor Changes

- d67227b: 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

### Minor Changes

- b8ff1dd: Refactor the SDKs onto kitcore's new internal plugin model.

  kitcore (an internal building block) gained a new plugin model, and the SDKs were rebuilt on it behind a compatibility bridge, so existing behavior is unchanged. The only changes to the published packages' surface:
  - 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

### Patch Changes

- 365ad1b: Fix published type declarations referencing modules consumers can't resolve.

  `tsc -b` (run in `validate` after the tsup build) was emitting per-module
  declarations over tsup's bundled `dist/index.d.ts`, reintroducing hundreds of
  `import("kitcore")` references; `kitcore` is bundled into the SDK and only a
  devDependency, so consumer type-checks failed with "Cannot find module
  'kitcore'" (CJS only, since `tsc` doesn't emit the ESM `.d.mts`). tsc now emits
  its declarations to a gitignored side dir instead of `dist`, so it can never
  overwrite tsup's bundle, while project references and editor type-checking keep
  working. (The CLI gets the same treatment, which also stops it from publishing
  stray per-module declarations under `dist/src`.) Separately, the optional
  `@zapier/zapier-sdk-cli/login` module is
  referenced through a local interface instead of `typeof import(...)`, so its
  reference no longer leaks into the published declarations. `verify-exports` now
  fails the build if any published declaration references an undeclared package.

## 0.77.1

### Patch Changes

- 3fa9190: Upgrade `@zapier/policy-context`, which drops `@asteasolutions/zod-to-openapi` from it's dependency tree.

## 0.77.0

### Minor Changes

- 19303e0: `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. It now returns the trigger's `id`, `workflow_id`, and `created_at` on `data` (previously `{ workflow, status, body }`). The call is unchanged: pass the workflow id and optional `input`.

## 0.76.2

### Patch Changes

- 27ca0c5: Add zapier-sdk-agent header to identify the AI agent using the SDK

## 0.76.1

### Patch Changes

- 745e172: Include client id and auth mechanism in client-side telemetry

## 0.76.0

### Minor Changes

- a7d2646: 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

### Minor Changes

- 8e5253d: `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

### Patch Changes

- f56bfdb: 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 until the CSW API ships them server-side (COSUB-630).

## 0.74.0

### Minor Changes

- 571f90d: Add zapier-sdk-package-operation header to identify the caller operation

## 0.73.1

### Patch Changes

- 6c7627c: 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

### Minor Changes

- f963a9d: Emit the standard `zapier-sdk-version`, `zapier-sdk-package`, `zapier-sdk-package-version`, and `zapier-service` telemetry headers (per the Zapier API header guidance) alongside the existing `x-zapier-*` headers. The legacy `x-zapier-*` headers continue to be sent for backward compatibility.

## 0.72.0

### Minor Changes

- fcc758e: `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

### Patch Changes

- 2521624: 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

### Minor Changes

- 3474ff3: 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`.

### Patch Changes

- 5ca445d: 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

### Patch Changes

- a790695: Response-field parity audit for the experimental code-substrate
  plugins. Restores fields the backend returns that were silently
  stripped by the SDK's Zod schemas after the port from
  `@zapier/zapier-sdk-code-substrate`.
  - `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).

  Shared schemas (`ConnectionBindingSchema`, `AppVersionBindingSchema`,
  `WorkflowVersionTriggerConfigSchema`, `WorkflowTriggerSchema`) live in
  a new `shared-schemas.ts` for reuse across the workflow plugins.

## 0.70.3

### Patch Changes

- b83f0b6: Add TTY and agent caller context to SDK telemetry events
- 3fa4bbe: Fix `get-durable-run` schema to accept a null `last_error`. The durable execution summary's `last_error` was `.optional()` but not `.nullable()`, so parsing threw on successful runs where the API returns `last_error: null`.

## 0.70.2

### Patch Changes

- cafad12: Fix `listActions` filtering out private/unlisted apps (COSUB-562)

  `listActions` hardcoded `public_only: "true"` on the `/implementations/` call, so actions on private CLI apps the caller has access to were dropped from the response. Consumers (e.g. the Durables Editor) then treated valid steps on private integrations as an "unknown action". The call now passes `public_only: "false"`, so private/unlisted implementations the caller can access are included; results remain access-scoped server-side.

## 0.70.1

### Patch Changes

- eb30657: Restore Schema.parse() on code-substrate workflow and durable-run response handlers. Opens RunStatus, ExecutionStatus, OperationType, and OperationStatus enums so future server-side values do not break parsing. Reinstates DeleteWorkflowResponseSchema and wires outputSchema on cancelDurableRun and deleteWorkflow.

## 0.70.0

### Minor Changes

- 8f20472: `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

### Patch Changes

- c4df375: Restore `connections`, `app_versions`, and `trigger` input fields on the
  experimental `publishWorkflowVersion` plugin. The fields were dropped
  during the port from `@zapier/zapier-sdk-code-substrate`, leaving
  workflows published via the in-tree plugin unable to bind connection
  aliases or wire a trigger. Shape matches the durableworkflowzaps
  backend: connections as `{alias: {connection_id: ...}}`, app_versions as
  `{alias: {implementation_name, version?}}`, and trigger as a nested
  object with `selected_api` + `action` required.

## 0.69.2

### Patch Changes

- c50db26: 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

### Patch Changes

- da80c77: 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

### Minor Changes

- 9f1e934: 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

### Patch Changes

- 9d6bd4d: Ship `AGENTS.md` as the canonical agent-instructions file. Each `CLAUDE.md` is now a thin stub that imports it, so Claude Code, Codex, and Cursor read the same guidance.

## 0.68.0

### Minor Changes

- 41a7c26: Add `zapier-sdk signup` for browser-based account setup and local SDK credential provisioning.
  Add the `signup_success` SDK lifecycle telemetry event type for successful signup OAuth callback acceptance.

## 0.67.0

### Minor Changes

- 9096184: Extract the plugin framework into a new sibling package `kitcore` that
  `@zapier/zapier-sdk` consumes as a workspace devDependency (bundled into
  the published dist, not a runtime dep). Existing SDK code is unaffected:
  `createZapierSdk`, `createSdk`, the `ZapierSdk` type, every SDK method, and
  the full `Zapier*` error hierarchy keep their names, codes, and `instanceof`
  semantics. Internally `createZapierSdk` now builds via the linear
  `createPluginStack().use(...).toSdk()` path, which substantially speeds up
  construction. One behavior change to note: `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.

  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; the CLI and MCP packages moved their internal
  assembly to stacks with no change to their commands or tools.

### Patch Changes

- a950509: 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

### Minor Changes

- 0eb6a76: Add the `triggerWorkflow` experimental code-substrate plugin. Lives behind `@zapier/zapier-sdk/experimental` only — the stable subpath does not surface it. Looks up the workflow's `trigger_url` via the durableworkflowzaps API, then POSTs the user-supplied JSON payload to that URL. The trigger endpoint is tokenized (the URL embeds a secret) and takes no auth header, so the SDK uses a raw `fetch` rather than the api plugin for the second leg. Custom fetch flows through `sdk.context.options.fetch` for tests. 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. The CLI gets the `workflowIdResolver` picker for the workflow input.

### Patch Changes

- 66db7cb: Limit approval polling waits to at most 5 seconds while preserving the existing generic polling cadence.
- c7c8f64: 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

### Minor Changes

- 9138968: Add the workflow-run experimental code-substrate plugins: `listWorkflowRuns`, `getWorkflowRun`, and `getTriggerRun`. All three live behind `@zapier/zapier-sdk/experimental` only — the stable subpath does not surface them. `listWorkflowRuns` is paginated against the backend's cursor + limit contract; `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. Handlers pass the API response through verbatim — schemas stay as `outputSchema` for docs and types, but consumers see any richer fields the server adds without an SDK release. Adds `workflowRunIdResolver` — a dependent resolver scoped to the parent workflow — so CLI commands taking a run id present an interactive picker via `sdk.listWorkflowRuns({ workflow })`. `getTriggerRun` does not register a picker for `trigger`; users typically have the trigger id from a recent fire and pass it directly.

## 0.64.0

### Minor Changes

- 913aa6b: Add the workflow-version experimental code-substrate plugins: `publishWorkflowVersion`, `listWorkflowVersions`, and `getWorkflowVersion`. All three are registered only in `@zapier/zapier-sdk/experimental`; the stable subpath does not expose them. `listWorkflowVersions` is paginated (cursor + pageSize); `publishWorkflowVersion` POSTs `source_files` (filename → contents) plus optional `dependencies`, `zapier_durable_version`, and `enabled` (defaults to true) to publish a new version; `getWorkflowVersion` returns the full version state including source files. Handlers pass API responses through verbatim (no client-side `.parse()` re-emission) so callers see any richer fields the server adds later without an SDK release. Adds `workflowVersionIdResolver` — a dependent resolver scoped to a parent workflow, mirrored on `tableRecordIdResolver`'s shape — so commands that take a version id present an interactive picker via `sdk.listWorkflowVersions({ workflow })` in the CLI. All ID inputs are UUID-validated at the boundary so non-UUID strings fail with a clear schema error instead of an opaque 500 from the backend's `::uuid` cast.

## 0.63.0

### Minor Changes

- dfa3cea: Add the durable-run-write experimental code-substrate plugins: `runDurable` and `cancelDurableRun`. Both are registered only in `@zapier/zapier-sdk/experimental`; the stable subpath does not expose them. `runDurable` POSTs to sdkdurableapi `/api/v0/runs` with `source_files` (filename → contents), optional `input`/`dependencies`/`zapier_durable_version`/`connections`/`app_versions`, and a `private` input that maps to `is_private` on the wire. Returns the run ID immediately in `initialized` status — callers that need terminal status poll via `getDurableRun`; no built-in polling. `cancelDurableRun` POSTs to `/api/v0/runs/:id/cancel`, returns `{ id, status: "cancelled" }` on success, and propagates `ZapierNotFoundError` (404) and `ZapierConflictError` (409 — run already terminal) so callers can distinguish those outcomes. `runDurable` passes the API response through verbatim (no client-side `.parse()` re-emission) so callers see any richer fields the server adds later without an SDK release. Input field naming follows the in-tree convention (`run` rather than `runId`); UUID-validated at the input boundary. `cancelDurableRun` reuses `durableRunIdResolver` from the reads MR for ID pickers.

## 0.62.0

### Minor Changes

- eb9b408: Add the durable-run-read experimental code-substrate plugins: `listDurableRuns` and `getDurableRun`. Both are registered only in `@zapier/zapier-sdk/experimental`; the stable subpath does not expose them. `listDurableRuns` is paginated (cursor + pageSize) per the sdkdurableapi `/api/v0/runs` contract; `getDurableRun` returns the full run state with nested execution and operations journal. Handlers pass API responses through verbatim (no client-side `.parse()` re-emission) so callers see any richer fields the server adds later without an SDK release. Also adds `durableRunIdResolver` in `src/resolvers/durableRunId.ts` so commands that take a run id present an interactive picker via `sdk.listDurableRuns()` in the CLI (uses `toIterable` to pull across pages). Input field naming follows the in-tree convention (`run` rather than the fork's `runId`); input is validated as a UUID at the boundary so non-UUID strings fail with a clear schema error instead of an opaque 500 from the backend's `::uuid` cast.

## 0.61.0

### Minor Changes

- 4827ffe: Add the workflow-write experimental code-substrate plugins: `createWorkflow`, `updateWorkflow`, `enableWorkflow`, `disableWorkflow`, `deleteWorkflow`. All five are registered only in `@zapier/zapier-sdk/experimental`; the stable subpath does not expose them. The four ID-based ops (update, enable, disable, delete) reuse `workflowIdResolver` so callers get an interactive picker via `sdk.listWorkflows()`. `deleteWorkflow` is marked `confirm: "delete"` for an explicit confirmation prompt before the destructive call. Input field naming follows the in-tree convention (`workflow` rather than the fork's `workflowId`, matching `tableIdResolver`'s shape) and is validated as a UUID at the input boundary so non-UUID strings fail with a clear schema error instead of an opaque 500 from the backend's `::uuid` cast. Response shapes match what the durableworkflowzaps handlers actually emit — no fabricated `is_private` / `created_by_user_id` / `triggers` fields. Handlers pass API responses through verbatim (no client-side `.parse()` re-emission) so callers see any richer fields the server adds later without an SDK release.

### Patch Changes

- 104daa3: 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

### Minor Changes

- f12598a: Add the workflow-read experimental plugins: `listWorkflows` and `getWorkflow`. Both are registered only in `@zapier/zapier-sdk/experimental`; the stable subpath does not expose them. `listWorkflows` uses `createPaginatedPluginMethod` (page-iterator + `pageSize`/`cursor`/`maxItems` options) so callers can iterate via `for await (const page of sdk.listWorkflows())` or `toIterable(sdk.listWorkflows())`. The backend does not paginate today; the SDK treats a missing `next_cursor` as the last page, so server-side pagination drops in without an SDK API change. Introduces `packages/zapier-sdk/src/plugins/codeSubstrate/shared.ts` with `codeSubstrateDefaults` (`{ categories: ["code-workflow"], experimental: true }`) that subsequent code-workflow plugins spread into their `createPluginMethod` configs. Also adds `workflowIdResolver` in `src/resolvers/workflowId.ts` (mirrors `tableIdResolver` / `triggerInboxResolver`) so commands that take a workflow id present an interactive picker via `sdk.listWorkflows()` in the CLI. Workflow-write commands (`createWorkflow`, `updateWorkflow`, `enable/disable/deleteWorkflow`) land in a follow-up MR.

## 0.59.0

### Minor Changes

- e9da7e9: Register `/sdkdurableapi` and `/durableworkflowzaps` in the API client's path configuration so plugins can route to those services via the sdkapi proxy. Requests to `/sdkdurableapi/...` and `/durableworkflowzaps/...` now resolve under `https://sdkapi.zapier.com/api/v0/sdk/<service>/...` with the standard `Authorization` header, matching the existing `/zapier`, `/tables`, and `/trigger-inbox` entries. The existing `getAuthorizationHeader` auto-detects JWTs and formats them as `JWT <token>`. Enables in-tree plugins (e.g. forthcoming experimental code-substrate plugins) to call durable services through `sdk.context.api` without rolling their own HTTP client.

## 0.58.0

### Minor Changes

- afbd4b6: 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

### Minor Changes

- 5457bdd: 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

### Patch Changes

- 884d0fc: Update ensureTriggerInbox to use new PUT endpoint in upstream Trigger Inbox API

## 0.56.1

### Patch Changes

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

## 0.56.0

### Minor Changes

- d2aa0e9: Allow opting into approvals during login

## 0.55.0

### Minor Changes

- ce779d1: 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

### Patch Changes

- 22a1727: Add optional `name` parameter to `createTriggerInbox` method

## 0.54.0

### Minor Changes

- ecfb727: 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

### Minor Changes

- 23352c8: 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

### Minor Changes

- 7984fae: 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

### Minor Changes

- ef1c97d: Default SDK auth to client credentials

### Patch Changes

- f5a734d: 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

### Minor Changes

- cd8f37b: 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

### Minor Changes

- 529663c: Add experimental support for triggers.

## 0.48.1

### Patch Changes

- 5ec7992: Document return type shapes in SDK README.

## 0.48.0

### Minor Changes

- c7cff63: 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

### Patch Changes

- 4ab820a: Skip the approval `poll_url` and `approval_url` origin checks when `baseUrl` (or `ZAPIER_BASE_URL`) points at `localhost` / `127.0.0.1`. Local dev runs sdkapi, approvalsapi, and the approval frontend on different ports, so the origin pin can never match. The check is intended to stop a compromised sdkapi from redirecting bearer-token traffic to an attacker host — a threat that doesn't apply when the developer owns every service on the machine.

## 0.47.0

### Minor Changes

- e45ce2f: 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

### Patch Changes

- fcb47ea: Set npm package homepage links to public SDK documentation.

## 0.46.1

### Patch Changes

- 591ddb5: Removed custom error handlers and added definePlugin, createPluginMethod, and createPaginatedPluginMethod to reduce plugin boilerplate.

## 0.46.0

### Minor Changes

- bd887ab: 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

### Patch Changes

- 783e180: Convert API query params from camelCase to snake_case (appKeys -> app_keys, pageSize -> page_size) to match the updated API contract. Also updated all `zapier-sdk-*` packages to Zod to 4.3.6

## 0.45.1

### Patch Changes

- cb0d898: Added telemetry headers so sdkapi can attribute traffic to the SDK entry point that produced it. Every outbound request now includes `x-zapier-sdk-version`, with `x-zapier-service` added when `ZAPIER_SDK_SERVICE` is set. Requests originating from `createZapierCliSdk` or `createZapierMcpServer` additionally include `x-zapier-sdk-package` and `x-zapier-sdk-package-version` identifying the wrapping package; direct `createZapierSdk` callers omit those two. Headers are applied after caller-supplied header merging, so they can't be spoofed via per-request `options.headers`.

## 0.45.0

### Minor Changes

- 15dce25: `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

### Minor Changes

- fd8660c: 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

### Minor Changes

- 8df8761: 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

### Patch Changes

- 707c57a: 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

### Minor Changes

- 55e8330: Support maxTime for SDK fetch & CLI curl - Relay extended timeout

## 0.41.2

### Patch Changes

- 3cf1a98: Fix connection resolution for no-auth apps

## 0.41.1

### Patch Changes

- 53c165a: `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

### Minor Changes

- 912e960: Prefer public IDs over numeric IDs in responses

## 0.40.4

### Patch Changes

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

## 0.40.3

### Patch Changes

- b250545: Connections - Replace isExpired with expired

## 0.40.2

### Patch Changes

- 362bc56: Make sure CLI only shows non-deprecated positional parameters.

## 0.40.1

### Patch Changes

- 5391c65: Fix ordering problem with tables CLI commands.

## 0.40.0

### Minor Changes

- 39e296a: Removing Id or Key suffixes from parameter names to make them flexible to be ID, key, name, alias, etc.

## 0.39.1

### Patch Changes

- b4c0560: Accept UUID authentication IDs without coercion. Stop coercing authentication IDs to numbers, allowing UUIDs and other string identifiers to pass through unchanged. Update Zod schemas to accept string or number for authentication_id fields.

## 0.39.0

### Minor Changes

- a20d36a: Add define primitives (defineTool, defineDurable, defineComponent) via @zapier/zapier-sdk/define entrypoint and app registry via @zapier/zapier-sdk/apps entrypoint.

## 0.38.0

### Minor Changes

- 2906101: Default `listConnections` and `listTables` to only return your own items. Gate shared access and table deletion behind boolean flags: `canIncludeSharedConnections`, `canIncludeSharedTables`, `canDeleteTables`. Set via SDK options, `.zapierrc`, CLI flags (`--can-delete-tables`), or env vars (`ZAPIER_CAN_DELETE_TABLES=true`).

## 0.37.0

### Minor Changes

- 307aa98: Add named connections support. A new `connection` parameter on `runAction`, the apps proxy, and `fetch` resolves a connection alias (string) from a connections map, or accepts a numeric `connectionId` directly. The map is provided via the `connections` field in `.zapierrc` (or the inline `manifest` option on `createZapierSdk()`).

## 0.36.0

### Minor Changes

- 3a447d3: Add support for pagination in Run Action

## 0.35.0

### Minor Changes

- d4534f3: Add support for Tables.

## 0.34.1

### Patch Changes

- 6c5bba9: Fix fetch type for app proxy without generated types.

## 0.34.0

### Minor Changes

- 3700f6a: Fix --json output

## 0.33.4

### Patch Changes

- d9e0f1d: Fix user properties being overwritten by context merge in telemetry events

## 0.33.3

### Patch Changes

- f676852: Suppress resolver method calls from emitting telemetry events

## 0.33.2

### Patch Changes

- 623dc25: Add deprecation warning for fetch CLI command

## 0.33.1

### Patch Changes

- 42edf6e: Remove test files from published packages

## 0.33.0

### Minor Changes

- f442359: Credential env vars (ZAPIER_CREDENTIALS, ZAPIER_CREDENTIALS_CLIENT_ID, ZAPIER_CREDENTIALS_CLIENT_SECRET, ZAPIER_CREDENTIALS_BASE_URL, ZAPIER_CREDENTIALS_SCOPE) are now read at call time rather than at import time. If you set or modify these env vars after importing the SDK, the updated values will now be picked up correctly. Also fixes baseUrl not being passed through when calling resolveAuthToken with an explicit baseUrl option.

## 0.32.5

### Patch Changes

- 0feaeb1: Fix telemetry sdk_version via build-time constant

## 0.32.4

### Patch Changes

- 1334eac: Emit login_success lifecycle event on CLI login

## 0.32.3

### Patch Changes

- 04000f6: Skip connection selection for apps that do not require auth

## 0.32.2

### Patch Changes

- a6dec83: Fix base URL with trailing slash bypassing sdkapi.

## 0.32.1

### Patch Changes

- c7be13e: Fix bug where `add` command hangs after completing successfully

## 0.32.0

### Minor Changes

- 250cb7d: Store CLI login credentials in system keychain.

## 0.31.4

### Patch Changes

- 026ae46: Properly capture and type errors from downstream proxy service.

## 0.31.3

### Patch Changes

- c98008a: Add callContext option to EventEmissionConfig to track where SDK method calls originate. MethodCalledEvent telemetry events now populate call_context with "sdk", "cli", or "mcp" instead of null.

## 0.31.2

### Patch Changes

- 1ae0349: Improve error message when credentials can't be found. Also improve module resolution for login module.

## 0.31.1

### Patch Changes

- b0f273f: Enrich MethodCalledEvent with selected_api, operation_type, operation_key

## 0.31.0

### Minor Changes

- 4a874c6: Add Zod schema for base SDK options, autodoc generation for SDK factory options and CLI base command options

## 0.30.0

### Minor Changes

- 0055854: Remove internal `_telemetry` property from all method option types

## 0.29.0

### Minor Changes

- ad5ee3b: Adds a new curl plugin.
  Switch -v flag to -V for version information.
  Fix CLI to properly handle string and object types.
  Add redirect passthrough to fetch plugin (to support curl plugin).

## 0.28.0

### Minor Changes

- b2e5675: Retry on 429s with appropriate backoff. Add maxNetworkRetries and maxNetworkRetryDelayMs options (also configurable via ZAPIER_MAX_NETWORK_RETRIES and ZAPIER_MAX_NETWORK_RETRY_DELAY_MS environment variables).

## 0.27.1

### Patch Changes

- 4ad0f34: Removed the `overall` option from the feedback command, since that will be inferred now. Also made it ask for feedback if you don't provide a value for it.

## 0.27.0

### Minor Changes

- 9fb0b48: Switch from "authentication" to "connection" everywhere.

## 0.26.0

### Minor Changes

- bfdd383: Remove authenticationTemplate option from fetch.

## 0.25.3

### Patch Changes

- 7ab8539: Adding feedback command for submitting SDK feedback

## 0.25.2

### Patch Changes

- 642713b: Update README with more detail and more attention on fetch.

## 0.25.1

### Patch Changes

- aacaf22: Improved `fetch` to automatically set the correct `Content-Type` header based on the request body type. `FormData`, `Blob`, and other binary bodies are now handled correctly instead of being misidentified as JSON.

## 0.25.0

### Minor Changes

- b0b7eb3: Add timeoutMs for setting the timeout for polling action results.

## 0.24.0

### Minor Changes

- d72cda1: Deprecates request() in favor of self-contained fetch(). The fetch plugin now handles URL-to-relay transformation, header normalization,
  and body content-type inference directly instead of delegating to request. The request plugin is preserved as a backward-compatible
  shim that forwards to fetch. CLI and MCP now expose a fetch command via a new inputParameters registry concept for
  multi-positional-argument functions.

## 0.23.2

### Patch Changes

- 9664bd0: Fix polling for callback actions.

## 0.23.1

### Patch Changes

- c95e1d4: Add debug option inside event emission plugin.

## 0.23.0

### Minor Changes

- 7cf2b12: Add debug logging to zapier-sdk-cli-login. Only allow one token refresh at a time.

## 0.22.1

### Patch Changes

- 8ebde4b: Add required scopes for credentials methods.

## 0.22.0

### Minor Changes

- f54f895: Fix allowed_scopes parameter to be allowedScopes.

## 0.21.1

### Patch Changes

- dd54c22: `request` and `fetch` now require auth and provide a more helpful error message

## 0.21.0

### Minor Changes

- 33e2a8f: Added methods/commands for creating/listing/deleting client credentials.

## 0.20.1

### Patch Changes

- 7bd3c5c: Fix process listener memory leak in event emission plugin

## 0.20.0

- Correction for accidentally publishing a major version update.

## 1.1.0

### Minor Changes

- 4dd27eb: Add isExpired parameter to listAuthentications for filtering authentications by expiration status.

## 1.0.3

### Patch Changes

- e393401: Adds CLAUDE.md documentation files to the zapier-sdk and zapier-sdk-cli packages to help users get up to speed faster when using AI assistants like Claude, Cursor, etc.

## 1.0.2

### Patch Changes

- 00ef417: Resolved confusing "Failed to read manifest from .zapierrc" error

## 1.0.1

### Patch Changes

- aba842a: Updated docs to remove reference to deprecated token option.

## 1.0.0

### Minor Changes

- 97ff6c0: Add support for client credentials.

### Patch Changes

- Updated dependencies [97ff6c0]
  - @zapier/zapier-sdk-cli-login@0.4.0

## 0.18.4

### Patch Changes

- 3bc3cad: - Migrated `listApps` to call sdkapi endpoints directly, removing the temporary handler infrastructure. - Schemas now imported from `@zapier/zapier-sdk-core` for shared type definitions

## 0.18.3

### Patch Changes

- 7c59b01: - `listAuthentications` now routes through the proxy. It also imports and overrides a shared schema from `zapier-sdk-core`

## 0.18.2

### Patch Changes

- 76fb606: - `getAuthentication` plugin now routes through proxy instead of direct Zapier API's

## 0.18.1

### Patch Changes

- ee5beb6: Refactor transport classes to factory functions

## 0.18.0

### Minor Changes

- c2eab85: Switch numeric IDs to strings.

## 0.17.0

### Minor Changes

- 79b47f7: Renaming user_id to profile_id in authentications.

## 0.16.3

### Patch Changes

- 870f2aa: Fix CLI process hanging after login and on signal handling
  - Clear login timeout timer after successful authentication to allow process exit
  - Use timer.unref() on telemetry timeouts so they don't block process exit
  - Add explicit process.exit() in signal handlers with correct exit codes

## 0.16.2

### Patch Changes

- 93cbb3c: Fix search to prefer public app versions over private when user has access to both

## 0.16.1

### Patch Changes

- 142c1ce: Fix CLI UX issues: stdout truncation when piped, nullable schema detection for Zod 4, error body display, and auto Content-Type for JSON bodies

## 0.16.0

### Minor Changes

- 24ae4f0: Upgrade to Zod 4
  - Update all packages to use Zod 4
  - Migrate internal API access from `_def` to `_zod.def`
  - Update `z.record()` calls to include explicit key types
  - Fix schema introspection for documentation generation and CLI
  - Update MCP schema converter for Zod 4 structure

## 0.15.13

### Patch Changes

- d08fa90: Add proper license
- Updated dependencies [d08fa90]
  - @zapier/zapier-sdk-cli-login@0.3.5

## 0.15.12

### Patch Changes

- 9989512: Deduplicate plugin names in telemetry implementations

## 0.15.11

### Patch Changes

- 64de0b0: Emit MethodCalledEvent telemetry event

## 0.15.10

### Patch Changes

- 2f1fc5c: Remove inaccurate `peak_memory_usage_bytes` values from telemetry events

## 0.15.9

### Patch Changes

- 450b009: Fix getAction to search across all paginated results

## 0.15.8

### Patch Changes

- 371315e: Extract main logic/transformations of getAuthentication into temporary-internal-core to prepare for full migration

## 0.15.7

### Patch Changes

- 9f3695b: Make sure path of base URL is used when overriding base URL.

## 0.15.6

### Patch Changes

- 6a0e0db: Fix telemetry user context to use token from SDK options and Deduplicate JWT validation logic

## 0.15.5

### Patch Changes

- 712c02b: Refactored temporary route override pattern

## 0.15.4

### Patch Changes

- f7e552e: Add synchronous customuser_id and account_id retrieval to event emission plugin

## 0.15.3

### Patch Changes

- 6657f05: Defined shape and support for configured actions in the .zapierrc manifest file

## 0.15.2

### Patch Changes

- e4a3457: Extract listApps API and schemas

## 0.15.1

### Patch Changes

- 4c78fb0: Added `getInputFieldsSchema` plugin to retrieve JSON Schema for action inputs

## 0.15.0

### Minor Changes

- f92bc07: Route all API requests through new service.

## 0.14.0

### Minor Changes

- 3f2f104: - Introduce a `services` layer for reusability between plugins
  - `listInputFieldChoices` now supports returning static choices if they exist

## 0.13.9

### Patch Changes

- 492e2f9: - Add new `batch` utility method to handle concurency limits, retries, timeouts and exponential backoffs.
  - Refactor `generateAppTypes` in CLI to use the new `batch` utility

## 0.13.8

### Patch Changes

- 6de89a9: Allow overriding ZAPIER_BASE_URL with env vars, and also add new ZAPIER_TRACKING_BASE_URL, ZAPIER_AUTH_BASE_URL, and ZAPIER_AUTH_CLIENT_ID env vars and parameters.
- Updated dependencies [6de89a9]
  - @zapier/zapier-sdk-cli-login@0.3.4

## 0.13.7

### Patch Changes

- c1d3c9c: Publish zapier-sdk as a public package.
- 16b4930: Only publish compiled TS files.

## 0.13.6

### Patch Changes

- a563cda: Extend ZapierCliSdkOptions with the base ZapierSdkOptions so we can see the token and other properties when initializing with createZapierSdkCli
- Updated dependencies [9b7a954]
  - @zapier/zapier-sdk-cli-login@0.3.3

## 0.13.5

### Patch Changes

- 05ce6f7: 1. Extracted manifest creation and type generation into flexible base plugins that can be used by other consumers. 2. Updated updateManifestEntry function from base SDK to allow manipulating manifest as file or as JSON

## 0.13.4

### Patch Changes

- 80732ea: Add basic event-driven telemetry for key lifecycle events and CLI logins

## 0.13.3

### Patch Changes

- 53fa85e: Show id and key properties when listing actions. Allow getAction to use an id or key. Make runAction pass action_id to API to ensure it always works.

## 0.13.2

### Patch Changes

- 325d5c2: Fix bug where adding apps with dashed slugs would create types with syntax errors. All valid keys are now valid properties on the apps interface.

## 0.13.1

### Patch Changes

- a607e3a: Fixes a bug where listApps would return all apps if no appKeys were resolved to app locators. This in turn fixes the `add` command hanging when using only invalid app keys (since it would try to add all apps), and it fixes getApp which returned the first app of all apps for an invalid slug, since it just calls to listApps.

## 0.13.0

### Minor Changes

- 53ad336: Tweak list-apps output. Hint at slug for appKey parameters. Fix type gen for new field format. Fix action normalization.

## 0.12.1

### Patch Changes

- c2f88bc: Fix usage examples, add rough apps proxy examples

## 0.12.0

### Minor Changes

- 21d8487: Improved get started README and added more documentation to the add plugin

## 0.11.2

### Patch Changes

- 407245e: Add packages to meta so we can document `fetch` for SDK but not CLI/MCP.

## 0.11.1

### Patch Changes

- 0002fe9: Updated doc generation

## 0.11.0

### Minor Changes

- 12c6d3d: Return nested fields with fieldsets instead of flat fields. Also have CLI properly create line items from fieldsets for run-action.

## 0.10.0

### Minor Changes

- 3184903: No more global resolver registry, each plugin function has its own resolvers. Plugin function meta also stores output schema and some function type info to avoid some special case code for handling lists, documenting functions, etc. findFirstAuthentication throws an error to make all item functions consistent. Various other schema and output cleanup.

## 0.9.1

### Patch Changes

- 3cfed98: Reducing any usages

## 0.9.0

### Minor Changes

- 5ccaec6: AST-based type gen instead of string-based. Added `add` function for locking app versions and generating types. Removed `lockVersion` and `generateTypes functions. Manifest matching on slug or implementation name.

## 0.8.3

### Patch Changes

- ed235b6: Adds improved backoff logic to the API polling

## 0.8.2

### Patch Changes

- bef5467: Change type imports to disallow inline imports

## 0.8.1

### Patch Changes

- 319a05f: Expanding no explicit any coverage

## 0.8.0

### Minor Changes

- 3a39eee: Add listInputFieldChoices method

## 0.7.0

### Minor Changes

- 096d674: Changed incorrect account_id parameter to accountId. Also made sure all CLI parameters are documented as kebab-case.

## 0.6.4

### Patch Changes

- 4315531: All CLI commands are now just local plugins used to build a CLI specific SDK, and that CLI specific SDK is used to generate the CLI docs.

## 0.6.3

### Patch Changes

- 5b74010: Manifest is now lazy loading so it doesn't warn until you try to use it.

## 0.6.2

### Patch Changes

- ac0624d: Update warning message to reference correct lock-version command

## 0.6.1

### Patch Changes

- 38fe5c4: Clean up no .zapierrc warning

## 0.6.0

### Minor Changes

- c472d6f: Add manifest plugin to consume a supplied manifest, as well as lockVersion plugin to create or update the manifest.
- c402bcd: Remove \_\_registry in favor of getRegistry that also provides categories for functions.

### Patch Changes

- e08365e: Add support for lock file in generate-types command

## 0.5.2

### Patch Changes

- 218a3ca: reducing 'any' usage with minimal changes to runtime
- Updated dependencies [218a3ca]
  - @zapier/zapier-sdk-cli-login@0.3.2

## 0.5.1

### Patch Changes

- c662f79: Add proper README with dynamically-listed methods

## 0.5.0

### Minor Changes

- 741c385: All functions are now plugins, so _everything_ is a plugin.
