> ## 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.

# Use the SDK in Cloudflare Workers

> Pass credentials explicitly and give environment operations an owner that can await cleanup.

The State Machines SDK runs in Cloudflare Workers. A Worker receives secrets as bindings on `env`, not through `process.env`. Pass your API key to the client explicitly.

Store the key as a secret binding and construct the client with `new StateMachines({ apiKey: env.STATEMACHINES_API_KEY })`. Never include the key in a browser bundle or return it in an HTTP response.

## Give the operation enough lifetime

Environment startup can outlast a short HTTP request. Choose a job owner that can await creation, startup, the app operation, and deletion, such as a Queue consumer, a Workflow step or a Durable Object. The function below is for that owner to await. It is not an HTTP handler or a fire-and-forget task.

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

export async function runSalesforceJob(apiKey: string): Promise<number> {
  const sm = new StateMachines({ apiKey });
  const env = await sm.environments.create(
    { apps: ['salesforce'] },
    { wait: false },
  );

  try {
    await sm.environments.wait(env.id, { status: 'running' });
    const salesforce = await env.connect('salesforce');
    const response = await salesforce.fetch('/services/data/v67.0/limits');

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

    await response.arrayBuffer();

    return response.status;
  } finally {
    await env.delete();
  }
}
```

The example accepts creation with `wait: false`, obtains the environment ID, and waits for readiness inside `try`. Its `finally` awaits deletion even when startup or the app request fails. The example reads the response body so the Worker does not leave it unread.

Calling this function without awaiting it does not provide reliable cleanup. The surrounding execution must remain alive until the function finishes.

## Split a job across requests when needed

For a request-driven workflow, create with `wait: false`, persist the returned environment ID with the job, and read its status in later requests. Only call the app when the status is `running`.

The job must retain ownership of deletion on success, failure, and cancellation. Persist the idempotency key before creation if a retry must recover an uncertain response. See [operation recovery](/sdk-api/recovery).

Do not return raw credentials so a browser can poll an app. Management polling belongs on the trusted server using the persisted environment ID.

## Set independent deadlines

`attemptTimeoutMs` bounds each management HTTP attempt. `timeoutMs` bounds an SDK wait. A caller's `signal` can cancel the wait, but it does not delete the environment.

Choose deadlines that fit the surrounding execution and leave time for cleanup. If the execution cannot guarantee that lifetime, use persisted job ownership rather than increasing a request timeout alone.


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