Skip to content

GET /views

List saved views

The saved views the caller may see. Naming a container answers the caller's own views plus what is shared into that container's path - the collection's, its hub's and the workspace-wide ones, computed in the query rather than filtered after a page. Naming none answers the caller's own views alone.

Query parameters

NameTypeRequiredDescription
container_idstring (uuid) optionalThe container whose shared views are wanted, together with the caller's own.

Responses

  • 200 The views
  • 4XX An error per RFC 9457 Problem
Example bash
curl -X GET "$HUBTASK_URL/views" \  -H "Authorization: Bearer $HUBTASK_TOKEN"

POST /views

Create saved view

Saves a view: a query in the DSL of POST /items:query, the layout it is drawn in, and the fields the client shows. The query is validated here, against the same catalogue and the same bounds as an ad-hoc one and with the same codes - a saved view that failed at read time would be a broken bookmark nobody can repair. The layout is validated against the declared set (/meta/capabilities, view_layouts), stored, echoed back, and never consulted: what a layout looks like is the client's business, which is what makes new views possible without a backend change. The creator owns the view, and it starts PRIVATE unless sharing says otherwise, under the same rules as :share.

Headers

NameTypeRequiredDescription
Idempotency-Keystring (uuid) optionalA UUID; identical requests return the same result for 24 h.

Request body application/json — SavedViewCreate

NameTypeRequiredDescription
scope_typestring
  • TENANT
  • HUB
  • COLLECTION
  • ACCOUNT
required
scope_idstring (uuid), or null optionalThe container for HUB and COLLECTION.
namestring
  • minLength: 1
  • maxLength: 200
required
layoutstring required
queryobject requiredThe query, anchored, in the use case's input shape - scope_container_id, not a nested scope object.
groupingobject optional
visible_fieldsarray of string optional
sharingstring
  • PRIVATE
  • SCOPE
  • PUBLIC_LINK
  • default: "PRIVATE"
optionalSCOPE at creation asks the same permission :share does.

Responses

Example bash
curl -X POST "$HUBTASK_URL/views" \  -H "Authorization: Bearer $HUBTASK_TOKEN" \  -H "Idempotency-Key: $(uuidgen)" \  -H "Content-Type: application/json" \  -d '{  "scope_type": "TENANT",  "scope_id": "018f6e2a-2b7c-7c1e-9b1a-3d5e6f7a8b9c",  "name": "string",  "layout": "string",  "query": {    "scope_container_id": "0192f000-0000-7000-8000-0000000000c0",    "filter": {      "field": "due_at",      "op": "LTE",      "value": "@today+P7D"    }  },  "grouping": {},  "visible_fields": [    "string"  ],  "sharing": "PRIVATE"}'

GET /views/{viewId}

Get saved view

One saved view. A view the caller may not see - another account's private view, or one shared into a scope the caller holds nothing on - is not found, in exactly the words a genuinely missing one produces.

Path parameters

NameTypeRequiredDescription
viewIdstring (uuid) required

Responses

Example bash
curl -X GET "$HUBTASK_URL/views/{viewId}" \  -H "Authorization: Bearer $HUBTASK_TOKEN"

PATCH /views/{viewId}

Update saved view

Changes a view's own fields. A field that is not sent is left alone. The scope and the sharing are not among them: where a view lives is decided when it is created, and sharing is :share - one decision with its own permission, not a field of an edit.

Path parameters

NameTypeRequiredDescription
viewIdstring (uuid) required

Headers

NameTypeRequiredDescription
If-Matchstring optionalThe ETag of the state last read (optimistic locking).

Request body application/merge-patch+json — SavedViewUpdate

NameTypeRequiredDescription
namestring
  • minLength: 1
  • maxLength: 200
optional
layoutstring optional
queryobject optionalThe whole query, replaced.
groupingobject optional
visible_fieldsarray of string optional

Responses

