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

# Quick Start

> Install the SDK, initialize a client, enqueue a job, add a worker handler, and inspect the run.

<Tip>
  **Live.** This area is documented as current, user-reliable behavior.
</Tip>

## Goal

Run your first Durable Job from TypeScript.

## Prerequisites

* Node.js 18 or newer
* A StackShift API key

## Workflow

<Steps>
  <Step>
    Install the SDK.
  </Step>

  <Step>
    Create a StackShift client.
  </Step>

  <Step>
    Enqueue a job with an idempotency key.
  </Step>

  <Step>
    Register a handler and expose an invocation route.
  </Step>

  <Step>
    Run the app and observe the job run in StackShift.
  </Step>
</Steps>

## Install the SDK

For TypeScript, install the npm package. For Go, install the public GitHub module with go get.

<CodeGroup>
  ```bash Install dependencies theme={null}
  npm install @stackshift-cloud/jobs
  ```

  ```bash Go theme={null}
  go get github.com/stackshiftCloud/jobs-go@v0.1.0
  ```
</CodeGroup>

## Initialize the client

The API key is the only required credential. It authenticates the request and scopes Durable Jobs internally, so you can use the SDK from any backend, whether or not that backend is deployed on StackShift.

<CodeGroup>
  ```ts lib/stackshift.ts theme={null}
  import { StackShift } from '@stackshift-cloud/jobs'

  export const stackshift = new StackShift({
    apiKey: process.env.STACKSHIFT_API_KEY!,
    baseUrl: process.env.STACKSHIFT_API_URL,
  })
  ```

  ```go Go theme={null}
  import stackshift "github.com/stackshiftCloud/jobs-go"

  client, err := stackshift.New(stackshift.Options{
    APIKey: os.Getenv("STACKSHIFT_API_KEY"),
    BaseURL: os.Getenv("STACKSHIFT_API_URL"),
  })
  ```
</CodeGroup>

## Enqueue a job

Use an idempotency key for any job started from an API request, checkout callback, signup flow, or webhook.

<CodeGroup>
  ```ts app/api/signup/route.ts theme={null}
  import { stackshift } from '@/lib/stackshift'

  export async function POST(request: Request) {
    const body = await request.json()

    const run = await stackshift.queue('emails').enqueue(
      'sendVerificationEmail',
      { userId: body.userId, email: body.email },
      {
        idempotencyKey: `verify:${body.userId}`,
        idempotencyTtl: '30d',
        handlerUrl: `${process.env.APP_URL}/api/stackshift/jobs`,
      }
    )

    return Response.json({ runId: run.id, status: run.status })
  }
  ```

  ```go Go theme={null}
  func signupHandler(w http.ResponseWriter, r *http.Request) {
    var body struct {
      UserID string `json:"userId"`
      Email  string `json:"email"`
    }
    _ = json.NewDecoder(r.Body).Decode(&body)

    run, err := client.Queue("emails").Enqueue(r.Context(),
      "sendVerificationEmail",
      map[string]any{"userId": body.UserID, "email": body.Email},
      &stackshift.EnqueueOptions{
        IdempotencyKey: "verify:" + body.UserID,
        IdempotencyTTL: "30d",
        HandlerURL: os.Getenv("APP_URL") + "/stackshift/jobs",
      },
    )
    if err != nil {
      http.Error(w, err.Error(), http.StatusBadGateway)
      return
    }

    _ = json.NewEncoder(w).Encode(map[string]any{
      "runId": run.ID,
      "status": run.Status,
    })
  }
  ```
</CodeGroup>

## Add a worker handler

<CodeGroup>
  ```ts jobs.ts theme={null}
  import { stackshift } from '@/lib/stackshift'
  import { sendEmail } from '@/lib/email'

  stackshift.job<{ userId: string; email: string }>('sendVerificationEmail', async ({ payload, step }) => {
    await step.run('send-email', async () => {
      await sendEmail({
        to: payload.email,
        subject: 'Verify your email',
        template: { name: "verify", userId: payload.userId },
      })

      return { sent: true }
    })

    return { ok: true }
  })
  ```

  ```go Go theme={null}
  client.Job("sendVerificationEmail", func(ctx context.Context, job stackshift.JobContext) (any, error) {
    var payload struct {
      UserID string `json:"userId"`
      Email  string `json:"email"`
    }
    if err := json.Unmarshal(job.Payload, &payload); err != nil {
      return nil, err
    }

    _, err := job.Step.Run(ctx, "send-email", func(ctx context.Context, invocation stackshift.HandlerInvocation) (any, error) {
      return map[string]any{"sent": true}, sendEmail(payload.Email, payload.UserID)
    })
    if err != nil {
      return nil, err
    }

    return map[string]any{"ok": true}, nil
  })
  ```
</CodeGroup>

<CodeGroup>
  ```ts app/api/stackshift/jobs/route.ts theme={null}
  import '@/jobs'
  import { stackshift } from '@/lib/stackshift'

  export async function POST(request: Request) {
    const invocation = await request.json()
    const { status, body } = await stackshift.handleInvocation(invocation)

    return Response.json(body, { status })
  }
  ```

  ```go Go theme={null}
  mux := http.NewServeMux()
  mux.Handle("/stackshift/jobs", client.HTTPHandler())

  if err := http.ListenAndServe(":8080", mux); err != nil {
    log.Fatal(err)
  }
  ```
</CodeGroup>

## Run and observe

* Run your app locally or deploy it to StackShift.
* Trigger the API route that enqueues the job.
* Open the Durable Jobs run in StackShift to see status, attempts, logs, payload, and timeline.

## Expected result

<Check>
  A job run is queued, invoked, completed, and visible in the Durable Jobs timeline.
</Check>

## Related guides

<CardGroup cols={2}>
  <Card title="Using Queues" href="/durable-jobs/using-queues">
    Use queues for background execution, retry policy, delayed jobs, and concurrency control.
  </Card>

  <Card title="Observability" href="/durable-jobs/observability">
    Inspect each job run through status, attempts, logs, payload, result, errors, and timeline.
  </Card>
</CardGroup>
