Guides

Scheduled Execution

A scheduled check tells you what moved since the last one: what is new in the backlog, what is executing, and what finished. Every call it makes reads, so a read key covers the whole job and nothing in your cloud changes.

Run it on a schedule

Write the check

monitor.py
from levelfour import LevelFour

client = LevelFour()

overview = client.recommendations.get_overview()
print(overview)

processing = client.recommendations.list_in_progress()
print(processing)

for rec in client.recommendations.list(
    page_size=50,
    sort_by="monthly_savings",
    sort_order="desc",
):
    print(f"{rec.service}: ${rec.monthly_savings}/mo")

Three calls: Get overview for the headline numbers, List in-progress for what is executing right now, and List recommendations for the backlog, largest saving first. The TypeScript and Go form of each one sits on that same page.

Give it a key

The SDK reads LEVELFOUR_API_KEY from the environment, so the client takes no arguments and the scheduler supplies the value. The crontab entry sets it inline. The workflow reads it from a repository secret of the same name.

A key written inline in a crontab sits in plain text on the host, and a read key reaches every cost figure, recommendation and savings number in your organization. Keep it in a secrets manager or a file only the job's user can read. Give the schedule a read key, since it applies nothing. Key scopes has the split.

Point a scheduler at it

Add the line with crontab -e. It runs at 06:00 in the host's timezone, Monday to Friday.

0 6 * * 1-5 LEVELFOUR_API_KEY=l4_live_... python monitor.py >> /var/log/levelfour.log 2>&1

Commit monitor.py next to the workflow, and store the key as a repository secret named LEVELFOUR_API_KEY.

.github/workflows/monitor-savings.yml
name: Monitor Savings
on:
  schedule:
    - cron: '0 6 * * 1-5'

jobs:
  monitor:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.11'
      - run: pip install levelfour
      - name: Check recommendations
        env:
          LEVELFOUR_API_KEY: ${{ secrets.LEVELFOUR_API_KEY }}
        run: python monitor.py

GitHub schedules on UTC, so the same expression fires at 06:00 UTC rather than in your own zone.

GitHub Actions has three more workflows: a scheduled cost check that runs the SDK inline rather than from a committed script, a cost summary commented on a pull request, and a daily report uploaded as a build artifact.

Confirm the first run

The overview numbers in /var/log/levelfour.log after the scheduled minute are the proof: the entry fired and the key was accepted. On GitHub Actions the same output lands in the job log.

The crontab entry redirects stderr to that file too, so a traceback there means the job ran and a call failed. An empty or missing file means the entry never fired, or the job cannot write to that path. Run python monitor.py by hand once before you schedule it, so a silent morning afterwards has only one place to hide.

When to stop polling

A poll sees only the state at the minute it runs. An optimization that starts and finishes between two runs never appears in list_in_progress, and the log reads like a quiet day.

Webhooks deliver each change as it happens, covering acceptances, rejections and every stage of an optimization. Events has what each one means, and Register an endpoint is the call that subscribes you. Once an endpoint is live the schedule has nothing left to do.

Slack Integration and Google Chat Integration are complete receivers, signature verification included.

Next

  • Recommendations is every call the script makes, in Python, TypeScript and Go
  • Webhooks is the push alternative, with the payloads, the signing algorithm and the retry behavior
  • GitHub Actions has the pull request comment, a scheduled check that runs the SDK inline, and the daily report artifact
  • Authentication is which scope a scheduled key needs