API: Query the list of all zettel

The endpoint /z also allows you to filter the list of all zettel1 and optionally specify some actions.

A query consists of an optional search expression and an optional list of actions (described below). If you provide no search expression, all zettel are selected. Similarly, if you specify no valid action, or the action list is empty, the list of all selected zettel metadata is returned.

Search expression and action list are separated by a vertical bar character (“|”, U+007C), and must be given with the q query parameter.

The query parameter “q” allows you to specify a query expression for a full-text search of all zettel content and / or restricting the search according to specific metadata.

The query parameter can be provided multiple times. Query expressions are combined with a logical AND.

This loosely resembles the search form of the web user interface or those of Zettelmarkup's Query Transclusion.

For example, if you want to retrieve all zettel that contain the string “API” in their title, your request will be:

# curl 'http://127.0.0.1:23123/z?q=title%3AAPI+ORDER+REVERSE+id+OFFSET+1'
00001012921200 API: Encoding of Zettel Access Rights
00001012921000 API: Structure of an access token
00001012920500 Encodings available via the API
00001012920000 Endpoints used by the API
...

If you want to retrieve a data document, as a symbolic expression:

# curl 'http://127.0.0.1:23123/z?q=title%3AAPI+ORDER+REVERSE+id+OFFSET+1&enc=data'
(meta-list (query "title:API ORDER REVERSE id OFFSET 1") (human "title HAS API ORDER REVERSE id OFFSET 1") (zettel "00001012921200" (meta (back "00001012051200 00001012051400 00001012053200 00001012053300 00001012053400 00001012054200 00001012920528") (backward "00001012051200 00001012051400 00001012053200 00001012053300 00001012053400 00001012054200 00001012920528") (box-name "manual") (created "20220201173115") (forward "00001003000000 00001006020400 00001010040100 00001010040200 00001010070200 00001010070300") (modified "20260714200809") (published "20260714200809") (role "manual") (syntax "zmk") (tags "#api #manual #reference #zettelstore") (title "API: Encoding of Zettel Access Rights")) (rights create read update delete)) (zettel "00001012921000" (meta (back "00001012050600") (backward "00001012050200 00001012050400 00001012050600") (box-name "manual") (created "20210126175322") (forward "00001012050200 00001012050400 00001012930000 00001012930500") (modified "20260605144534") (published "20260605144534") (role "manual") (syntax "zmk") (tags "#api #manual #reference #zettelstore") (title "API: Structure of an access token") ...

The data object contains a key "meta-list" to signal that it contains a list of metadata values (and some more). It contains the keys "query" and "human" with a string value. Both will contain a textual description of the underlying query if you select only some zettel with a query expression. Without a selection, the values are the empty string. "query" returns the normalized query expression itself, while "human" is the normalized query expression to be read by humans.

Then comes the list of zettel data. Data of a zettel is indicated by the symbol zettel, followed by the zettel identifier as a string value. Metadata starts with the symbol meta, and each metadatum itself is a list of metadata key / metadata value. Metadata keys are encoded as a symbol, metadata values as a string. "rights" encodes the access rights for the given zettel.

Aggregates

An implicit precondition is that the zettel must contain the given metadata key. For metadata keys like title, which have a default value, this precondition should always be true. But the situation is different for a key like url. Both curl 'http://localhost:23123/z?q=url%3A' and curl 'http://localhost:23123/z?q=url%3A!' may result in an empty list.

As an example for a query action, to list all roles used in the Zettelstore, send an HTTP GET request to the endpoint /z?q=|role.

# curl 'http://127.0.0.1:23123/z?q=|role'
configuration	00001000000100 00000000090002 00000000090000 00000000040001 00000000025001 00000000020001 00000000000100 00000000000092 00000000000090 00000000000006 00000000000005 00000000000004 00000000000001
manual	00001018000000 00001017000000 00001014000000 00001012921200 00001012921000 00001012920800 00001012920588 00001012920584 00001012920582 00001012920522 00001012920519 00001012920516 00001012920513 00001012920510 00001012920503 00001012920500 00001012920000 00001012080500 00001012080200 00001012080100 00001012070500 00001012054600 00001012054400 00001012054200 00001012054000 00001012053900 00001012053800 00001012053600 00001012053500 00001012053400 00001012053300 00001012053200 00001012051400 00001012051200 00001012050600 00001012050400 00001012050200 00001012000000 00001010090100 00001010070600 00001010070400 00001010070300 00001010070200 00001010040700 00001010040400 00001010040200 00001010040100 00001010000000 00001008050000 00001008010500 00001008010000 00001008000000 00001007990000 00001007906000 00001007903000 00001007900000 00001007800000 00001007790000 00001007780000 00001007706000 00001007705000 00001007702000 00001007700000 00001007050200 00001007050100 00001007050000 00001007040350 00001007040340 00001007040330 00001007040324 00001007040322 00001007040320 00001007040310 00001007040300 00001007040200 00001007040100 00001007040000 00001007031400 00001007031300 00001007031200 00001007031140 00001007031110 00001007031100 00001007031000 00001007030900 00001007030800 00001007030700 00001007030600 00001007030500 00001007030400 00001007030300 00001007030200 00001007030100 00001007030000 00001007020000 00001007010000 00001007000000 00001006055000 00001006050000 00001006036500 00001006036000 00001006035500 00001006035000 00001006034500 00001006034000 00001006033500 00001006033000 00001006032500 00001006032000 00001006031500 00001006031000 00001006030500 00001006030000 00001006020400 00001006020100 00001006020000 00001006010000 00001006000000 00001005090000 00001005000000 00001004101000 00001004100000 00001004059900 00001004059700 00001004051400 00001004051200 00001004051100 00001004051000 00001004050400 00001004050200 00001004050000 00001004020200 00001004020000 00001004011600 00001004011400 00001004011200 00001004010000 00001004000000 00001003600000 00001003315000 00001003310000 00001003305000 00001003300000 00001003000000 00001002000000 00001001000000 00001000000000
zettel	00010000000000 00000000090001

The result is a text file. The first word, separated by a horizontal tab (U+0009) contains the role name. The rest of the line consists of zettel identifier, where the corresponding zettel have this role. Zettel identifiers are separated by a space character (U+0020).

Please note that the list is not sorted by the role name, so the same request might result in a different order. If you want a sorted list, you could sort it on the command line (curl 'http://127.0.0.1:23123/z?q=|role' | sort) or within the software that made the call to the Zettelstore.

Of course, this list can also be returned as a data object:

# curl 'http://127.0.0.1:23123/z?q=|role&enc=data'
(aggregate "role" (query "| role") (human "| role") ("tag" "00001019990010") ("manual" "00001012921200" "00001007900000" "00001012920519" "00001007031000" "00001012930500" "00001003310000" "00001012053600" "00001004020200" "00001007040340" "00001007702000" "00001007720500" "00001012050600" "00001002000000" "00001006033000" "00001005000000" "00001007031200" "00001012920531" "00001008000000" "00001012080200" "00001012080100" "00001007990000" "00001012931600" "00001004011400" "00001004101000" "00001004010200" "00001004051100" "00001006000000" "00001007031110" "00001006030500" "00001007030500" "00001010040100" "00001012931000" "00001012920000" "00001006031000" "00001003000000" "00001006050000" "00001006020100" "00001007720900" "00001006020000" "00001006020400" "00001007770000" "00001007040322" "00001004059900" "00001014000000" "00001004020000" "00001004100000" "00001007010000" "00001006032500" "00001005090000" "00001012051400" "00001010070300" "00001007040320" "00001007040350" "00001012931900" "00001012054200" "00001007040330" "00001004059700" "00001008010800" "00001006033500" "00001007050000" "00001007020000" "00001006034000" "00001012054600" "00001010040700" "00001010070600" "00001007720300" "00001007906000" "00001007030100" "00001017000000" "00001007701000" "00001012050200" "00001010070200" "00001003300000" "00001004050200" "00001007040100" "00001004000000" "00001012930000" "00001012920525" "00001010040200" "00001007031300" "00001004010000" "00001007706000" "00001007031400" "00001000000000" "00001004050000" "00001007800000" "00001012051600" "00001006055000" "00001004051400" "00001007030000" "00001007031100" "00001007050100" "00001008010500" "00001010000000" "00001010070400" "00001012920800" "00001012921000" "00001012931400" "00001008010000" "00001006035000" "00001012053500" "00001003600000" "00001010040400" "00001008050000" "00001012920516" "00001007030900" "00001004051200" "00001007030200" "00001012051800" "00001007700000" "00001007705000" "00001007903000" "00001012931200" "00001007720000" "00001010090100" "00001012931800" "00001007030600" "00001007040000" "00001006034500" "00001007780000" "00001012051200" "00001018000000" "00001004011200" "00001007050200" "00001012920513" "00001006031500" "00001007040300" "00001003315000" "00001012000000" "00001012050400" "00001003305000" "00001007720600" "00001007710000" "00001004011600" "00001007721200" "00001007040200" "00001012920500" "00001012053200" "00001012920510" "00001004050400" "00001007030400" "00001007030800" "00001006030000" "00001001000000" "00001007040310" "00001007790000" "00001006035500" "00001006032000" "00001012053300" "00001006010000" "00001012080500" "00001007040324" "00001012070500" "00001007030700" "00001012920528" "00001007030300" "00001007031140" "00001012053800" "00001012920522" "00001004051000" "00001012053400" "00001007000000") ("configuration" "00001000000100" "00000000000100" "00000000090000" "00000000000007" "00001000000001" "00000000000005" "00000000025001" "00000000030001" "00000000090002" "00000000030101" "00000000080001" "00000000000006" "00000000000092" "00000000040001" "00000000000090" "00000000000001" "00000000090003" "00000000090001" "00000999999999" "00000000090004" "00000000000004" "00000000020001") ("role" "00000000060010" "00000000060020" "00001000000002" "00000000060040" "00000000060030") ("zettel" "00010000000000") ("material" "00001008010802" "00001008010801" "00001008010803"))

The data object starts with the symbol aggregate to signal a different format compared to meta-list above. Then a string follows, which specifies the key on which the aggregate was performed. query and human have the same meaning as above. Then comes the result list of aggregates. Each aggregate starts with a string of the aggregate value, in this case the role value, followed by a list of zettel identifier, denoting zettel which have the given role value.

Similarly, to list all tags used in the Zettelstore, send an HTTP GET request to the endpoint /z?q=|tags. If successful, the output is a data object:

# curl 'http://127.0.0.1:23123/z?q=|tags&enc=data'
(aggregate "tags" (query "| tags") (human "| tags") ("#meta" "00001006030000" "00001006031500" "00001006033500" "00001006034000" "00001006034500" "00001006020000" "00001006032500" "00001006031000" "00001006020400" "00001006035000" "00001006020100" "00001006033000" "00001006032000" "00001006035500") ("#tutorial" "00001007900000" "00001007903000" "00001007906000") ("#example" "00001007790000") ("#design" "00001005000000" "00001006055000" "00001002000000" "00001006000000" "00001006050000") ("#security" "00001010040200" "00001010070200" "00001010040100" "00001010090100" "00001010040700" "00001010000000" "00001010070300" "00001010040400" "00001010070400" "00001010070600") ("#search" "00001007710000" "00001007700000" "00001007720500" "00001007706000" "00001007702000" "00001007720900" "00001007720600" "00001007790000" "00001007031140" "00001007720300" "00001007705000" "00001007701000" "00001007780000" "00001007720000" "00001007770000") ("#encryption" "00001010090100") ("#api" "00001012050400" "00001012080500" "00001012070500" "00001012920510" "00001012053800" "00001012054600" "00001012931600" "00001012931800" "00001012920500" "00001012051800" "00001012053200" "00001012920519" "00001012080200" "00001012053300" "00001012051200" "00001012920525" "00001012050600" "00001012931000" "00001012920516" "00001012921200" "00001012931900" "00001012920800" "00001012050200" "00001012051400" "00001012920528" "00001012921000" "00001012920000" "00001012931400" "00001012080100" "00001012920522" "00001012053600" "00001012931200" "00001012920513" "00001012000000" "00001012920531" "00001012053400" "00001012053500" "00001012051600" "00001012054200") ...

If you want only those tags that occur at least 100 times, use the endpoint /z?q=|MIN100+tags. You see from this that actions are separated by space characters.

Actions

There are two types of actions: parameters and aggregates. The following actions are supported:

MINn (parameter)

Emit only those values with at least n aggregated values. n must be a positive integer, MIN must be given in upper-case letters.

MAXn (parameter)

Emit only those values with at most n aggregated values. n must be a positive integer, MAX must be given in upper-case letters.

KEYS (aggregate)

Emit a list of all metadata keys, together with the number of zettel having the key.

REDIRECT (aggregate)

Performs an HTTP redirect to the first selected zettel, using HTTP status code 302. The zettel identifier is in the body.

REINDEX (aggregate)

Updates the internal search index for the selected zettel, similar to the refresh API call, and requires the same permissions. It is not technically an aggregate, since it is used primarily for its side effect. However, another aggregate may be specified.

Any metadata key of type Word or TagSet (aggregates)

Emit an aggregate of the given metadata key. The key can be given in any letter case.

First, REINDEX actions are executed, then REDIRECT. If no REDIRECT was found the first other aggregate action will be executed.

To allow some kind of backward compatibility, an action written in uppercase letters that leads to an empty result list, will be ignored. In this case the list of selected zettel is returned.

HTTP Status codes

200

Query was successful.

204

Query was successful, but results in no content. Most likely, you specified no appropriate aggregator.

302

Query was successful, redirect to first zettel in list.

400

Request was not valid. There are several reasons for this. Maybe the access bearer token was not valid, or you forgot to specify a valid query.

  1. If authentication is enabled, you must include a valid access token in the Authorization header ↩︎