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

# Declares work to run on a schedule: an ordered list of named steps, each an


> action to invoke or a script to run, bounded by the provider objects a workstream governs. The declaration replaces whatever was previously declared under the same name; enabled false removes it.

REST only, with no MCP write tool, and the asymmetry is the point. The scope a run acts on is read from the workstream at run time, so an automation that could declare its own scheduled work could hand itself a wider one than it was given — which is exactly what moving scope out of prose was for.




## OpenAPI

````yaml /api/openapi.json put /v1/scheduled-actions
openapi: 3.0.0
info:
  title: Erdo API
  description: >-
    Erdo's REST API: query and write datasets, run agents, manage threads,
    integrations, pages, evals, workstreams, and experiments. Authenticate with
    a Bearer API key (erdo_api_...) or scoped token (erdo_token_...).
  version: '2026-07-28'
servers:
  - url: https://api.erdo.ai
    description: Production
security:
  - bearerAuth: []
paths:
  /v1/scheduled-actions:
    put:
      summary: >
        Declares work to run on a schedule: an ordered list of named steps, each
        an
      description: >
        action to invoke or a script to run, bounded by the provider objects a
        workstream governs. The declaration replaces whatever was previously
        declared under the same name; enabled false removes it.


        REST only, with no MCP write tool, and the asymmetry is the point. The
        scope a run acts on is read from the workstream at run time, so an
        automation that could declare its own scheduled work could hand itself a
        wider one than it was given — which is exactly what moving scope out of
        prose was for.
      operationId: PUT:mcp.SetScheduledActionAPI
      requestBody:
        content:
          application/json:
            schema:
              properties:
                destination:
                  $ref: '#/components/schemas/mcp.ScheduledActionDestination'
                enabled:
                  title: >
                    enabled defaults to true. Passing false removes the
                    declaration.
                  type: boolean
                name:
                  description: >
                    run several without either replacing the other. Lowercase
                    letters, digits, hyphens and underscores.
                  title: >
                    name identifies this declaration within the organization, so
                    an org can
                  type: string
                schedule:
                  description: |
                    at eight.
                  title: >
                    schedule is a five-field cron expression, e.g. "0 8 * * *"
                    for every day
                  type: string
                steps:
                  description: |
                    under its name for the steps that follow.
                  items:
                    $ref: '#/components/schemas/mcp.ScheduledStep'
                  title: >
                    steps is ordered, and every one of them runs. Each step's
                    result is kept
                  type: array
                timezone:
                  description: >
                    "America/New\_York". Defaults to UTC. It matters for
                    anything comparing against a provider's own day boundary: an
                    ad account reports yesterday in the account's timezone, and
                    a run at 08:00 UTC is the previous afternoon in Miami.
                  title: |
                    timezone is the IANA zone the schedule is read in, e.g.
                  type: string
                workstream:
                  description: >
                    bound what this run may act on. The refs are read at run
                    time and handed to the steps as {{scope.ids}} and
                    {{scope.refs}}; nothing is copied here, so publishing a new
                    set takes effect on the next run with no edit to this
                    declaration.


                    A workstream governing nothing yet means a run that does
                    nothing and says so — never a run with no filter. Omit this
                    only for a declaration that genuinely acts on no provider
                    objects.
                  title: >
                    workstream is the slug of the workstream whose declared
                    external refs
                  type: string
              type: object
      responses:
        '200':
          content:
            application/json:
              schema:
                properties:
                  destination:
                    $ref: '#/components/schemas/mcp.ScheduledActionDestination'
                  enabled:
                    type: boolean
                  job_id:
                    description: |
                      history can be inspected through the automation surfaces.
                    title: >
                      job_id names the automation implementing this declaration,
                      so its run
                    type: string
                  name:
                    type: string
                  schedule:
                    type: string
                  steps:
                    items:
                      $ref: '#/components/schemas/mcp.ScheduledStep'
                    type: array
                  timezone:
                    type: string
                  workstream:
                    type: string
                type: object
          description: Success response
        default:
          $ref: '#/components/responses/APIError'
