zenith-docs/docs/api/zenith-watcher.md
2025-11-28 15:34:21 -05:00

11 KiB

Zenith Watcher API

The Zenith Watcher indexes the Zenith blockchain across all network stages, providing access to account information, transactions, validators, scry bindings, and treasury claims.

GraphQL Endpoint: https://zenith-watcher.zenith-test.tlon.systems/graphql

GraphQL API

Query Account Information

query GetAccount($address: String!) {
  account(address: $address) {
    address
    balances {
      denom
      amount
    }
    transactions {
      hash
      type
      timestamp
      blockHeight
      success
    }
  }
}

Query Transactions

query GetTransactions($address: String!, $limit: Int!) {
  transactions(
    where: {
      or: [
        { sender: $address }
        { receiver: $address }
      ]
    }
    limit: $limit
    orderBy: timestamp
    orderDirection: desc
  ) {
    hash
    sender
    receiver
    amount
    denom
    timestamp
    blockHeight
    success
  }
}

Query Validators

query GetValidators {
  validators {
    address
    moniker
    votingPower
    commission
    jailed
    uptime
  }
}

Query Scry Bindings

query GetScryBindings($path: String!) {
  scryBindings(where: { path: $path }) {
    path
    hash
    blockHeight
    timestamp
    signatures {
      signer
      signature
    }
  }
}

Query Treasury Claims

query GetClaims($address: String!) {
  treasuryClaims(where: { claimer: $address }) {
    claimer
    amount
    denom
    timestamp
    blockHeight
    transactionHash
  }
}

REST API

The Zenith Watcher also provides REST API endpoints for querying scry oracle data.

1. Get Binding by Path

The /laconic/scryoracle/v1/binding_by_path API retrieves the binding (hash, block number, and block hash) for a specific path.

Example:

curl -X 'GET' -H 'accept: application/json' \
  "http://127.0.0.1:3008/rest/laconic/scryoracle/v1/binding_by_path?path=/~zod/group-store/groups/random-group/json" | jq

Response:

{
  "binding": {
    "hash": "d5af5fddee9de5cedbe1ad1df367f96f67347f8edaddef75",
    "block_number": "23",
    "block_hash": "a9521112d4ee58da8221c893c8dae465b236456c4becc25edffe85ae3b0ac15e"
  },
  "binding_with_verification": null
}

With include_verification_data parameter:

curl -X 'GET' -H 'accept: application/json' \
  "http://127.0.0.1:3008/rest/laconic/scryoracle/v1/binding_by_path?path=/~zod/group-store/groups/random-group/json&include_verification_data=true" | jq

Parameters:

  • path (required): The exact path to lookup
  • include_verification_data (optional): Whether to return signature and life (default: false)

2. Get Bindings by Path Prefix

The /laconic/scryoracle/v1/bindings_by_prefix API gets path-to-hash mappings using a path prefix with support for both cursor-based and offset-based pagination.

Cursor-based Pagination

Example - First page:

curl -X 'GET' -H 'accept: application/json' \
  "http://127.0.0.1:3008/rest/laconic/scryoracle/v1/bindings_by_prefix?path_prefix=/~zod&pagination.limit=3" | jq

Response:

{
  "path_bindings": {
    "/~zod/group-store/groups/random-group/json": {
      "hash": "d5af5fddee9de5cedbe1ad1df367f96f67347f8edaddef75",
      "block_number": "23",
      "block_hash": "a9521112d4ee58da8221c893c8dae465b236456c4becc25edffe85ae3b0ac15e"
    },
    "/~zod/group-store/members/random-group/json": {
      "hash": "77873b7b96bd7f4d5bddff366ba6f6779738edad1fddef75",
      "block_number": "23",
      "block_hash": "a9521112d4ee58da8221c893c8dae465b236456c4becc25edffe85ae3b0ac15e"
    },
    "/~zod/metadata-store/associations/groups/random-group/json": {
      "hash": "73b7b96bd77a6f47f5ddff367786b57366f97bd7f8edad37",
      "block_number": "23",
      "block_hash": "a9521112d4ee58da8221c893c8dae465b236456c4becc25edffe85ae3b0ac15e"
    }
  },
  "pagination": {
    "next_key": "eyJwYWdpbmF0aW9uX3NraXAiOjN9",
    "total": "0"
  }
}

