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.
curl "$AGENTOWER_URL/v1/export" -H "authorization: Bearer $AGENTOWER_EXPORT_KEY"{
"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}
| Query | Default | Notes |
|---|---|---|
from | everything | Start: a date (2026-09-01), an ISO time, or milliseconds. UTC |
to | everything | End, inclusive of the whole day for a date |
format | json | json or csv |
limit | 1000 | Rows per page, at most 50,000 |
offset | 0 | Rows to skip |
from and to apply to datasets with "dateFilter": true.
curl "$AGENTOWER_URL/v1/export/agents?from=2026-09-01&limit=1" \
-H "authorization: Bearer $AGENTOWER_EXPORT_KEY"{
"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.
curl "$AGENTOWER_URL/v1/export/state_changes?from=2026-09-01&to=2026-09-30&format=csv" \
-H "authorization: Bearer $AGENTOWER_EXPORT_KEY"at_utc,agent_id,project,person,model_name,from_state,to_state,reasonCSV 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).
| Column | What it is |
|---|---|
at_utc, agent_id, parent_agent_id, project, person | When, which agent (and its parent, for a subagent), project and person |
turn | The turn number within the top-level agent's session (1, 2, …) |
kind | edit, 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 |
category | For a command: test, build, lint, install, git, run or other |
lines_added, lines_removed, new_file | For a file change |
files | Files changed — on turn_end, the turn's total |
runs | For a command: how many commands of the same kind in a row were folded into this step |
exit_code | For a command or test run (0 = success) |
tests_passed, tests_failed, tests_skipped | From the test runner's summary, when it printed one Agentower recognises |
commits, commit | How many commits, and the short hash of the last |
pushed, pull_requests | Whether a branch was pushed; pull requests opened |
more_steps | For more: steps in the turn beyond what was sent one by one |
path, tool, failed_tests, commit_subject, branch, pr_number, pr_url | Names — 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 |
stream | The name of the work stream the agent was in at the time; null for steps from before streams |
text | On 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).
| Column | What it is |
|---|---|
week | The ISO week, e.g. 2026-W41 |
week_start_utc | Monday 00:00 UTC of that week |
stream, stream_source | The stream's name (No stream for steps without one) and where it came from: launch, manual, branch, folder or title (null without a stream) |
project | The project |
files_created, files_edited | Files created and files edited (each file counted once a turn) |
lines_added, lines_removed, commits | Totals for the week |
last_test_result, last_test_passed | The week's last test run — "47 passed, 1 failed" when the runner printed counts, else "passed" or "failed" — and whether it passed |
sessions_per_day | Sessions per day of the week, seven numbers separated by commas, Monday first (e.g. 1,0,2,0,0,0,0) |
commit_subjects | The commit messages (first lines, up to 20, separated by ; ) |
first_instruction | The stream's first instruction that week (600 characters at most, secrets masked) |
agent_summary_not_verified | The 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
| Dataset | Date filter | Columns | Who gets which rows |
|---|---|---|---|
routines | No | routine, 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_utc | Every 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_runs | Yes (scheduled_for_utc) | scheduled_for_utc, routine, project, person, trigger, state, reason, started_at_utc, ended_at_utc, agent_id, tokens, cost_usd_estimate | Every run, and every time skipped or blocked |
computers | No | computer (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_name | The key's person's own computers; an owner's key gets everyone's. Never the computer's real name |
keys | No | name, 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_utc | The key's person's own keys; an owner's key gets everyone's. Never the key, its hash or its first characters |
my_data | No | name, 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_url | Only the key's own person, one row per workspace they belong to |
plan_accounts | No | provider, provider_name, account, person, window, window_minutes, used_percent, resets_at_utc, updated_at_utc | The 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
| Status | error | When |
|---|---|---|
| 400 | invalid_date | from or to can't be read |
| 400 | invalid_format | format isn't json or csv |
| 400 | invalid_paging | limit or offset isn't a whole number (limit at least 1) |
| 403 | not_allowed | The key's creator's role can't export this dataset (the hint says which role is needed) |
| 404 | unknown_dataset | No such dataset |
| 401 | unauthorized | Also when the key's person is no longer in the workspace |
| 429 | rate_limited | More than 60 requests a minute with this key |
| 429 | export_budget_spent | The 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.