components:
  schemas:
    mcp.ScheduledActionDestination:
      description: |
        declaration whose steps act rather than report.
      properties:
        columns:
          additionalProperties:
            type: string
          description: >
            {{scope...}}, {{steps.\<name>...}}, {{result...}} for the last
            step's value, {{item}} when the last step returned a list, and
            {{now}}.


            A run whose final step returned a list writes one row per element,
            which is how a set of findings becomes a set of rows. Anything else
            writes one row.
          title: |
            columns maps each destination column to a template, resolved against
          type: object
        dataset:
          title: |
            dataset is where result rows are written.
          type: string
        key_column:
          description: >
            the same conclusion twice replaces it rather than appending a rival
            copy. A row whose key renders empty is not written. Omit it to
            append.
          title: >
            key_column makes the write an upsert on that column, so a run that
            reaches
          type: string
      title: >
        Where to record what a run produced. Omitting a destination is normal
        for a
      type: object
    mcp.ScheduledStep:
      description: >
        (app and key) OR a script to run, never both.


        Unlike a dataset row action, every step runs, in the order declared, and
        each one's result is kept under its name for the steps after it. That is
        because these steps are the reads a judgement is made from: a step
        skipped because an earlier one succeeded would remove a threshold's only
        source without saying so.
      properties:
        app:
          description: >
            connected integration such as "google\_ads". Omit it for a script
            step.
          title: |
            app names the app an action belongs to — "erdo", or the slug of a
          type: string
        for_each:
          description: >
            {{placeholder}} resolving to one — {{scope.refs}} runs it once per
            governed object. The action is invoked once per element, with
            {{item}} and {{item\_index}} available in its input, and the step's
            result is the list of what came back. Every invocation counts
            against the run's budget.
          title: |
            for_each fans the action out over a list: a JSON array, or one
          type: object
        input:
          description: >
            may contain {{placeholder}} references resolved against the run:
            {{scope.ids}} for the provider ids this run may act on,
            {{scope.refs}} for the full objects, {{steps.\<name>}} for an
            earlier step's result, and {{now}}. Everything else passes through
            untouched, so a numeric setting stays a number.
          title: >
            input carries the action's own parameters, as a JSON object. String
            values
          type: object
        key:
          description: |
            a script step.
          title: >
            key names the action within that app, e.g. "query_google_ads". Omit
            it for
          type: string
        name:
          description: >
            \`steps.\<name>\`. Required, unique within the declaration, and a
            JavaScript identifier: lowercase letter first, then letters, digits
            and underscores.
          title: |
            name is how the steps after this one refer to what it returned, as
          type: string
        result_path:
          description: >
            Many actions wrap their answer in an envelope that echoes the
            request, and a path selects the part worth keeping. Defaults to the
            whole result.
          title: >
            result_path is a dotted path into the action's result, e.g.
            "results".
          type: string
        script:
          description: >
            body receiving (scope, steps, run): the objects this run may act on,
            the results of the steps before it addressed by name, and {now,
            budget, invocations} describing the run. What it returns becomes
            this step's result. It may also return a \`note\` explaining the
            decision, which is reported on the run result. A script shapes data:
            it cannot invoke actions or read datasets, because a declaration has
            to say what it calls and where it writes.


            Every \`steps.\<name>\` a script mentions must name a step declared
            before it. That is checked when the declaration is saved, so
            removing a read that a threshold depends on fails here rather than
            evaluating to nothing every morning.
          title: >
            script is JavaScript run instead of invoking an action. It is a
            function
          type: string
      title: >
        One step of a scheduled declaration. A step is EITHER an action to
        invoke
      type: object
  responses:
    APIError:
      content:
        application/json:
          schema:
            externalDocs:
              url: https://pkg.go.dev/encore.dev/beta/errs#Error
            properties:
              code:
                description: Error code
                example: not_found
                externalDocs:
                  url: https://pkg.go.dev/encore.dev/beta/errs#ErrCode
                type: string
              details:
                description: Error details
                type: object
              message:
                description: Error message
                type: string
            title: APIError
            type: object
      description: Error response
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: An Erdo API key (erdo_api_...) or scoped token (erdo_token_...).

````