!!! note "Using next_key" Use next_key from pagination output of the above API response in a subsequent request (as pagination.key) to get the next page of results.

Example - Next page using next_key:

curl -X 'GET' -H 'accept: application/json' \
  "http://127.0.0.1:3008/rest/laconic/scryoracle/v1/bindings_by_prefix?path_prefix=/~zod&pagination.key=eyJwYWdpbmF0aW9uX3NraXAiOjN9" | jq

Offset-based Pagination

Example:

curl -X 'GET' -H 'accept: application/json' \
  "http://127.0.0.1:3008/rest/laconic/scryoracle/v1/bindings_by_prefix?path_prefix=/~zod&pagination.limit=10&pagination.offset=2&pagination.count_total=true" | jq

Parameters:

  • path_prefix (required): The path prefix to match against
  • pagination.limit (optional): Number of results per page (default: 100)
  • pagination.key (optional): Base64-encoded cursor for next page
  • pagination.offset (optional): Offset for traditional pagination (cannot be used with key)
  • pagination.count_total (optional): Whether to return total count (default: false)
  • include_verification_data (optional): Whether to return signature and life (default: false)

!!! warning "Pagination Note" You cannot use both pagination.key and pagination.offset in the same request.

3. Get Bindings by Block Number

The /laconic/scryoracle/v1/bindings_by_block_number API gets path-to-hash mappings added at a specific block number.

Example:

curl -X 'GET' -H 'accept: application/json' \
  "http://127.0.0.1:3008/rest/laconic/scryoracle/v1/bindings_by_block_number?block_number=25&path_prefix=/~zod" | jq

Response:

{
  "path_bindings": {
    "/~zod/publish/comments/2025.3.6..15.30.20..0000/json": {
      "hash": "6b477973b7fdd5ee9be367f76fd6b577cd9cd1fe3b7b9dda",
      "block_number": "25",
      "block_hash": "5a932989009ea3ed054e8a98752eea09384e3bf134ebeb833984f11e52ea8bf5"
    },
    "/~zod/publish/posts/2025.3.6..15.30.20..0000/json": {
      "hash": "ddff757786bb6f4d9ce9ee5af5ff376f57397746b8ef67ba",
      "block_number": "25",
      "block_hash": "5a932989009ea3ed054e8a98752eea09384e3bf134ebeb833984f11e52ea8bf5"
    }
  }
}

Parameters:

  • block_number (required): The block number to query
  • path_prefix (optional): Filter results by path prefix
  • include_verification_data (optional): Whether to return signature and life (default: false)

4. Get Bindings in Block Range

The /laconic/scryoracle/v1/bindings_in_block_range API gets path-to-hash mappings added within a block range.

Example:

curl -X 'GET' -H 'accept: application/json' \
  "http://127.0.0.1:3008/rest/laconic/scryoracle/v1/bindings_in_block_range?from_block=10&to_block=100&path_prefix=/~zod/publish" | jq

Response:

{
  "path_bindings": {
    "/~zod/publish/comments/2025.3.6..15.30.20..0000/json": {
      "hash": "6b477973b7fdd5ee9be367f76fd6b577cd9cd1fe3b7b9dda",
      "block_number": "25",
      "block_hash": "5a932989009ea3ed054e8a98752eea09384e3bf134ebeb833984f11e52ea8bf5"
    },
    "/~zod/publish/posts/2025.3.6..15.30.20..0000/json": {
      "hash": "ddff757786bb6f4d9ce9ee5af5ff376f57397746b8ef67ba",
      "block_number": "25",
      "block_hash": "5a932989009ea3ed054e8a98752eea09384e3bf134ebeb833984f11e52ea8bf5"
    }
  }
}

