LaufwerkLaufwerk
API reference

HTTP routes

defineHttpRoutes, authentication, HttpContext.startWorkflow, input and idempotency semantics.

HTTP routes are trusted project code outside durable workflow execution. Use them to validate requests and accept a workflow run. Import all types and defineHttpRoutes from @laufwerk/sdk/http.

defineHttpRoutes(routes)

Accepts readonly HttpRoute[] and returns it unchanged. Default-export the result from laufwerk/http.ts. Validation happens when the server loads the routes.

HttpRoute

PropertyTypeRequiredMeaning
methodstringYesUppercase HTTP method, e.g. "POST"
pathstringYesExact absolute pathname, e.g. "/triggers/review"
auth"owner" | "public" or authentication functionYesAccess policy
handler(request: Request, context: HttpContext) => Response | Promise<Response>YesStandard Web Request/Response handler

Paths are exact matches, not parameter patterns. A path must start with one /, contain no query, fragment, percent escape or backslash, and not normalize to a different pathname. Reserved prefixes are /api, /auth, /healthz, /brand, /assets. Reserved exact paths are /, /index.html, /client.js, /styles.css, /client.css, /favicon.ico. Duplicate method/path pairs are rejected.

Authentication

ValueBehavior
"owner"Requires the server's owner bearer token; a Studio cookie alone does not authenticate custom owner routes
"public"No route authentication
Function(request) => void | Response | Promise<void | Response>; return void to allow or a Response to reject

If custom authentication reads the body, read request.clone() so the handler can still consume the original. Return a rejection response, not false.

context.startWorkflow(input)

HttpContext has one method, startWorkflow. Its argument is HttpWorkflowStart:

PropertyTypeRequiredMeaning
workflowNamestringYesRegistered workflow name
inputunknownYesJSON-compatible input matching the workflow's payload schema
idempotencyKeystringYesNonblank submission key scoped to this HTTP method/path
admission{ groupId: string }NoRegister in the admission queue for later dispatcher handling

Returns Promise<{ runId: string; duplicate: boolean }> after acceptance commits. It does not wait for the workflow result. Each call commits independently; a later handler error does not roll back a run already accepted.

The HTTP submission key and workflow's idempotencyKey(input) are distinct identities. Retrying the same submission with the same data reuses acceptance; conflicting reuse is rejected. Input must contain only JSON values; functions, undefined, nonfinite numbers and nonplain objects are not valid submission data.

Example: authenticated entry point

http.ts
import { defineHttpRoutes } from "@laufwerk/sdk/http";

export default defineHttpRoutes([{
  method: "POST",
  path: "/triggers/review",
  auth: "owner",
  async handler(request, context) {
    const idempotencyKey = request.headers.get("idempotency-key");
    if (!idempotencyKey?.trim()) {
      return new Response("Missing Idempotency-Key", { status: 400 });
    }
    let input: unknown;
    try { input = await request.json(); }
    catch { return new Response("Expected JSON", { status: 400 }); }
    const accepted = await context.startWorkflow({
      workflowName: "review", input, idempotencyKey,
    });
    return Response.json(accepted, { status: 202 });
  },
}]);

Define a matching review workflow separately. Serve routes with laufwerk serve; --studio also serves Studio. Owner routes require a configured owner token. An HTTP 202 response means accepted, not completed or successful. Inspect the returned run ID through CLI/Studio.

On this page