Article · part of a guide
API Driven Workflows for Terraform and OpenTofu
Learn how to take an API driven approach with examples

Key takeaways
- API-driven runs in Scalr use a push-based model, giving you full control over when a Terraform or OpenTofu run is triggered.
- API-driven runs suit real-time or event-driven provisioning, integration with external systems like Slack or New Relic, and complex custom automation.
- The example Python workflow uploads a configuration version to an existing workspace, then triggers a run via the Scalr API, with an is-dry flag to choose a speculative plan or a full apply.
- Combining VCS-driven and API-driven runs is often most effective: VCS handles versioning while API runs add agility for dynamic changes.
Most people run Terraform or OpenTofu in Scalr through the CLI or a connected version control system (VCS). This post covers a less common path: triggering a run through the API. The difference is control. With a VCS-driven run, something in your repository sets the run off. With an API-driven run, you make the call yourself, so you decide exactly when it happens. Here are a few reasons you might want that.
When Do You Need Real-Time or Event-Driven Provisioning?
Sometimes a run has to fire the moment something happens, not on a schedule or a git push. An API-driven run can be triggered programmatically in response to an event, so infrastructure changes follow events as they happen. That matters most when waiting for someone to click a button isn't an option.
How Do You Integrate Runs with External Systems?
If you need tight integration with external systems, calling the API directly is often the better option. This comes up when Terraform has to talk to custom scripts, external APIs, or other tools that aren't connected to your VCS provider. Going through the API gives you room to handle those integrations however you want. For example, if an alert goes off in New Relic, you might have a specific workspace and configuration update that needs to be made in response to that alert. A few customers also integrate with Slack so they can kick off runs from Slack in certain scenarios.
Can the API Handle Custom Workflows and Complex Automation?
Some automation goes past what a VCS-driven run can do on its own. When you need to chain several steps together, or wire a run into systems that have nothing to do with your repository, the API gives you room to do it. It's not unusual to see the API approach used with tools such as GitHub Actions, Harness, Bamboo, or Jenkins.
What Does an API-Driven Workflow Look Like in Practice?
In this example, we'll upload a new configuration version (can be Terraform or OpenTofu) to an existing workspace, and then execute a new run.
Prerequisites
You'll need values for the following objects in Scalr:
- API token
- URL for your Scalr account
- Workspace ID
- Environment ID
- Terraform configuration files that are in a tar.gz file
Script
The sample script below covers the basic steps, and you can modify it to suit your setup. Make sure to update the token, base_url, env_id, ws_id, and upload_archive_path with values specific to your Scalr account. You can also update the is_dry_run flag based on the type of run you want to execute, a dry (speculative plan) run or a full Terraform apply.
import requests
token = ""
base_url = 'https://example.scalr.io'
headers = {
'Prefer': 'profile=preview',
'accept': 'application/vnd.api+json',
'content-type': 'application/vnd.api+json',
'Authorization': f'Bearer {token}'
}
env_id = ""
ws_id = ""
is_dry_run = True
upload_archive_path = ''
## Create CV
url = f'{base_url}/api/iacp/v3/configuration-versions'
data = {
'data': {
'attributes': {
"auto-queue-runs": False,
},
'relationships': {
'workspace': {
'data': {
'type': 'workspaces',
'id': ws_id
}
}
},
'type': 'configuration-versions'
}
}
response = requests.post(url, headers=headers, json=data)
cv_id = None
if response.status_code == 201:
# Successful request
result = response.json()
# Process the response data
print(result)
cv_id = result['data']['id']
else:
# Request failed
raise Exception(f"Error: {response.status_code} - {response.text}")
upload_url = result['data']['links']['upload']
print(upload_url)
upload = requests.put(upload_url, headers={'Content-Type': 'application/octet-stream'}, data=open(upload_archive_path, 'rb'))
print(upload.status_code)
## create run
url = f'{base_url}/api/iacp/v3/runs'
data = {
'data': {
'attributes': {
"is-dry": is_dry_run,
},
'relationships': {
'configuration-version': {
'data': {
'type': 'configuration-versions',
'id': cv_id
}
},
'workspace': {
'data': {
'type': 'workspaces',
'id': ws_id
}
}
},
'type': 'runs'
}
}
response = requests.post(url, headers=headers, json=data)
if response.status_code == 201:
# Successful request
result = response.json()
# Process the response data
print(result)
else:
# Request failed
raise Exception(f"Error: {response.status_code} - {response.text}")The script targets an existing workspace. To start from scratch, create the workspace first (in the UI, with the Scalr Terraform provider, or through the API) and pass its ID as ws_id. Workspace settings offer many more options, including whether runs execute immediately or wait until someone makes a separate request. The full Scalr API documentation is here.
Should You Use VCS-Driven or API-Driven Runs?
For a lot of teams, the best setup uses both. VCS keeps your infrastructure as code versioned and reviewable, and API-driven runs cover the dynamic, real-time changes that don't fit a git workflow. Which one you reach for depends on what a given workspace needs.
About the author

director of platform engineering at Scalr
Ryan Fee is the director of platform engineering at Scalr, with over 15 years of experience improving infrastructure experiences at companies large and small.
Part of this guide
15 sheets
What is OpenTofu?
- What Is an OpenTofu Management Platform?
- An Overview of Scalr's CI/CD Capabilities for Terraform and OpenTofu
- Debugging opentofu apply Failures
- Scalr VSCode Extension for Terraform & OpenTofu
- The Terraform & OpenTofu Terralith
- New Feature: Terraform & OpenTofu Ephemeral Workspaces
- Understanding Terraform & OpenTofu Workspaces
- OpenTofu Language Guide
- OpenTofu Runs are Free in Scalr
- 10 OpenTofu Commands
- Finding a Home for OpenTofu: Unpacking The Decision to Join The Linux Foundation
- Announcing OpenTF
- Is Terraform Still Open Source?