RPC endpoints of a Lisk node
The open Lisk communication architecture is based on two different RPC (Remote-Procedure-Call), API modes: Inter-Process Communication (IPC) and WebSocket (WS). The Application can be configured to either expose an IPC or a WS API that can be used by internal components such as modules and plugins, as well as by any external service such as other scripts in JS, a tool in Rust, or a Python daemon.
For more information about the configuration of the RPC endpoints, check out the configuration guide. |

The API client
The API client simplifies sending API requests to a blockchain application via IPC or WS.
It can be imported in any JS client application.
It provides an interface to subscribe to all events and to invoke actions of the blockchain application and its' modules & plugins.
To conveniently communicate with a blockchain application, use the apiClient which is included in the @liskhq/lisk-client and the lisk-sdk packages.
|
const { apiClient } = require('@liskhq/lisk-client');
let clientCache;
const nodeAPIURL = 'ws://localhost:8080/ws';
const getClient = async () => {
if (!clientCache) {
clientCache = await apiClient.createWSClient(nodeAPIURL);
}
return clientCache;
};
const blockId = 123;
getClient().then((client) => {
client.invoke("app:getBlockByID", {
id: blockId
}).then(res => {
const decodedBlock = client.block.decode(res);
console.log("Decoded block: ", decodedBlock);
process.exit(0);
});
});
const { apiClient } = require('@liskhq/lisk-client');
let clientCache;
const nodeAPIURL = 'ws://localhost:8080/ws';
const getClient = async () => {
if (!clientCache) {
clientCache = await apiClient.createIPCClient('~/.lisk/my-app');
}
return clientCache;
};
const blockId = 123;
getClient().then((client) => {
client.invoke("app:getBlockByID", {
id: blockId
}).then(res => {
const decodedBlock = client.block.decode(res);
console.log("Decoded block: ", decodedBlock);
process.exit(0);
});
});
IPC vs WS
There are two methods available whereby a node can communicate via the API:
-
IPC (Inter-Process-Communication)
-
WS (WebSocket)
In general, IPC is the preferred method for local connections for the following reasons:
-
It is slightly faster
-
It supports synchronous data exchange
-
It does not use the system ports, therefore avoiding any risk of collision when the ports are already in use by another application
WS, on the contrary, should be used if the node API communicates with services on remote servers.
Channels
All modules and plugins have access to a channel
to communicate with the application via actions and events.
Channel for modules
The channel in modules has only one purpose: it allows a module to publish events to the application which were defined in the Events property of the module.
The channel is accessible inside of a module under this._channel
.
It is used especially in the lifecycle-hooks, to publish the events of the module.
The following function is available for a channel
inside a module:
-
publish(eventName: string, data?: object)
: Publishes an event.
An example how to use the channel to publish an event is shown below:
this._channel.publish('hello:newHello', {
sender: transaction._senderAddress.toString('hex'),
hello: helloAsset.helloString
});
The above code example will publish the event hello:newHello
to the application, and attach an object which is containing the sender address and the hello message of the last sent hello transaction.
Channel for plugins
The channel is used inside of the load() function of a plugin.
The following functions are available for a channel
inside a plugin:
-
publish(eventName: string, data?: object)
: Publishes an event. -
subscribe(eventName: string, cb: EventCallback)
: Subscribes to an event. -
once(actionName: string, cb: EventCallback)
: Executes the callback only once, when receiving the event for the first time. -
invoke(actionName: string, params?: object)
: Invokes an action.
channel.subscribe('app:block:new', ({ data }) => {
const decodedBlock = this.codec.decodeBlock(data.block);
this._knownTimestamps.push(decodedBlock.header.timestamp);
channel.publish('myPlugin:timestamp', { timestamp: decodedBlock.header.timestamp });
});
Aliases
Example alias:
"monitor:getTransactionStats"
The alias always consists of the following parts:
-
Prefix: Consists of the module or plugin name that provides the respective action or event. Equals
app
if it’s an application event or action. The prefixmonitor
in this example is referring the the Monitor plugin. -
Separator: Prefix and suffix are always separated by a colon
:
. -
Suffix: The respective name of the event or action.
Interfaces
A blockchain application communicates via Actions and Events which can be invoked (actions), or subscribed to (events), via WebSocket.
The different components of the application each have access to different parts of these interfaces. This is summarized in the following table.
For each action and event displayed below, the following statements apply:
-
…
reply
means, the component can reply to this kind of RPC request. -
…
invoke
means, the component can invoke this kind of RPC request. -
…
publish
means, the component can publish events. -
…
subscribe
means, the component can subscribe to events.

Actions
Actions are invoked to receive specific data from the blockchain application. Actions are part of the request / response API, and are invoked via RPCs.
The following components can expose actions:
-
and also the application itself, see application actions
The following components can invoke actions:
-
Plugins
-
External services/applications
How to invoke actions
The first argument is always the alias. If input data is required, it is provided as a second argument.
Actions can be invoked by The API client.
const data = await client.invoke('app:getSchema'); (1)
const data = await client.invoke('app:actionName', input); (2)
client.invoke('monitor:getTransactionStats').then((val) => { (3)
console.log(val);
});
1 | How to invoke an action. |
2 | How to invoke an action that needs some data input. |
3 | Example of how to invoke an action of the monitor plugin. |
Actions can be invoked by plugins with the Channel for plugins.
this._nodeInfo = await this.channel.invoke("app:getNodeInfo");
Events
Events are part of the public publish / subscribe API of a blockchain application. If an event is published it is immediately received by all of the subscribers of the event.
The following components can publish events:
-
and also the application itself, see application events
The following components can subscribe to events:
-
Plugins
-
External services / applications
How to publish and subscribe to events
Events are published inside lifecycle hooks of the module.
The channel
is available inside the lifecycle hooks, which offers the possibility to subscribe and publish to events, as well as invoking actions in the network.
channel.publish('pluginAlias:timestamp', { info: 'sample' });
Example for subscribing to an event by utilizing The API client:
client.subscribe('pluginAlias:timestamp', ( data ) => {
console.log(data);
});
client.subscribe('app:block:new', ( data ) => {
console.log('new block:',data);
});