Beta

API reference

Export API

GET /v1/export and GET /v1/export/{dataset} — every data point Agentower keeps, as JSON or CSV.

The export API returns the same datasets as the app's History → Export page, for scripts, spreadsheets and your own reporting. Scope: export:read (create an export key on History → Export). What a key can export follows its creator's current role — see Export your data. Metadata only: never chat text, messages, a routine's brief, keys or notification addresses. The exception is the work record of projects with Work details on: work and work_summary carry its instructions and the agent's summaries (first 600 characters, secrets masked) for a key whose person may approve the project.

#GET /v1/export

Lists the datasets this key may export, with their columns.

List datasets
curl "$AGENTOWER_URL/v1/export" -H "authorization: Bearer $AGENTOWER_EXPORT_KEY"
Response · 200
{
  "datasets": [
    {
      "name": "agents",
      "label": "Agents and subagents",
      "description": "One row per agent or subagent: its short ID and name, project, person, tool, model, state and why, when it started, last signalled and ended, active time, tokens and ≈ cost.",
      "dateFilter": true,
      "columns": ["agent_id", "name", "kind", "parent_agent_id", "subagent_type", "project", "person", "tool", "model", "model_name", "state", "reason", "state_since_utc", "started_at_utc", "last_signal_at_utc", "ended_at_utc", "active_minutes", "tokens_in", "tokens_out", "cost_usd_estimate", "machine", "guardrail_state", "guardrail_note", "imported"],
      "url": "/v1/export/agents"
    }
  ],
  "usage": "GET /v1/export/{dataset}?from=2026-09-01&to=2026-09-30&format=json|csv&limit=1000&offset=0 (times in UTC)"
}

