Detected country: US
logo
Sign InGet Early Access
GuideRecipesDeveloper
‌
‌
‌
logo

Powered by

  • Home
  • Running and Automating
  • Run from your environment via API

Run from your environment via API

3min read

Share

Use Run in the app, or call the API from your environment. Set BALLET_API_TOKEN to a workspace API token.

HTTP

Starts the run, then polls GET /runs/:id until it's completed, failed, or cancelled.

:::warning API runs need a complete input body. You will need to manually input this.

:::

cURL

# 1. Start the run and capture the runId
RUN_ID=$(curl -s --request POST \
  --url '/api/playbooks/:id/run' \
  --header "Authorization: Bearer $BALLET_API_TOKEN" \
  --header 'Content-Type: application/json' \
  --data '{"input":{}}' | jq -r .runId)

# 2. Poll until the run finishes
while true; do
  RUN=$(curl -s -H "Authorization: Bearer $BALLET_API_TOKEN" \
    '/api/runs/"$RUN_ID"')
  echo "$RUN" | jq -r .status
  case "$(echo "$RUN" | jq -r .status)" in
    completed|failed|cancelled) echo "$RUN" | jq .; break ;;
  esac
  sleep 2
done

Node

// 1. Start the run
const res = await fetch('/api/playbooks/:id/run', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.BALLET_API_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
  "input": {}
}),
});
const { runId } = await res.json();

// 2. Poll until the run finishes
const terminal = new Set(['completed', 'failed', 'cancelled']);
while (true) {
  const r = await fetch(`/api/runs/${runId}`, {
    headers: { Authorization: `Bearer ${process.env.BALLET_API_TOKEN}` },
  });
  const run = await r.json();
  console.log(run.status);
  if (terminal.has(run.status)) { console.log(run); break; }
  await new Promise(r => setTimeout(r, 2000));
}

Python

import json, os, time, requests

# Round-trip through json.loads so JSON booleans / null work in Python.
payload = json.loads('''{
  "input": {}
}''')

# 1. Start the run
res = requests.post(
    '/api/playbooks/:id/run',
    headers={
        'Authorization': f"Bearer {os.environ['BALLET_API_TOKEN']}",
        'Content-Type': 'application/json',
    },
    json=payload,
)
res.raise_for_status()
run_id = res.json()['runId']

# 2. Poll until the run finishes
terminal = {'completed', 'failed', 'cancelled'}
headers = {'Authorization': f"Bearer {os.environ['BALLET_API_TOKEN']}"}
while True:
    run = requests.get(f"/api/runs/{run_id}", headers=headers).json()
    print(run['status'])
    if run['status'] in terminal:
        print(run)
        break
    time.sleep(2)

Stream

One request — streams live step events over SSE and closes on run_stop. Add Accept: text/event-stream.

cURL

curl -N --request POST \
  --url '/api/playbooks/:id/run' \
  --header "Authorization: Bearer $BALLET_API_TOKEN" \
  --header 'Accept: text/event-stream' \
  --header 'Content-Type: application/json' \
  --data '{"input":{}}'

# Streams SSE on one connection: stream_start, step_start,
# step_stop, … then run_stop (final output) or
# stream:timeout (run still in progress — poll GET /runs/:id).

Node

const res = await fetch('/api/playbooks/:id/run', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.BALLET_API_TOKEN}`,
    Accept: 'text/event-stream',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
  "input": {}
}),
});
const reader = res.body.getReader();
const decoder = new TextDecoder();
let buf = '';
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  buf += decoder.decode(value, { stream: true });
  const parts = buf.split('\n\n');
  buf = parts.pop() ?? '';
  for (const part of parts) {
    if (!part.includes('data:')) continue;
    const data = JSON.parse(part.match(/data: (.+)/)?.[1] ?? '{}');
    console.log(part.match(/event: (.+)/)?.[1] ?? 'message', data);
    if (part.includes('event: run_stop')) process.exit(0);
  }
}

Python

import json, os, requests

# Round-trip through json.loads so JSON booleans / null work in Python.
payload = json.loads('''{
  "input": {}
}''')

headers = {
    'Authorization': f"Bearer {os.environ['BALLET_API_TOKEN']}",
    'Accept': 'text/event-stream',
    'Content-Type': 'application/json',
}
with requests.post('/api/playbooks/:id/run', headers=headers, json=payload, stream=True) as res:
    res.raise_for_status()
    buf = ''
    for chunk in res.iter_content(decode_unicode=True):
        if not chunk: continue
        buf += chunk
        while '\n\n' in buf:
            part, buf = buf.split('\n\n', 1)
            if 'data:' not in part: continue
            data = json.loads(part.split('data:', 1)[1].strip())
            print(data)
            if 'run_stop' in part:
                raise SystemExit(0)

:::tip Looking to create an API token?

You can create an API token by going to Settings > API Tokens

:::

Share