Sanity Library Reference Docs
    Preparing search index...
    interface WorkflowClient {
        action?: (action: any, options?: { tag?: string }) => Promise<any>;
        config?: () => WorkflowClientConfigState;
        create: <T extends { _id: string; _type: string }>(
            doc: T,
            options?: WorkflowCommitOptions,
        ) => Promise<T>;
        fetch: <T = unknown>(
            query: string,
            params?: Record<string, unknown>,
            options?: WorkflowFetchOptions,
        ) => Promise<T>;
        getDataUrl?: (operation: string, path?: string) => string;
        getDocument: <T = SanityDocument>(
            id: string,
            options?: { tag?: string },
        ) => Promise<T | null | undefined>;
        patch: (documentId: string) => WorkflowPatch;
        request?: <T>(opts: WorkflowRequestOptions) => Promise<T>;
        transaction: () => WorkflowTransaction;
        withConfig?: (config: WorkflowClientConfig) => this;
    }
    Index

    Properties

    action?: (action: any, options?: { tag?: string }) => Promise<any>

    Optional — present on the real @sanity/client and on the test fake (from @sanity-labs/client-fake-for-test@0.2.0+). Effect handlers use it to dispatch Content Releases and version actions (sanity.action.release.publish, sanity.action.document.version.create, etc.) without depending on the broader client surface.

    Typed loosely so both the strict real-client Action union and the test fake's discriminated shape satisfy the field entry. Callers (effect handlers) pass the concrete action object literal.

    Read the effective client configuration. The engine uses apiHost for account-global identity routing and projectId for project directory and organization lookups. Without projectId, organization attributes cannot be loaded and project-scoped principals cannot use the directory bridge.

    For clients without WorkflowClient.withConfig, an omitted apiVersion means the implementation must already serve ENGINE_API_VERSION. A declared apiVersion other than that version skips organization attributes with a warning.

    create: <T extends { _id: string; _type: string }>(
        doc: T,
        options?: WorkflowCommitOptions,
    ) => Promise<T>

    Create a brand-new document. Errors loud (HTTP 409 / mutation error) if a document with the same _id already exists. The engine uses this whenever it mints a new doc — instances on startInstance, child instances on spawn, new definitions on first deploy.

    The interface deliberately omits createOrReplace: for existing docs the engine uses patch().set(...).ifRevisionId(rev).commit(), which fails fast if the doc was deleted or concurrently modified (createOrReplace's behaviour on a missing target is ambiguous and its rev-less form silently clobbers). If a consumer truly needs createOrReplace they can extend their own client type.

    fetch: <T = unknown>(
        query: string,
        params?: Record<string, unknown>,
        options?: WorkflowFetchOptions,
    ) => Promise<T>
    getDataUrl?: (operation: string, path?: string) => string

    Build a resource-bound data URL, as on SanityClient. Used to confirm document availability.

    getDocument: <T = SanityDocument>(
        id: string,
        options?: { tag?: string },
    ) => Promise<T | null | undefined>
    patch: (documentId: string) => WorkflowPatch
    request?: <T>(opts: WorkflowRequestOptions) => Promise<T>

    Optional — present on the real @sanity/client. Without it, ACL grant discovery uses its dry-run fallback, while a definition containing role-constrained assignment fields fails loudly because the engine cannot read the project membership directory required to validate assignees.

    Raw request transport. The engine passes the request target through url; relative paths must resolve against the client's configured API host, matching supported SanityClient.request implementations.

    transaction: () => WorkflowTransaction

    Build a multi-document transaction. All operations succeed or fail together. Used whenever the engine writes multiple documents that are provably in the same workflow resource (spawn fan-out, deploy batches, parent + child propagation that stays in one dataset).

    Shape matches @sanity/client.transaction() and the in-memory test client. patch() accepts a WorkflowPatch handle built via client.patch(id).set(...).ifRevisionId(rev) — pass the handle in without calling .commit() on it.

    withConfig?: (config: WorkflowClientConfig) => this

    Optional — present on the real @sanity/client and the in-memory test fake. Returns a sibling client with the given config overrides, inheriting everything else from the source (token, apiHost). The engine derives three things from it:

    • Cross-resource routing (resource + the dataset pair): a sibling for a foreign GDR when resourceClients doesn't map it. A client without withConfig makes foreign GDRs a loud routing error rather than a silent read of the wrong resource.
    • API-version normalization (apiVersion): every engine entry derives its working client with withConfig({apiVersion: ENGINE_API_VERSION}), so the caller's configured version never reaches engine traffic (the caller's own instance is untouched). A client without withConfig cannot be rebound and is used as-is — it must be built to serve ENGINE_API_VERSION already; older dated versions fail silently incomplete, not loud.
    • Effect request attribution (requestTagPrefix): handlers receive a derived client whose untagged traffic carries the effect tag while the caller's own client remains untouched. A client without withConfig uses the structural request wrapper instead.

    Dataset resources carry the {projectId, dataset} pair alongside resource: the real client routes by resource (it takes precedence in URL building), while the test fake keys its dataset registry by the pair. Known gap: the fake ignores resource, so it derives DATASET siblings only — a canvas/media-library derivation on the fake aliases the current store until the fake learns resource upstream.