-
Notifications
You must be signed in to change notification settings - Fork 22
REST API
If you're already running a Conseil instance, there is an OpenAPI route at <conseil-host>/docs
.
Conseil provides a dynamic query API. This means that newly exposed datasets can be automatically served through the interface. The metadata routes have a prefix of /v2/metadata/
. All results are in JSON format.
To get a list of platforms, make the following call.
curl --request GET --header 'apiKey: <API key>' --url '<conseil-host>/v2/metadata/platforms'
The result may look like the following.
[{
"name": "tezos",
"displayName": "Tezos"
}]
To get a list of networks, take one of the platform name
attributes from the call above to construct the following URL.
curl --request GET --header 'apiKey: <API key>' --url '<conseil-host>/v2/metadata/tezos/networks'
On a development server the result might be this:
[{
"name": "carthagenet",
"displayName": "Carthagenet",
"platform": "tezos",
"network": "carnet"
}, {
"name": "mainnet",
"displayName": "Mainnet",
"platform": "tezos",
"network": "mainnet"
}]
Taking again the name
property from one of the network results, we can list the entities available for that network.
curl --request GET --header 'apiKey: <API key>' --url '<conseil-host>/v2/metadata/tezos/mainnet/entities'
With the following sample result.
[{
"name": "accounts",
"displayName": "Accounts",
"count": 19587
}, {
"name": "accounts_checkpoint",
"displayName": "Accounts checkpoint",
"count": 5
}, {
"name": "bakers",
"displayName": "Bakers",
"count": 9232185
}, {
"name": "balance_updates",
"displayName": "Balance updates",
"count": 8848857
}, {
"name": "ballots",
"displayName": "Ballots",
"count": 0
}, {
"name": "blocks",
"displayName": "Blocks",
"count": 346319
}, {
"name": "fees",
"displayName": "Fees",
"count": 1680
}, {
"name": "operation_groups",
"displayName": "Operation groups",
"count": 2590969
}, {
"name": "operations",
"displayName": "Operations",
"count": 2619443
}, {
"name": "proposals",
"displayName": "Proposals",
"count": 0
}]
The count
property above contains the number of records for a particular entity.
Keep in mind that not all of the entities provided in that list map directly to on-chain entities on Tezos mainnet. Conseil may provide custom pre-processed data for convenience. In this example the fees
is one such entity that contains moving averages for operation fees in Tezos.
Using the results from the entities
call, we can get details of their composition.
curl --request GET --header 'apiKey: hooman' --url '<conseil-host>/v2/metadata/tezos/mainnet/accounts/attributes'
[{
"name": "account_id",
"displayName": "Account id",
"dataType": "String",
"cardinality": 19587,
"keyType": "UniqueKey",
"entity": "accounts"
}, {
"name": "block_id",
"displayName": "Block id",
"dataType": "String",
"cardinality": 4614,
"keyType": "NonKey",
"entity": "accounts"
}, {
"name": "manager",
"displayName": "Manager",
"dataType": "String",
"cardinality": 15572,
"keyType": "UniqueKey",
"entity": "accounts"
}, {
"name": "spendable",
"displayName": "Spendable",
"dataType": "Boolean",
"cardinality": 2,
"keyType": "NonKey",
"entity": "accounts"
}, {
"name": "delegate_setable",
"displayName": "Delegate setable",
"dataType": "Boolean",
"cardinality": 2,
"keyType": "NonKey",
"entity": "accounts"
}, {
"name": "delegate_value",
"displayName": "Delegate value",
"dataType": "String",
"cardinality": 143,
"keyType": "NonKey",
"entity": "accounts"
}, {
"name": "counter",
"displayName": "Counter",
"dataType": "Int",
"keyType": "NonKey",
"entity": "accounts"
}, {
"name": "script",
"displayName": "Script",
"dataType": "String",
"cardinality": 1317,
"keyType": "NonKey",
"entity": "accounts"
}, {
"name": "balance",
"displayName": "Balance",
"dataType": "Decimal",
"keyType": "NonKey",
"entity": "accounts"
}, {
"name": "block_level",
"displayName": "Block level",
"dataType": "Decimal",
"keyType": "UniqueKey",
"entity": "accounts"
}]
Using the information above it is possible to make intelligent decisions about how to construct user interfaces. For example, Arronax creates drop-down lists for value selection for low-cardinality properties like accounts.spendable
. Furthermore the datatype
field allows display of the appropriate editor be it numeric or date entry. You'll note also that certain properties do no contain cardinality
. Those are considered high cardinality fields for which that metadata is not collected.
Finally for low-cardinality fields it is possible to get a list of distinct values to populate the drop-down lists mentioned above for example.
curl --request GET --header 'apiKey: <API key>' --url '<conseil-host>/v2/metadata/tezos/mainnet/operations/kind'
These are the operation types this particular Conseil instance has seen since start.
["seed_nonce_revelation", "delegation", "transaction", "activate_account", "origination", "reveal", "double_endorsement_evidence", "double_baking_evidence", "endorsement"]
It is possible to get values for high-cardinality properties with a prefix. In this example we get all accounts.manager
values starting with "KT1".
curl --request GET --header 'apiKey: <API key>' --url 'https://conseil-dev.cryptonomic-infra.tech:443/v2/metadata/tezos/mainnet/accounts/manager/KT1'
...
As mentioned in the Datasource configuration section, it's possible to provide additional details for the items Conseil manages.
Data requests in Conseil v2 API are sent via POST
command and have a prefix of /v2/data/<platform>/<network>/<entity>
. The items in angle braces match up to the name
property of the related metadata results. There additional header to be set in the request: Content-Type: application/json
.
The most basic query has the following JSON structure.
{
"fields": [],
"predicates": [],
"limit": 5
}
This will return five items without any filtering for some entity. Note that the query does not specify which entity is being requested. If this is sent to /v2/data/tezos/mainnet/blocks
, it will return five rows with all the fields available in the blocks entity.
curl -d '{ "fields": [], "predicates": [], "limit": 5 }' -H 'Content-Type: application/json' -H 'apiKey: <API key>' -X POST '<conseil-host>/v2/data/tezos/mainnet/blocks/'
The query grammar allows for some fine-grained data extraction.
It is possible to narrow down the fields returned in the result set by listing just the ones that are necessary. The fields
property of the query is an array of string
, these values are the name
s from the /v2/metadata/<platform>/<network>/<entity>/attributes/
metadata response.
predicates
is an array containing objects. The inner object has several properties:
-
field
– attribute name from the metadata response. -
operation
– one of: in, between, like, lt, gt, eq, startsWith, endsWith, before, after. -
set
– an array of values to compare against. 'in' requires two or more elements, 'between' must have exactly two, the rest of the operations require a single element. Dates are expressed as epoch milliseconds. -
inverse
– boolean, setting it totrue
applied aNOT
to the operator -
precision
– for numeric field matches this specifies the number of decimal places to round to. -
group
- an optional naming to collect predicates in groups that will be eventually OR-ed amongst each other
Specifies the maximum number of records to return.
Sort condition, multiple may be supplied for a single query. Inner object(s) will contain field
and direction
properties. The former is name
from the /v2/metadata/<platform>/<network>/<entity>/attributes/
metadata response, the latter is one of 'asc', 'desc'.
It is possible to sort on aggregated results, in this case the field
value would be "function_fieldname", for example sum_balance
. See query samples below.
It is possible to apply an aggregation function to a field of the result set. The aggregation object contains the following properties:
-
field
–name
from the/v2/metadata/<platform>/<network>/<entity>/attributes/
metadata response. -
function
– one of: sum, count, max, min, avg. -
predicate
– same definition as the predicate object described above. This gets translated into aHAVING
condition in the underlying SQL.
Multiple fields can be aggregated and the same field can be aggregated with different functions in the same request. See examples below.
Default result set format is JSON, it is possible however to output csv instead for exporting larger datasets that will then be imported into other tools. There is also possibility to return query which is being ran on the DB with sql
output type.
'output': 'csv|json|sql'
Here's a collection of interesting datasets. Run these examples as
curl -H 'Content-Type: application/json' -H 'apiKey: <API key>' \
-X POST '<conseil-host>/v2/data/<platform>/<network>/<entity>/' \
-d '<example>'
Send this query to /v2/data/tezos/<network>/blocks
Note that orderBy
below ends up sorting by the aggregated value.
{
"fields": ["baker", "level"],
"predicates": [{ "field": "timestamp", "set": [1554076800000, 1556668799000], "operation": "between", "inverse": false }],
"orderBy": [{ "field": "count_level", "direction": "desc" }],
"aggregation": [{ "field": "level", "function": "count" }],
"limit": 50,
"output": "csv"
}
When you make this query with sql
output
{
"fields": ["baker", "level"],
"predicates": [{ "field": "timestamp", "set": [1554076800000, 1556668799000], "operation": "between", "inverse": false }],
"orderBy": [{ "field": "count_level", "direction": "desc" }],
"aggregation": [{ "field": "level", "function": "count" }],
"limit": 50,
"output": "sql"
}
you'll get following response:
SELECT COUNT(level) as count_level,baker FROM tezos.blocks WHERE true AND timestamp BETWEEN '2019-04-01 00:00:00.0' AND '2019-04-30 23:59:59.0' AND invalidated_asof ISNULL GROUP BY baker ORDER BY count_level desc LIMIT 50
Send this query to /v2/data/tezos/<network>/accounts
{
"fields": ["delegate_value", "balance"],
"predicates": [{ "field": "delegate_value", "set": [], "operation": "isnull", "inverse": true }],
"orderBy": [{ "field": "sum_balance", "direction": "desc" }],
"aggregation": [{ "field": "balance", "function": "sum" }],
"limit": 50,
"output": "csv"
}
Send this query to /v2/data/tezos/<network>/accounts
{
"fields": ["delegate_value", "account_id"],
"predicates": [{ "field": "delegate_value", "set": [], "operation": "isnull", "inverse": true }],
"orderBy": [{ "field": "count_account_id", "direction": "desc" }],
"aggregation": [{ "field": "account_id", "function": "count" }],
"limit": 50,
"output": "csv"
}
Send this query to /v2/data/tezos/<network>/rolls
{
"fields": ["pkh", "rolls"],
"predicates": [],
"orderBy": [
{ "field": "block_level", "direction": "desc" },
{ "field": "rolls", "direction": "desc" }
],
"limit": 20,
"output": "csv"
}
Send this query to /v2/data/tezos/<network>/accounts
{
"fields": ["account_id"],
"predicates": [
{ "field": "account_id", "set": ["KT1"], "operation": "startsWith", "inverse": false },
{ "field": "script", "set": [], "operation": "isnull", "inverse": true }
],
"limit": 10000,
"output": "csv"
}
Send this query to /v2/data/tezos/<network>/operations
{
"fields": ["destination", "operation_group_hash"],
"predicates": [
{ "field": "kind", "set": ["transaction"], "operation": "eq", "inverse": false },
{ "field": "destination", "set": ["KT1"], "operation": "startsWith", "inverse": false },
{ "field": "parameters", "set": [], "operation": "isnull", "inverse": true }
],
"orderBy": [{ "field": "count_operation_group_hash", "direction": "desc" }],
"aggregation": [{ "field": "operation_group_hash", "function": "count" }],
"limit": 10,
"output": "csv"
}
Send this query to /v2/data/tezos/<network>/operations
{
"fields": ["source", "operation_group_hash"],
"predicates": [
{ "field": "kind", "set": ["origination"], "operation": "eq", "inverse": false },
{ "field": "script", "set": [], "operation": "isnull", "inverse": true }
],
"orderBy": [{ "field": "count_operation_group_hash", "direction": "desc" }],
"aggregation": [{ "field": "operation_group_hash", "function": "count" }],
"limit": 10,
"output": "csv"
}
Send this query to /v2/data/tezos/<network>/operations
{
"fields": ["source", "amount", "fee"],
"predicates": [
{ "field": "kind", "set": ["transaction"], "operation": "eq", "inverse": false },
{ "field": "timestamp", "set": [1546300800000, 1577836799000], "operation": "between", "inverse": false }
],
"orderBy": [{ "field": "sum_amount", "direction": "desc" }],
"aggregation": [{ "field": "amount", "function": "sum" }, { "field": "fee", "function": "avg" }
],
"limit": 50,
"output": "csv"
}
Send this query to /v2/data/tezos/<network>/operations
{
"fields": ["block_level", "kind", "fee"],
"predicates": [
{ "field": "timestamp", "set": [1554076800000, 1556668799000], "operation": "between", "inverse": false },
{ "field": "fee", "set": [0], "operation": "gt", "inverse": false }
],
"orderBy": [{ "field": "sum_fee", "direction": "desc" }],
"aggregation": [{ "field": "fee", "function": "sum" }, { "field": "fee", "function": "avg" }],
"limit": 100000,
"output": "csv"
}
Send this query to /v2/data/tezos/<network>/operations
{
"fields": ["kind", "operation_group_hash"],
"predicates": [
{ "field": "timestamp", "set": [1554076800000, 1556668799000], "operation": "between", "inverse": false }
],
"orderBy": [{ "field": "count_operation_group_hash", "direction": "desc" }],
"aggregation": [{ "field": "operation_group_hash", "function": "count" }],
"limit": 20,
"output": "csv"
}
Send this query to /v2/data/tezos/<network>/operations
{
"fields": ["block_level", "operation_group_hash"],
"predicates": [
{ "field": "timestamp", "set": [1554076800000, 1556668799000], "operation": "between", "inverse": false },
{ "field": "kind", "set": ["transaction", "origination", "delegation", "activation", "reveal"], "operation": "in", "inverse": false }
],
"orderBy": [{ "field": "count_operation_group_hash", "direction": "desc" }],
"aggregation": [{ "field": "operation_group_hash", "function": "count" }],
"limit": 100,
"output": "csv"
}
Send this query to /v2/data/tezos/<network>/accounts
{
"fields": ["manager", "account_id"],
"predicates": [
{ "field": "script", "set": [], "operation": "isnull", "inverse": false },
{ "field": "balance", "set": [0], "operation": "gt", "inverse": false }
],
"orderBy": [{ "field": "count_account_id", "direction": "desc" }],
"aggregation": [{ "field": "account_id", "function": "count" }],
"limit": 20,
"output": "csv"
}
Send this query to /v2/data/tezos/<network>/accounts
{
"fields": ["manager", "balance"],
"predicates": [
{ "field": "script", "set": [], "operation": "isnull", "inverse": false }
],
"orderBy": [{ "field": "sum_balance", "direction": "desc" }],
"aggregation": [{ "field": "balance", "function": "sum" }],
"limit": 20,
"output": "csv"
}
Send this query to /v2/data/tezos/<network>/operations
{
"fields": ["block_level", "operation_group_hash"],
"predicates": [
{ "field": "timestamp", "set": [1554076800000], "operation": "before", "inverse": false, "group": "before" },
{ "field": "kind", "set": ["transaction"], "operation": "in", "inverse": false, "group": "before" },
{ "field": "timestamp", "set": [1556668799000], "operation": "after", "inverse": false, "group": "after" },
{ "field": "kind", "set": ["transaction"], "operation": "in", "inverse": false, "group": "after" }
],
"orderBy": [{ "field": "count_operation_group_hash", "direction": "desc" }],
"aggregation": [{ "field": "operation_group_hash", "function": "count" }],
"limit": 100,
"output": "csv"
}
A note on predicate conjunction/disjunction
- By default all predicates with no specified group-name belong to the same un-named group
- predicates within the same group are joined via the "AND" operator
- predicates between separate groups are joining via the "OR" operator
Send this query to /v2/data/tezos/<network>/accounts_history
Example temporal table queries:
Get the balance of an account at a specific timestamp.
{
"predicates": [
{
"field": "account_id",
"operation": "eq",
"set": ["KT18x4B5BkyGMR5DCr7esP8pC5biQc1M6CGr"]
}
],
"snapshot": {
"field": "asof",
"value": 11530382887000
},
"aggregation": [],
"fields": [
"account_id", "balance", "block_level", "asof"
],
"orderBy": [
],
"output": "json",
"limit": 100
}
Get the balance of an account at a specific block level
{
"predicates": [
{
"field": "account_id",
"operation": "eq",
"set": ["KT18x4B5BkyGMR5DCr7esP8pC5biQc1M6CGr"]
}
],
"snapshot": {
"field": "block_level",
"value": 2700
},
"aggregation": [],
"fields": [
"account_id", "balance", "block_level", "asof"
],
"orderBy": [
],
"output": "json",
"limit": 100
}
Get all records for an account over a range of blocks
{
"predicates": [
{
"field": "account_id",
"operation": "eq",
"set": ["KT18x4B5BkyGMR5DCr7esP8pC5biQc1M6CGr"]
},
{
"field": "block_level",
"operation": "between",
"set": [1500, 3000]
}
],
"aggregation": [],
"fields": [
"account_id", "balance", "block_level", "asof"
],
"orderBy": [
],
"output": "json",
"limit": 100
}
Note on temporal tables:
- Temporal tables contains
asof
andblock_level
columns which have information about the timestamp and block level - besides that they contain the same columns as regular tables and can be queried as them
Not all entities are necessarily items from the chain. One such example is /v2/data/tezos/<network>/fees
. Conseil continuously buckets and averages network fees to give users an idea of what values they should submit when sending operations. Fees are aggregated by operation type.
{
"fields": [],
"predicates": [{ "field": "kind", "operation": "eq", "set": [ "transaction" ] }],
"orderBy": [{"field": "timestamp", "direction": "desc"}],
"limit": 1
}