> ## Documentation Index
> Fetch the complete documentation index at: https://docs.usestatemachines.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Save prepared data in a snapshot

> Save all apps in a running environment as reusable starting data.

Create a snapshot after preparing the records your tests need. A snapshot saves the data of every app in one running State Machines environment at one moment.

A snapshot does not import a customer's Salesforce organization. Its source is an environment you already created and populated in State Machines.

## Prepare and save the data

1. Create an environment and wait until it is `running`.
2. Write the records needed by the scenario through the app's native API.
3. Check that each write succeeded before saving a snapshot.
4. Call `env.snapshots.create({ name: 'Account fixture' })`.
5. Keep the returned snapshot ID to create environments from it.

The SDK waits for `ready` by default. Passing `{ wait: false }` returns after the save is accepted, with status `saving`. Use `sm.snapshots.wait(id, { status: 'ready' })` before restoring it. If the save fails, the wait throws `SnapshotFailedError`.

## Run a complete example

This example writes an Account, saves a snapshot, creates another environment from it, and queries the restored record. It deletes both environments in awaited cleanup and deletes the demonstration snapshot after saving ends. If a wait ends while the snapshot is still saving, the example reports the snapshot ID for later cleanup instead of calling delete, which would fail.

```ts theme={null}
import { StateMachines } from '@usestatemachines/sdk';

const sm = new StateMachines();
const source = await sm.environments.create(
  { apps: ['salesforce'] },
  { wait: false },
);

try {
  await sm.environments.wait(source.id, { status: 'running' });
  const salesforce = await source.connect('salesforce');
  const created = await salesforce.fetch(
    '/services/data/v67.0/sobjects/Account',
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ Name: 'Snapshot example' }),
    },
  );

  if (!created.ok) {
    throw new Error(`Account creation returned ${created.status}`);
  }

  const snapshot = await source.snapshots.create(
    { name: 'Account fixture' },
    { wait: false },
  );
  console.log('Snapshot ID for cleanup:', snapshot.id);

  try {
    await sm.snapshots.wait(snapshot.id, { status: 'ready' });
    const copy = await sm.environments.create(
      { snapshotId: snapshot.id },
      { wait: false },
    );

    try {
      await sm.environments.wait(copy.id, { status: 'running' });
      const restored = await copy.connect('salesforce');
      const query = encodeURIComponent(
        "SELECT Id, Name FROM Account WHERE Name = 'Snapshot example'",
      );
      const response = await restored.fetch(
        `/services/data/v67.0/query?q=${query}`,
      );

      if (!response.ok) {
        throw new Error(`Query returned ${response.status}`);
      }

      console.log(await response.json());
    } finally {
      await copy.delete();
    }
  } finally {
    const current = await sm.snapshots.get(snapshot.id);

    if (current.status === 'saving') {
      console.error('Save still pending; retry snapshot cleanup:', snapshot.id);
    } else {
      await sm.snapshots.delete(snapshot.id);
    }
  }
} finally {
  await source.delete();
}
```

The example obtains the snapshot ID with `wait: false` before waiting. If the save is still pending, deleting the source interrupts it. Read the snapshot again and delete it after it reaches `failed` or `ready`. Preserve this ID in job storage when cleanup must survive process exit.

The example uses `@usestatemachines/sdk` 0.6.0 or later. For a reusable fixture, keep the ready snapshot and record its ID instead of deleting it after the demonstration.

## Keep the source available until ready

Only one snapshot can be `saving` for an environment at a time. A concurrent attempt fails with `snapshot_in_progress`. List snapshots for that environment, wait for the active save to finish, then decide whether you need another snapshot.

Pausing or deleting the environment before the save completes fails the snapshot with code `interrupted`. A failed snapshot cannot start an environment. Inspect the failure and create another snapshot while the source is running.

A ready snapshot is independent of the source environment's running lifetime. Delete the source when preparation is complete. Follow [reusing snapshots](/snapshots/reuse) to start isolated copies of the prepared data.

## Recover an interrupted save request

Snapshot creation accepts `idempotencyKey`, `wait`, `timeoutMs`, and `signal`. The SDK creates a key for its own automatic retries. To recover across separate calls or process restarts, persist your own key with `{ environmentId, name }` before creation.

A timeout does not cancel the save. Keep the source running if you want saving to finish, then call `sm.snapshots.wait(id, { status: 'ready' })` again. With `wait: false`, `timeoutMs` does not apply. A failed snapshot carries `failure.code` and `failure.message`. The failure codes are `interrupted` and `internal_error`.

To create a snapshot, you need `snapshots:write` and access to the source environment's workspace. The source must be `running`, and its workspace must not be archived (`workspace_archived`). The snapshot takes its workspace from the source. It does not accept a separate app list, actor, or target workspace.

After a snapshot is ready, its saved data is fixed. `update()` changes only its name. To change the data, see [Refresh a fixture](/snapshots/reuse#refresh-a-fixture).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.