Views & exports
Read the shared saved views of a workspace and the runs they select, create and change views owned by your key's creator, and export a workflow's runs as CSV.
Operations: Views endpoints · Exports endpoints.
Saved views
A saved view is a board query — filters, sort and the board's column choice — with a name. Through the API a key sees every shared view of the workspace (visibility: "org" or "groups") and never a private one: a private id is a 404, indistinguishable from a missing view.
{
"id": "v1e2…", "name": "Open rush orders",
"query": { "workflowId": "3c1d…", "status": ["active", "on_hold"], "priority": ["urgent", "high"], "labels": ["lbl_rush"],
"assignee": null, "due": null, "q": "", "qMode": "prefix", "sort": { "key": "due", "dir": "asc" },
"columns": ["status", "priority", "due", "assignees"] },
"visibility": "org", "groupIds": [],
"owner": { "userId": "11111111-…", "name": "Ada Lovelace" },
"createdAt": "2026-09-24T16:00:00.000Z", "updatedAt": "2026-09-24T16:00:00.000Z"
}GET /v1/viewslists shared views by name (updatedSincefor a sync);GET /v1/views/{id}reads one.GET /v1/views/{id}/runsapplies the view's stored query exactly as the board does and returns full Run resources, paged likeGET /v1/runs(up to 100 per page) and limited to the key's allowlist. Two queries cannot be resolved for a key: a view that filters by the viewer (assignee: { "kind": "me" }) — callGET /v1/runs?assignee=u:<user id>instead — and a view sorted byprogress(computed in the app); both are a 422 (errors[].codeviewer_relativeandunsupported_sort).updatedSinceorders byupdatedAtascending instead of the view's sort.columnsis presentation only and ignored.
Owner rules
A saved view always has a person behind it. A view the API creates is owned by the member who created the key, who must still be a Builder or Admin of the workspace (else 403 not_allowed_for_key — mint a key as a current Admin). Each owner keeps at most 30 views (a 31st is a 422, errors[].code limit_reached).
POST /v1/views—{ name, query, visibility?: "org" (default) | "groups", groupIds? }. Send only thequerymembers you set; the rest take the board's defaults — any workflow, statusactive+on_hold, any priority, label, assignee and due date, no name filter, sorted bystartednewest first, and the board's default columns.sort: { "key": "name" }without adirtakes that key's natural direction (ascforname,key_dateanddue;descfor the rest). The 201 carries the complete query, with an absoluteLocation.groupsneeds at least one group of the workspace (a group id from another workspace is a 422,errors[].codeunknown_group).PATCH /v1/views/{id}— any subset of the same members. Aquerychanges only the members it sends; the rest keep the view's stored values, andnullclearsworkflowId,assigneeordue. Only a view owned by the key's creator can be changed through the API (403not_allowed_for_keyotherwise — create a view of your own), and the creator must still be a Builder or Admin of the workspace (403not_allowed_for_keyotherwise). Switching toorgdrops the group list.- In both, every
querymember is checked: a bad value is a 422 naming it (errors[].fieldquery.status.0), and a member the query does not have ("workflow"forworkflowId) is a 422unrecognized_keysrather than a silent default. DELETE /v1/views/{id}— removes any shared view, whoever owns it (the same power an Admin has in the app); audited under the key's name. 204.
curl -X POST https://app.processcart.com/api/v1/views \
-H "Authorization: Bearer pc_live_…" -H "Content-Type: application/json" \
-d '{ "name": "Active by name", "query": { "workflowId": "3c1d…", "status": ["active"], "sort": { "key": "name" } } }'The status labels a query.labels filter takes are listed by GET /v1/me (org.labels).
CSV export
GET /v1/exports/runs.csv?workflowId=… returns one workflow's runs as a CSV file, newest first:
curl "https://app.processcart.com/api/v1/exports/runs.csv?workflowId=3c1d…&status=completed&cols=status,started,completed&fields=amount,ship_date" \
-H "Authorization: Bearer pc_live_…" -o orders.csvworkflowIdis required — a CSV has one set of field columns. The run filters areGET /v1/runs's (status,priority,labels,assignee,due,q+qMode,updatedSince,includeTrashed).colspicks the run columns after "Run name":status,priority,labels,progress,key_date,due,started,completed(default: status, started, completed).fieldspicks field columns by key, in the workflow's own order (default: the first six fields); an unknown key is a 422.- Every cell is formatted as the app's own export formats it — currency with its symbol, dates in the workspace's time zone, members by name — and cells that could be read as formulas by a spreadsheet are defused.
text/csv; charset=utf-8with a BOM and CRLF line ends (so it opens cleanly in Excel) and aContent-Disposition: attachmentheader.- The whole file is built before it is sent; a selection above 10,000 rows is refused with a 422 (
errors[].codetoo_many_rows) — narrow the filter (by status, byupdatedSince, by label). - The usual pre-checks answer Problem Details: 404 for an unknown workflow, 409
workflow_not_published, 403 outside the key's allowlist.
For a machine-readable copy of every run, prefer GET /v1/runs with updatedSince — it carries canonical values rather than display text (Incremental sync).