Skip to main content
Proton v5

Monitoring and data warehouse

Proton delivers what happens in the automations to the company's tools in two ways:

  • Pull, through the query API: runs, logs, metrics, exceptions, runners and events, with incremental load. This is the path to the data warehouse, Power BI and the corporate dashboards.
  • Receive, through webhooks: Proton notifies right away, with a signed message, when a run finishes, a batch does not run, an exception opens or a runner goes down. This is the path to the monitoring and ticketing tools.

Both are part of the Enterprise plan.

1. Read-only access​

The integration should not depend on a person nor be able to change anything. So use a robot user with a read-only profile and a token that only queries:

  1. Profile: in Access & Teams > Profile, create a profile (for example, "Read for integrations") with only the view permissions of what the integration will read: Runs, Exceptions, Runners, Automations, Automation groups and Environments.
  2. Robot user: in Access & Teams, on the users screen, use Create robot account and give it that profile.
  3. Token: in the robot's API tokens, generate a token with the Query API only (read) option. That token only performs the reads of the query API and gets 403 on any other route. Keep the token in the company's secret vault: it is shown only once.

In the portal, Settings > Query API brings these three steps together, with the status of each one: the organization's query tokens (owner, last use and expiration), the base URL and ready-made examples in curl, Python and Power BI. The Generate query token button asks who the token is for (preferably a robot) and creates a query-only token right away.

Teams

The API follows the same rule as the screens: an automation restricted to a team only shows up for people in it. For the integration to see everything, keep the robot in the right teams or give it an organization administrator profile.

2. The first call​

curl -s https://app.protoncloud.com.br/api/v1/runs?limit=5 \
-H "Authorization: Bearer $PROTON_TOKEN_CONSULTA"

The response brings the most recent runs, with the automation, dataset, group, environment, runner, status, end reason, duration and Correlation ID:

{
"data": [
{
"id": 48211,
"correlationId": "7f6c2d2e-5f0b-4a4a-9b9b-3c1f2a9e0d11",
"state": "finished",
"status": "failed",
"endReason": "technical_error",
"startedAt": "2026-10-19T14:58:00.000Z",
"finishedAt": "2026-10-19T15:00:00.000Z",
"durationMs": 120000,
"automation": { "id": 5, "name": "Supplier registration" },
"environment": { "id": 2, "name": "Production", "production": true },
"link": "https://app.protoncloud.com.br/automations/center/dataset/40/cycle/7/dataset-run/48211/details"
}
],
"hasMore": true,
"nextCursor": "eyJvIjoiZGlzcGF0Y2hlZCIsImsiOls0ODIxMV19"
}

3. Incremental load​

Each incremental listing reads in the order things happened and returns, in nextCursor, where the read stopped, including on the last page. The load keeps that cursor and, on the next round, comes back with it: it receives only what arrived after, without repeating or skipping.

Table in the data warehouseRouteFirst loadKey
Runs/v1/runsfinishedSinceid
Log lines/v1/logsfromid
Exceptions/v1/exceptionsupdatedSinceid (an exception comes back when it changes)
Events/v1/eventssinceid
Automations, groups and environments/v1/automations, /v1/groups, /v1/environmentsFull loadid

Write by id (insert or update): that way, repeating a page never duplicates a row.

import json
import os
import time
from pathlib import Path

import requests

BASE = "https://app.protoncloud.com.br/api/v1"
STATE = Path("proton_state.json")

session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['PROTON_TOKEN_CONSULTA']}"


def read_state():
return json.loads(STATE.read_text()) if STATE.exists() else {}


def save_state(state):
STATE.write_text(json.dumps(state))


def load(route, key, state, first_load, write):
"""Reads the route from the last saved cursor (or from the first load) and writes each page."""
params = {"cursor": state[key]} if key in state else dict(first_load)
while True:
response = session.get(f"{BASE}{route}", params={**params, "limit": 500}, timeout=60)
if response.status_code == 429:
time.sleep(int(response.headers.get("Retry-After", "60")))
continue
response.raise_for_status()
page = response.json()

write(page["data"]) # insert or update by id

if page["nextCursor"]:
state[key] = page["nextCursor"]
save_state(state)
if not page["hasMore"]:
return
params = {"cursor": page["nextCursor"]}


state = read_state()
load("/runs", "runs", state, {"finishedSince": "2026-10-01T00:00:00Z"}, write_runs)
load("/logs", "logs", state, {"from": "2026-10-01T00:00:00Z"}, write_log_lines)
load("/exceptions", "exceptions", state, {"updatedSince": "2026-10-01T00:00:00Z"}, write_exceptions)
load("/events", "events", state, {"since": "2026-10-01T00:00:00Z"}, write_events)

Run the load at the interval the company needs (every 5 minutes, every hour). The write_... functions are your data warehouse's.

4. Ready-made indicators​

For a dashboard that does not need the data row by row, /v1/metrics delivers the period's indicators already calculated: runner availability, success and failure rate, average processing time (with p95), MTTR, reprocessings, downtime and the trend by day or week, by automation, group, environment or runner.

curl -s "https://app.protoncloud.com.br/api/v1/metrics?from=2026-10-01T00:00:00Z&groupBy=day" \
-H "Authorization: Bearer $PROTON_TOKEN_CONSULTA"

What each indicator counts is in the reference.

Good practices​

  • Limit: 600 calls per token every 5 minutes. On a 429, wait for the time in the Retry-After header and go on from the same cursor.
  • Dates: everything comes in UTC (ISO 8601). Convert to the company's time zone when displaying.
  • New fields: v1 only grows. Treat an unknown field as optional and do not break the load because of it.
  • One token per integration: if one leaks, revoke only that one, in the robot's API tokens.
  • Correlation ID: the same id shows up in the runs, in the log and in the systems the automation called. Use it to match Proton with the logs of the rest of the company.