Parameters:

  • from_block (required): Starting block number (inclusive)
  • to_block (required): Ending block number (inclusive)
  • path_prefix (optional): Filter results by path prefix
  • include_verification_data (optional): Whether to return signature and life (default: false)

!!! note "Block Range Limit" The block range is limited to 1000 blocks maximum.

5. Get Bindings by Wildcard Pattern

The /laconic/scryoracle/v1/bindings_by_wildcard API gets path-to-hash mappings using wildcard pattern matching with support for both cursor-based and offset-based pagination.

Example - Match any path between ~zod and random-group/json:

curl -X 'GET' -H 'accept: application/json' \
  "http://127.0.0.1:3008/rest/laconic/scryoracle/v1/bindings_by_wildcard?path_pattern=/~zod/*/random-group/json" | jq

Response:

{
  "path_bindings": {
    "/~zod/group-store/groups/random-group/json": {
      "hash": "d5af5fddee9de5cedbe1ad1df367f96f67347f8edaddef75",
      "block_number": "23",
      "block_hash": "a9521112d4ee58da8221c893c8dae465b236456c4becc25edffe85ae3b0ac15e"
    },
    "/~zod/group-store/members/random-group/json": {
      "hash": "77873b7b96bd7f4d5bddff366ba6f6779738edad1fddef75",
      "block_number": "23",
      "block_hash": "a9521112d4ee58da8221c893c8dae465b236456c4becc25edffe85ae3b0ac15e"
    },
    "/~zod/metadata-store/associations/groups/random-group/json": {
      "hash": "73b7b96bd77a6f47f5ddff367786b57366f97bd7f8edad37",
      "block_number": "23",
      "block_hash": "a9521112d4ee58da8221c893c8dae465b236456c4becc25edffe85ae3b0ac15e"
    }
  },
  "pagination": {
    "next_key": null,
    "total": "0"
  }
}

Parameters:

  • path_pattern (required): The wildcard pattern to match (use * for wildcard matching)
  • pagination.limit (optional): Number of results per page (default: 100)
  • pagination.key (optional): Base64-encoded cursor for next page
  • pagination.offset (optional): Offset for traditional pagination (cannot be used with key)
  • pagination.count_total (optional): Whether to return total count (default: false)
  • include_verification_data (optional): Whether to return signature and life (default: false)

!!! warning "Pagination Note" You cannot use both pagination.key and pagination.offset in the same request.

Using the APIs

With curl (GraphQL)

# Query Zenith Watcher
curl -X POST https://zenith-watcher.zenith-test.tlon.systems/graphql \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query { validators { moniker votingPower jailed } }"
  }'

With JavaScript/TypeScript (GraphQL)

const query = `
  query GetAccount($address: String!) {
    account(address: $address) {
      balances {
        denom
        amount
      }
    }
  }
`;

const variables = { address: "zenith1..." };

const response = await fetch('https://zenith-watcher.zenith-test.tlon.systems/graphql', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ query, variables })
});

const data = await response.json();

With GraphQL Client Libraries

import { GraphQLClient } from 'graphql-request';

const client = new GraphQLClient(
  'https://zenith-watcher.zenith-test.tlon.systems/graphql'
);

const query = `
  query GetAccount($address: String!) {
    account(address: $address) {
      balances { denom amount }
    }
  }
`;

const data = await client.request(query, { address: 'zenith1...' });

Rate Limiting and Best Practices

  • Rate Limits: Public watcher endpoints have rate limiting in place. For production applications, consider running your own watcher instances.
  • Pagination: Use pagination parameters for queries that return large result sets.
  • Caching: Cache frequently accessed data to reduce API load.
  • Error Handling: Implement proper error handling and retry logic for network failures.

!!! note "Watcher Documentation" For more information about the watcher architecture and deployment, see the Watchers documentation.