Example bash
curl -X PATCH "$HUBTASK_URL/views/{viewId}" \  -H "Authorization: Bearer $HUBTASK_TOKEN" \  -H 'If-Match: "<the ETag you read>"' \  -H "Content-Type: application/merge-patch+json" \  -d '{  "name": "string",  "layout": "string",  "query": {},  "grouping": {},  "visible_fields": [    "string"  ]}'

DELETE /views/{viewId}

Delete saved view

Deletes the view. A calendar feed that served it keeps its token and serves nothing, saying why - the feed's view reference nulls rather than cascading, because a feed is the subscriber's and a view is the workspace's.

Path parameters

NameTypeRequiredDescription
viewIdstring (uuid) required

Headers

NameTypeRequiredDescription
If-Matchstring optionalThe ETag of the state last read (optimistic locking).

Responses

  • 204 Deleted
  • 4XX An error per RFC 9457 Problem
Example bash
curl -X DELETE "$HUBTASK_URL/views/{viewId}" \  -H "Authorization: Bearer $HUBTASK_TOKEN" \  -H 'If-Match: "<the ETag you read>"'

POST /views/{viewId}:share

Share saved view

Decides who sees the view: PRIVATE keeps it the owner's, SCOPE shares it with everyone who may read the view's scope. Sharing publishes workspace furniture, so it asks the STRUCTURE permission on the scope's path - a view over a collection cannot be pushed onto people by somebody who may not shape that collection. An ACCOUNT-scoped view names no audience and cannot be shared. PUBLIC_LINK is declared and refused by name: the calendar feed is this version's only public reader and carries its own token, and a browsable public link is a product decision no task takes in passing.

Path parameters

NameTypeRequiredDescription
viewIdstring (uuid) required

Headers

NameTypeRequiredDescription
Idempotency-Keystring (uuid) optionalA UUID; identical requests return the same result for 24 h.
If-Matchstring optionalThe ETag of the state last read (optimistic locking).

Request body application/json — SavedViewShare

NameTypeRequiredDescription
sharingstring
  • PRIVATE
  • SCOPE
  • PUBLIC_LINK
required

Responses

Example bash
curl -X POST "$HUBTASK_URL/views/{viewId}:share" \  -H "Authorization: Bearer $HUBTASK_TOKEN" \  -H "Idempotency-Key: $(uuidgen)" \  -H 'If-Match: "<the ETag you read>"' \  -H "Content-Type: application/json" \  -d '{  "sharing": "PRIVATE"}'

POST /views/{viewId}:export

Export view

The view's result, rendered whole, in one of three formats. A read with no side effect, and a POST for the reason POST /search is one: what a view selects is the caller's content, and a query string travels through access logs, proxies and browser history. The view executes under the caller's authorisation, exactly as reading it does - two people exporting one shared view export two different files, and neither gets a row their role hides. Synchronous and bounded rather than a job: the row cap is in /meta/capabilities as max_export_rows, and a result that reached it is answered whole up to the cap with the Export-Truncated header set. An export stays one synchronous answer rather than a job a caller has to poll, and the cap is what keeps it one - a truncation a caller is told about is honest, and a silent one is not. ICS renders the same document the calendar feed serves, from the same renderer: an entry with no due date is not a calendar entry and does not appear.

Path parameters

NameTypeRequiredDescription
viewIdstring (uuid) required

Headers

NameTypeRequiredDescription
Idempotency-Keystring (uuid) optionalA UUID; identical requests return the same result for 24 h.

Request body application/json — ViewExport

NameTypeRequiredDescription
formatstring
  • CSV
  • JSON
  • ICS
requiredCSV for a spreadsheet, JSON for a script, ICS for a calendar.
time_zonestring optionalThe zone the dates are written in.

Responses

  • 200 The rendered view
  • 4XX An error per RFC 9457 Problem
Example bash
curl -X POST "$HUBTASK_URL/views/{viewId}:export" \  -H "Authorization: Bearer $HUBTASK_TOKEN" \  -H "Idempotency-Key: $(uuidgen)" \  -H "Content-Type: application/json" \  -d '{  "format": "CSV",  "time_zone": "Europe/Berlin"}'