Skip to content

πŸ‘‘ Surface History Data - UIs & Front-ends

πŸ‘‘ Surface History Data - UIs & Front-ends

UIs and apps will be able to query any Token or NFTs (that uses CAP) transaction history and surface it for its users. This will be done using the CAP-js library, that will allow any frontend to communicate with CAP's main canister to query data from any integrated asset.


This is an early version of the documentation! 🚧 for the complete interface you can visit the CAP-js repository above to see more code examples, parameters, and returns for each method. Here we detail the necessary steps based on consuming data for UIs/front-ends.

You can also find to quick code-interactive examples to follow as you read this guide on our GitHub:

Getting Started - CAP-js

Before we can get into any of the fun, we need to download the CAP-js library locally.


You'll need to have @Psychedelic Github Package Registry setup to pull and install from @Psychedelic via the NPM CLI. To do so you'll need:

A personal access token with the following scopes selected

  • repo β†’ [ full control to private repositories]
  • read:packages β†’ [Download packages from GitHub Package Registry]
  • read:org β†’ [Read org and team membership, read org projects]
  • Authentication via npm login, using your GitHub username for the username, the personal access token as your password, and your GitHub email as the email address.

Once you have those ready, run:

npm login --registry= --scope=@Psychedelic

Note: You only need to configure this once to install the package! On npm login provide your Github email as your username and the Personal access token as the password.

The last thing we’ve got to do before installing is setting your npm configuration so that when you run β€˜npm install @psychedelic/’ npm will pull from Github instead of its own registry.

To do this, run:

npm config set @psychedelic:registry

You’re all set! You can now install CAP-js by running:

yarn add @psychedelic/cap-js

Importing CAP-js

To interact with CAP-js we are going to need to import two objects into our application; the Router & Root.

First, an example to better understand CAP’s structure.

You can imagine CAP like a brewery. In this case, the Router object is like a brewmaster. It has the job of overseeing all beer production (transactions) and must keep track of when, where, and by who each different beer (transaction) is produced in the brewery (NFTs/Tokens using CAP, or the beer's brand!).

A Root object can be thought of like a vat in the brewery. Vats hold all of the beer (transactions) for one specific brand (NFT/Token using CAP). Vats can also be tapped to access their contents (see transactions.).

Importing Router & Root

import { CapRouter, CapRoot } from '@psychedelic/cap-js';

Why must we import two different objects instead of interacting with one universal object? Think back to our brewery example. Similar to how there is only ever one brewmaster in a brewery, our application only needs one instance of the Router.

Additionally, we will have to spawn a new Root instance every time we add a canister just like a brewery would have to add another vat when they add a new brand of beer to production. This relationship between only ever having one Router no matter how many Roots there are, is why we import each object individually.

Talking to the Router πŸ—£ - Query CAP to See Available Histories

We will now initialize the Router to start talking to it. When you talk to the router you are asking CAP's main canister (Router) what NFT/Token histories are available in the entire open internet service.

But first, lets initialize it. To do so, we call Router’s init function. The init function takes two optional parameters:

  • host: defaults to IC mainnet
  • canisterId: defaults to CAP’s mainnet canister ID

Here’s an example:

import { CapRouter } from '@psychedelic/cap-js';

const getCapRouterInstance = async ({
}: {
  canisterId?: string,
  host?: string,
}) => await CapRouter.init({

// On a hypotetical application top-level or entry-point
(async () => {
    const capRouter = new getCapRouterInstance();

Asking the Router What Token/NFT Histories are Available

Why have a chat with the Router? He can tell you external information about any or all histories available in CAP. Meaning, all the histories of NFTs/Tokens that integrate CAP.

That's the cool thing. Instead of having to interact/integrate them individually, you can use the Router to find the ones you need (the Tokens where a user has records, or a specific NFT's history, or all of them!).

There are three ways to ask CAP for this information:

  • Ask for all available histories β†’ get_index_canisters( );
  • Ask about a specific NFT/Token's history β†’ get_token_contract_root_bucket( );
  • Ask for histories a user interacted with β†’ get_user_root_buckets( );

The Router will respond all the available histories based on what you asked; and you will be able to interact now with each history (Root) to get specific transaction data.

get_index_canisters( );

Returns the Indexes, which relates to Router, as the index interface (which is currently only implemented by Router canister) is responsible for storing things such as: 1. The root bucket for each canister using Cap 2. The root buckets for a certain user 3. ID of all the other Index canisters It basically exists to allow Cap to expand it's routing mechanism to more than one subnet in future if it becomes a need (data replication/load balancing)

  • witness: The optional Certified response, defaults to false.

get_token_contract_root_bucket( );

Returns the history canister (Root) for a specific Token/NFT project. How do you do so? By passing the Token/NFTs contract canister ID (e.g. XTC's main canister ID). CAP will check if that canister has an associated history, and return the Canister ID of it.

  • canister: Canister ID of the token/NFT contract.
  • witness: The optional Certified response, defaults to false.
capRouter.get_token_contract_root_bucket({canister, witness})

get_user_root_buckets( );

With this method you can ask the router for all the NFT/Token histories in CAP that a specific user (Principal ID) has interacted with.

  • user: The user principal of the requested transactions.
  • witness: The optional Certified response, defaults to false.
capRouter.get_user_root_buckets({user, witness})

Talking to the Root(s)🚰 - Query Transaction Data from Histories

Just like tapping a vat, we can hook up to our a specific Token or NFTs history in CAP (Root) to extract some of its contents (transactions).

To do so, you need to instantiate that Root/history. You will use the Canister IDs the Router provided in the step before to instantiate the different Root/histories. You will pass the canisterID of that Root, and the host will default to the IC mainnet.

import { CapRoot } from '@psychedelic/cap-js';

const getCapRootInstance = async ({
}: {
  canisterId: string,
  host?: string,
}) => await CapRoot.init({

// On a short lived section of your application
(async () => {
    const capRouter = new getCapRootInstance({
        canisterId: 'rrkah-fqaaa-aaaaa-aaaaq-cai',

Available Methods for Querying Data

With the Root/History of your desired NFT/Token instantiated, you can start querying data! Three ways to tap into a vat (Root):

  • Ask for a single transaction β†’ get_transaction( );
  • Ask for all transactions β†’ get_transactions( );
  • Ask for a specific case of beer β†’ get_user_transactions( );

get_transaction( );

Allows you to query a specific transaction in that Token/NFT's history. You pass an ID for the index of the transaction you are looking to query.

  • id: the global txnId of a transaction.
  • witness: the optional witness for certified response.
capRoot.get_transaction(id, witness)

get_transactions( );

Allows you to query all available transactions in the NFT/Token's history. It will return page objects of up to 64 transactions each. This method always defaults to the most recent 64 transactions.

  • page: The optional number of the page to query for transactions, each page can hold up to 64 transactions. Defaults to page 0.
  • witness: the optional witness for certified response.
capRoot.get_transactions({page, witness})

get_user_transactions( );

Allows you to query all available transactions for a specific user (Principal ID). You pass a Principal ID and it will return a page object (similarly to the method above) with the transactions tied to that specific user. If you don't specify a page,

  • page: The optional number of the page to query for transactions, each page can hold up to 64 transactions. Defaults to page 0.
  • user: The user principal of the requested transactions.
  • witness: the optional witness for certified response.
capRoot.get_user_transactions(({page, user, witness})