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

# API & Triggers

> Expose SLang actions through HTTP, queues, cron schedules, and events.

Triggers connect an action to an entry point. A trigger selects the transport, maps transport data into action arguments, and optionally protects execution with an `auth` block.

## HTTP Triggers

HTTP triggers expose actions as REST endpoints.

```slang theme={null}
entity Todo
  fields
    title: TEXT
    status: ENUM("todo", "done") := "todo"

action CreateTodo(title: TEXT): Todo
  body
    todo := create Todo {
      title := title
      status := "todo"
    }
    return todo

trigger CreateTodo on HttpRequest
  endpoint POST /todos
  statusCode 201
  body {
    id := @result.id
    title := @result.title
    status := @result.status
  }
  responseHeaders {
    "x-resource-type" := "todo"
  }
  arguments
    title := @request.body.title
```

HTTP triggers support these request sources:

| Source                     | Meaning                             |
| -------------------------- | ----------------------------------- |
| `@request.body.fieldName`  | JSON request body fields.           |
| `@request.path.paramName`  | Path parameters from `{paramName}`. |
| `@request.query.paramName` | Query string values.                |
| `@request.files.fieldName` | Uploaded files as `FILE` values.    |

### Entity arguments from path IDs

When an action argument is typed as an entity, you can bind it directly from a path-string ID. The runtime auto-resolves the path string into the entity instance for you — there is no need to declare a `TEXT` id parameter and then look the entity up with `single Entity where @id == X`.

```slang theme={null}
action GetTodo(todo: Todo): Todo
  body
    return todo

trigger GetTodo on HttpRequest
  endpoint GET /todos/{id}
  arguments
    todo := @request.path.id
```

The argument inside the action body is the resolved entity, so field access (e.g. `todo.title`) and relation traversal work as expected. This also applies to `PUT /{collection}/{id}` and `DELETE /{collection}/{id}` triggers that operate on a single resource.

By default, an HTTP trigger returns the action result with status `200` and no extra headers. Override that with `statusCode`, `body`, and `responseHeaders` when the public API shape should differ from the action result.

## Queues

Use a queue when a request should return quickly while background work continues.

```slang theme={null}
entity WorkItem
  fields
    label: TEXT

entity ProcessedWork
  fields
    label: TEXT

queue workQueue with WorkItem

action EnqueueWork(label: TEXT): WorkItem
  body
    item := create WorkItem {
      label := label
    }
    enqueue workQueue with item
    return item

action ProcessWork(message: WorkItem): VOID
  body
    create ProcessedWork {
      label := message.label
    }

trigger EnqueueWork on HttpRequest
  endpoint POST /work
  arguments
    label := @request.body.label

trigger ProcessWork on Queue
  queue workQueue
  arguments
    message := @message
```

Declare a queue with `queue name with EntityType`, enqueue with `enqueue name with value`, and consume with a `trigger ... on Queue` that maps `@message`.

## Cron Triggers

Cron triggers run on a schedule and have no request or subject context, so they cannot use `auth`, `@request`, or `@subject`.

```slang theme={null}
entity CleanupLog
  fields
    label: TEXT
    retentionDays: NUMBER

action NightlyCleanup(retentionDays: NUMBER): VOID
  body
    create CleanupLog {
      label := "nightly"
      retentionDays := retentionDays
    }

trigger NightlyCleanup on Cron
  schedule "0 2 * * *"
  arguments
    retentionDays := 30
```

Schedules are plain cron strings. Use five-field cron expressions for minute-level schedules, or a seconds field when the local dev server needs sub-minute testing.

## Event Triggers

Event triggers subscribe an action to an internal named event.

```slang theme={null}
entity AuditEntry
  fields
    message: TEXT

action RecordUserEvent(message: TEXT): VOID
  body
    create AuditEntry {
      message := message
    }

trigger RecordUserEvent on Event
  event userCreated
  arguments
    message := @message
```

Event and queue triggers both use `@message` for their payload. The difference is how the message is produced: queues are explicit SLang queues, while events are named application events emitted by the runtime.