The datasets are agents, state_changes, work, work_summary, audit, usage_daily, projects, members, guardrails, channels, routines, routine_runs, computers, keys, my_data (what Agentower keeps about the key's own person, across their workspaces) and plan_accounts (plan limits per account and window). Not exported: agent chats (never — chat text is held only while the agent is open) and routines' briefs.

#GET /v1/export/{dataset}

QueryDefaultNotes
fromeverythingStart: a date (2026-09-01), an ISO time, or milliseconds. UTC
toeverythingEnd, inclusive of the whole day for a date
formatjsonjson or csv
limit1000Rows per page, at most 50,000
offset0Rows to skip

from and to apply to datasets with "dateFilter": true.

Agents, as JSON
curl "$AGENTOWER_URL/v1/export/agents?from=2026-09-01&limit=1" \
  -H "authorization: Bearer $AGENTOWER_EXPORT_KEY"
Response · 200
{
  "dataset": "agents",
  "columns": ["agent_id", "name", "kind", "parent_agent_id", "subagent_type", "project", "person", "tool", "model", "model_name", "state", "reason", "state_since_utc", "started_at_utc", "last_signal_at_utc", "ended_at_utc", "active_minutes", "tokens_in", "tokens_out", "cost_usd_estimate", "machine", "guardrail_state", "guardrail_note", "imported"],
  "rows": [
    {
      "agent_id": "DPP-01", "name": "Sarah", "kind": "agent", "parent_agent_id": null, "subagent_type": null,
      "project": "data-pipeline", "person": "Alex", "tool": "nightly-import", "model": null, "model_name": null,
      "state": "done", "reason": null,
      "state_since_utc": "2026-09-30T09:12:04.000Z", "started_at_utc": "2026-09-30T09:00:00.000Z",
      "last_signal_at_utc": "2026-09-30T09:12:04.000Z", "ended_at_utc": "2026-09-30T09:12:04.000Z",
      "active_minutes": 12, "tokens_in": 0, "tokens_out": 0, "cost_usd_estimate": 0,
      "machine": null, "guardrail_state": null, "guardrail_note": null, "imported": false
    }
  ],
  "count": 1,
  "nextOffset": 1
}

agent_id is the agent's short ID, which never changes; name is its first name — empty for subagents. Only open agents' names are unique, so a finished agent may share a name with another.

When there are more rows, nextOffset is the offset for the next page (and the x-next-offset header says the same); on the last page it's null.

State changes, as CSV
curl "$AGENTOWER_URL/v1/export/state_changes?from=2026-09-01&to=2026-09-30&format=csv" \
  -H "authorization: Bearer $AGENTOWER_EXPORT_KEY"
Response · 200
at_utc,agent_id,project,person,model_name,from_state,to_state,reason

CSV comes as a download (content-disposition: attachment), with a header row. Cells that a spreadsheet could run as formulas are made safe.

#The work record dataset

work has one row per step of the work record — a file changed, a command, a test run, a commit, a push, a pull request, "and N more", or the end of a turn — in time order. Subagents' steps have parent_agent_id set; person is the top-level agent's person. A column is null when the step doesn't have it, or the tool couldn't measure it (never 0 in its place).

ColumnWhat it is
at_utc, agent_id, parent_agent_id, project, personWhen, which agent (and its parent, for a subagent), project and person
turnThe turn number within the top-level agent's session (1, 2, …)
kindedit, command, tests, commit, push, pr, turn_end, more, prompt (the instruction that started the turn) or summary (the agent's closing summary). prompt and summary rows exist only for projects with Work details on
categoryFor a command: test, build, lint, install, git, run or other
lines_added, lines_removed, new_fileFor a file change
filesFiles changed — on turn_end, the turn's total
runsFor a command: how many commands of the same kind in a row were folded into this step
exit_codeFor a command or test run (0 = success)
tests_passed, tests_failed, tests_skippedFrom the test runner's summary, when it printed one Agentower recognises
commits, commitHow many commits, and the short hash of the last
pushed, pull_requestsWhether a branch was pushed; pull requests opened
more_stepsFor more: steps in the turn beyond what was sent one by one
path, tool, failed_tests, commit_subject, branch, pr_number, pr_urlNames — the file's path relative to the repository, the git sub-command or test runner, failed tests' names (separated by ; ), the commit's first line, the branch, the pull request. Only kept for projects with Work details on, and only filled in for a key whose person may approve the project (owners, and approvers of that project); otherwise null
streamThe name of the work stream the agent was in at the time; null for steps from before streams
textOn a prompt row, the first 600 characters of the instruction; on a summary row, the agent's own closing summary — what it says it did, not verified. Code blocks removed and secrets replaced by [hidden]. Same rule as the names: Work details on, and a key whose person may approve the project; otherwise null

The turn_end row also carries the turn's totals (files, lines_added, lines_removed, commits, pushed, pull_requests and the last test result). Never code, diffs or command lines — Agentower doesn't keep them.

#The work summary dataset

work_summary is the work record rolled up by work stream and ISO week (Monday to Sunday, UTC) — the same numbers as History → Work. One row per stream, project and week, newest week first. The date filter picks the steps that count. One request covers at most 56 days (8 weeks): a wider range is cut to its newest 56 days, and the answer says so in an x-agentower-note header (and a note field in JSON). Ask for older weeks with their own from and to. Building the summary reads every step in the range, so those rows count against the workspace's daily export budget (see Errors).

ColumnWhat it is
weekThe ISO week, e.g. 2026-W41
week_start_utcMonday 00:00 UTC of that week
stream, stream_sourceThe stream's name (No stream for steps without one) and where it came from: launch, manual, branch, folder or title (null without a stream)
projectThe project
files_created, files_editedFiles created and files edited (each file counted once a turn)
lines_added, lines_removed, commitsTotals for the week
last_test_result, last_test_passedThe week's last test run — "47 passed, 1 failed" when the runner printed counts, else "passed" or "failed" — and whether it passed
sessions_per_daySessions per day of the week, seven numbers separated by commas, Monday first (e.g. 1,0,2,0,0,0,0)
commit_subjectsThe commit messages (first lines, up to 20, separated by ; )
first_instructionThe stream's first instruction that week (600 characters at most, secrets masked)
agent_summary_not_verifiedThe agent's latest summary that week — what it says it did, not checked by Agentower

The counts are for everyone who may export. commit_subjects, first_instruction and agent_summary_not_verified are filled in only for projects with Work details on and only for a key whose person may approve the project; otherwise null.

#Routines, computers, keys, my data and plan limits

DatasetDate filterColumnsWho gets which rows
routinesNoroutine, project, computer, person, schedule (in words), schedule_cron, time_zone, permission_mode, allowed_tools (separated by ; ), max_minutes, max_tokens, enabled, approved_on_computer, approval_seen_at_utc, created_by, created_at_utc, updated_at_utcEvery routine in the workspace. allowed_tools only for a key whose person may approve the project (owners, and approvers of that project); otherwise null. Never the brief
routine_runsYes (scheduled_for_utc)scheduled_for_utc, routine, project, person, trigger, state, reason, started_at_utc, ended_at_utc, agent_id, tokens, cost_usd_estimateEvery run, and every time skipped or blocked
computersNocomputer (its label), computer_id (random), os, person, first_seen_at_utc, last_seen_at_utc, computer_allows, answers_from_app, hook_version, setup, last_hook_at_utc, last_telemetry_at_utc, last_status_line_at_utc, channel_connected_at_utc, key_nameThe key's person's own computers; an owner's key gets everyone's. Never the computer's real name
keysNoname, kind (Reporting, Telemetry only, Public stats, MCP, Agent actions or Export), scope, person, created_at_utc, last_used_at_utc, expires_at_utc, revoked_at_utcThe key's person's own keys; an owner's key gets everyone's. Never the key, its hash or its first characters
my_dataNoname, email, account_created_at_utc, workspace, role, joined_at_utc, weekly_email, background, colour, logo, highlight, has_profile_picture, profile_picture_type, profile_picture_updated_at_utc, profile_picture_urlOnly the key's own person, one row per workspace they belong to
plan_accountsNoprovider, provider_name, account, person, window, window_minutes, used_percent, resets_at_utc, updated_at_utcThe key's person's own plan accounts; an owner's key gets everyone's. One row per account and window (an account with no windows yet: one row with the window columns null). Never the account's email or ID

approved_on_computer says whether the version the computer last said it approved is the current one; it's null until the computer has said anything, and approval_seen_at_utc is when it last did. profile_picture_url is an address in the app (/api/avatars/…), not part of the API: open it while signed in to download the picture; it's null when there's no picture.

#Errors

StatuserrorWhen
400invalid_datefrom or to can't be read
400invalid_formatformat isn't json or csv
400invalid_paginglimit or offset isn't a whole number (limit at least 1)
403not_allowedThe key's creator's role can't export this dataset (the hint says which role is needed)
404unknown_datasetNo such dataset
401unauthorizedAlso when the key's person is no longer in the workspace
429rate_limitedMore than 60 requests a minute with this key
429export_budget_spentThe workspace has exported 250,000 rows today (app, API and MCP together; rows skipped by offset count too). It resets at 00:00 UTC

Exports through the API are recorded in the audit log, at most once per key and dataset every 10 minutes.