Skip to main content

High Level API Specification

Introduction

This document specifies a user-friendly API to be used in the client libraries. The main implementation will be in Rust which will receive automatically compiled client libraries in other languages via C or Webassembly bindings. There are also many crates to support developers creating foreign function interfaces with native bindings.

Builder

The data structure to initialize the instance of the Higher level client library. This is always called first when starting a new interaction with the library. Note: This is the common approach to do initialization in Rust. Different languages might use different methods such as just calling an initialization function directly.

Parameters

ParameterRequiredDefault ValueTypeDefinition
networkTestnet&strOptional, the network type can be "testnet" or "mainnet". If no node url is provided, some default nodes are used for the specified network. Nodes that aren't in this network will be ignored.
nodeNone&strThe URL of a node to connect to; format: https://node:port
primary_nodeNone&str, auth_name_pwd: Option<(&str, &str)>The URL of a node to always connect first to, if multiple nodes are available. Optional JWT and or name and password for basic authentication; format: https://node:port, Some("JWT"), Some("name", "password")
primary_pow_nodeNone&str, auth_name_pwd: Option<(&str, &str)>The URL of a node to always connect first to when submitting a message with remote PoW, if multiple nodes are available. Will override primary_node in that case. With optional JWT or name and password for basic authentication; format: https://node:port, Some("JWT"), Some("name", "password")
permanodeNone&str, auth_name_pwd: Option<(&str, &str)>The URL of a permanode. With optional JWT or name and password for basic authentication; format: https://node:port, Some("JWT"), Some("name", "password")
node_authNone&str, Option
, Option<(&str, &str)>
The URL of a node to connect to with optional JWT and or name and password for basic authentication; format: https://node:port, Some("JWT"), Some("name", "password")
nodesNone&[&str]A list of nodes to connect to; nodes are added with the https://node:port format. The amount of nodes specified in quorum_size are randomly selected from this node list to check for quorum based on the quorum threshold. If quorum_size is not given the full list of nodes is checked.
node_sync_intervalDuration::from_secs(60)std::time::DurationThe interval in milliseconds to check for node health and sync
node_sync_disabledfalseboolIf disabled also unhealty nodes will be used
node_pool_urlsNone&[String]A list of node_pool_urls from which nodes are added. The amount of nodes specified in quorum_size are randomly selected from this node list to check for quorum based on the quorum threshold. If quorum_size is not given the full list of nodes is checked.
quorumfalseboolDefine if quorum should be used for the requests
quorum_size3usizeDefine how many nodes should be used for quorum
quorum_threshold66usizeDefine the % of nodes that need to return the same response to accept it
request_timeoutDuration::from_secs(30)std::time::DurationThe amount of seconds a request can be outstanding to a node before it's considered timed out
api_timeoutApi::GetInfo: Duration::from_secs(2)),
Api::GetHealth: Duration::from_secs(2),
Api::GetPeers: Duration::from_secs(2),
Api::GetMilestone: Duration::from_secs(2),
Api::GetTips: Duration::from_secs(2),
Api::PostMessage: Duration::from_secs(2),
Api::PostMessageWithRemotePow: Duration::from_secs(30),
Api::GetOutput: Duration::from_secs(2)
HashMap<Api,
std::time::Duration>
The amount of milliseconds a request to a specific Api endpoint can be outstanding to a node before it's considered timed out.
local_powTrueboolIf not defined it defaults to local PoW to offload node load times
tips_interval15u64Time interval during PoW when new tips get requested.
mqtt_broker_optionsTrue,
Duration::from_secs(30),
True
BrokerOptionsIf not defined the default values will be used
  • Note that there must be at least one node to build the instance successfully.

Return

Finalize the builder with finish() will run the instance in the background. Users don’t need to worry about the return object handling.

On initialization

On initialisation, call getNodeInfo API. Check the health of each node in the node list, and put healty nodes, matching the PoW settings and network in a synced nodelist.

Node metadataDescription
networkIf this parameter does not match the global builder parameter, don't add it to the synced nodelist.
powIf the global local_pow parameter is set to false, then put only nodes with the PoW feature in the synced nodelist.

Sync Process

When a Client instance (The instance which is used for calling the client APIs) is built, the status of each node listed is checked. If the returned status of the node information is healthy, which means the node is synced, then this node will be pushed into a synced_nodes list. The rust-like pseudo code of synced_nodes construction process follows. The process of syncing a node is repeated every 60 seconds or at the interval specified in the node_sync_interval argument of the initializer if set.

synced_nodes = Vec::new()
for node in node_pool_urls{
status = Client.get_info(node).await?;
if status == healthy{
synced_nodes.push(node)
}
}

General high level API

Here is the high level abstraction API collection with sensible default values for users easy to use.

message()

A generic send function for easily sending a message.

Parameters

ParameterRequiredDefaultTypeDefinition
seedNoneSeedThe seed of the account we are going to spend, only needed for transactions
account_index0usizeThe account index, responsible for the value in the Bip32Path m/44'/4218'/✘'/0'/0'.
initial_address_index0usizeThe index from where to start looking for balance. Responsible for the value in the Bip32Path m/44'/4218'/0'/0'/✘'.
inputNoneUtxoInputUsers can manually select their UtxoInputs instead of having automatically selected inputs.
input_range0..100RangeCustom range to search for the input addresses if custom inputs are provided.
outputNoneaddress: &[String],
amount: u64
Address to send to and amount to send. Address needs to be Bech32 encoded.
output_hexNoneaddress: &str,
amount: u64
Address to send to and amount to send. Address needs to be hex encoded.
indexNone&[u8] / &strAn optional indexation key for an indexation payload. 1-64 bytes long.
dataNoneVec<u8>Optional data for the indexation payload.
parentsNoneMessageId1-8 optional parents MessageId to be used.

Depending on the provided values this function will create a message with:

  • no payload
  • an indexation payload
  • a transaction payload
  • a transaction payload containing an indexation payload

Return

The Message object we build.

Implementation Details

  • Validate inputs, such as address and seed to check if they are correct.
  • Check if account balance is bigger or equal to the value using method similar to get_balance();
  • Build and validate the message with signed transaction payload accordingly;
  • Get tips using get_tips();
  • Perform proof-of-work locally (if not set to remote);
  • Send the message using post_messages();

get_message()

(GET /api/v1/messages)

Endpoint collection all about GET messages.

Parameters

ParameterRequiredTypeDefinition
message_idMessageIdThe identifier of message.
index&[u8] / &strAn indexation key.

Returns

Depend on the final calling method, users could get different results they need:

  • metadata(&MessageId): Return MessageMetadata of the message.
  • data(&MessageId): Return a Message object.
  • raw(&MessageId): Return the raw data of given message.
  • children(&MessageId): Return the list of MessageIds that reference a message by its identifier.
  • index(&[u8] | &str) : Return the list of MessageIds that have this str as indexation key

find_messages()

Find all messages by provided message IDs.

Parameters

ParameterRequiredTypeDefinition
indexation_keys[&[u8] / &str]The index key of the indexation payload.
message_ids[MessageId]The identifier of message.

Returns

A vector of Message Object.

get_unspent_address()

Return a valid unspent public Bech32 encoded address.

Parameters

ParameterRequiredDefaultTypeDefinition
seed-SeedThe seed we want to use.
account_index0usizeThe account index, responsible for the value in the Bip32Path m/44'/4218'/✘'/0'/0'.
initial_address_index0usizeStart index of the addresses to search. Responsible for the value in the Bip32Path m/44'/4218'/0'/0'/✘'.

Return

Return a tuple with type of (String, usize) as the address and corresponding index in the account.

Implementation Details

Following are the steps for implementing this method:

  • Start generating addresses with given account index and starting index. We will have a default gap limit of 20 at a time;
  • Check for balances on the generated addresses using find_outputs() and keep track of the positive balances;
  • Repeat the above step till there's an unspent address found;
  • Return the address with corresponding index on the wallet chain;

get_addresses()

Return a list of addresses from the seed regardless of their validity.

Parameters

ParameterRequiredDefaultTypeDefinition
seedNoneSeedThe seed we want to search for.
account_index0usizeThe account index, responsible for the value in the Bip32Path m/44'/4218'/✘'/0'/0'.
rangeNonestd::ops::RangeRange indices of the addresses we want to search for. Default is (0..20)
get_allGet public and change addresses. Will return Vec<([String], bool)>, where the bool is indicating whether it's a change address

Return

Vec<[String]>, with the public addresses

get_balance()

Return the balance for a provided seed and its wallet account index.

Parameters

ParameterRequiredDefaultTypeDefinition
seed-SeedThe seed we want to search for.
account_index0usizeThe account index, responsible for the value in the Bip32Path m/44'/4218'/✘'/0'/0'.
initial_address_index0usizeStart index from which to generate addresses. Default is 0. Responsible for the value in the Bip32Path m/44'/4218'/0'/0'/✘'.
gap_limit20usizeThe gap limit specifies how many addresses will be checked each round. If gap_limit amount of addresses in a row have no balance the function will return.

Return

Total account balance.

Implementation Details

Following are the steps for implementing this method:

  • Start generating addresses with given wallet account index and starting index. We will have a default gap limit of 20 at a time;
  • Check for balances on the generated addresses using find_outputs() and keep track of the positive balances;
  • Repeat the above step till an address of zero balance is found;
  • Accumulate the positive balances and return the result.

get_address_balances()

Return the balance in iota for the given addresses; No seed or security level needed to do this since we are only checking and already know the addresses.

Parameters

ParameterRequiredTypeDefinition
addresses[[String]]List of Bech32 encoded addresses.

Return

A list of tuples with value of AddressBalancePair. The usize is the balance of the address accordingly.

Implementation details:

Following are the steps for implementing this method:

  • Validate address semantics;
  • Get latest balance for the provided address using find_outputs() with addresses as parameter;
  • Return the list of Output which contains corresponding pairs of address and balance.

generate_mnemonic()

Returns a random generated Bip39 mnemonic with the English word list.

Return

Parsed [String].

mnemonic_to_hex_seed(mnemonic)

Returns the seed hex encoded.

Parameters

ParameterRequiredTypeDefinition
mnemonic[String]Bip39 mnemonic with words from the English word list.

Return

Parsed [String].

bech32_to_hex()

Returns a parsed hex String from bech32.

Parameters

ParameterRequiredTypeDefinition
bech32[String]Bech32 encoded address.

Return

Parsed [String].

hex_to_bech32()

Returns a parsed bech32 String from hex.

Parameters

ParameterRequiredTypeDefinition
hex[String]Hex encoded address.
bech32_hrp[Option
]
Optional bech32 hrp.

Return

Parsed [String].

parse_bech32_address()

Returns a valid Address parsed from a String.

Parameters

ParameterRequiredTypeDefinition
address[String]Bech32 encoded address.

Return

Parsed Address.

is_address_valid()

Parameters

ParameterRequiredTypeDefinition
address[String]Bech32 encoded address.

Return

A boolean showing if the address is valid.

subscriber()

Subscribe to a node event Topic (MQTT)

Required: one of

  • topic(): Add a new Topic to the list.

  • topics(): Add a vector of Topic to the list.

  • subscribe(): Subscribe to the given topics with the callback, which will be called every time when the topic is detected.

  • unsubscribe(): Unsubscribes from all subscriptions.

  • disconnect(): Disconnects the broker. This will clear the stored topic handlers and close the MQTT connection.

Returns

Nothing apart from a Ok(()) result if successful

retry()

Retries (promotes or reattaches) a message for provided MessageId if the node suggests it. The need to use this function should be low, because the confirmation throughput of the node is expected to be quite high.

Parameters

ParameterRequiredTypeDefinition
message_idMessageIdThe identifier of message.

Returns:

A tuple with the newly promoted or reattached (MessageId, Message).

Implementation Details

Following are the steps for implementing this method:

  • Only unconfirmed messages should be allowed to retry. The method should validate the confirmation state of the provided messages. If a message id of a confirmed message is provided, the method should error out;
  • The method should also validate if a retry is necessary. This can be done by leveraging the /messages/{messageId}/metadata endpoint (already available through get_message). See this implementation for reference;
  • Use reattach or promote accordingly.

retry_until_included()

Retries (promotes or reattaches) a message for provided MessageId until it's included (referenced by a milestone). Default interval is 5 seconds and max attempts is 40. The need to use this function should be low, because the confirmation throughput of the node is expected to be quite high.

Parameters

ParameterRequiredTypeDefinition
message_id[&MessageId]The identifier of message.
intervalOption<u64>The interval in which we retry the message.
max_attemptsOption<u64>The maximum of attempts we retry the message.

Returns:

An array of tuples with the newly reattached (MessageId, Message).

consolidate_funds()

Function to consolidate all funds from a range of addresses to the address with the lowest index in that range

Parameters

| Parameter | Type | Definition | | ----------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | | seed | Seed | The seed we want to search for. | | account_index | usize | The account index, responsible for the value in the Bip32Path m/44'/4218'/✘'/0'/0'. | | address_range | Range | Range from which to generate public and internal addresses from which to consolidate the funds. Responsible for the value in the Bip32Path m/44'/4218'/0'/0'/✘'. |

Returns:

The address to which the funds got consolidated.

reattach()

Depends on find_messages, get_message and post_message.

Reattaches a message. The method should validate if a reattachment is necessary through get_message. If not, the method should error out and should not allow unnecessary reattachments.

Parameters

ParameterRequiredTypeDefinition
message_idMessageIdThe identifier of message.

Returns

A tuple with the newly reattached (MessageId, Message).

promote()

Depends on find_messages, get_message and post_message.

Promotes a message. The method should validate if a promotion is necessary through get_message. If not, the method should error out and should not allow unnecessary promotions.

Parameters

ParameterRequiredTypeDefinition
message_idMessageIdThe identifier of message.

Returns

A tuple with the newly promoted (MessageId, Message).

Full node API

Full node API of Bee and HORNET will still be public. Users who know these relative low level Restful API can still call them directly if they are confident and think it’s good for them. Note that both Bee and HORNET haven't finalized their APIs either. Following items and signatures might change later.

get_health()

(GET /health)

Returns the health of the node, which can be used for load-balancing or uptime monitoring.

Parameters

None

Returns

Boolean to indicate if node is healthy.

get_peers()

(GET /peers)

Get information about the peers of the node.

Parameters

None

Returns

pub struct PeerDto {
pub id: String,
#[serde(rename = "multiAddresses")]
pub multi_addresses: Vec<String/>,
pub alias: Option<String/>,
pub relation: RelationDto,
pub connected: bool,
pub gossip: Option<GossipDto/>,
}

get_info()

(GET /api/v1/info)

Returns information about the node.

Parameters

None

Returns

A Response Object similar to this:

pub struct NodeInfoWrapper {
pub nodeinfo: NodeInfo,
pub url: String,
}
pub struct NodeInfo {
pub name: String,
pub version: String,
pub is_healthy: bool,
pub network_id: String,
pub latest_milestone_index: usize,
pub min_pow_score: f64,
pub messages_per_second: f64,
pub referenced_messages_per_second: f64,
pub referenced_rate: f64,
pub latest_milestone_timestamp: u64,
pub confirmed_milestone_index: usize,
pub pruning_index: usize,
pub features: Vec<String/>,
}

get_tips()

(GET /tips)

Returns two non-lazy tips. In case the node can only provide one tip, tip1 and tip2 are identical.

Parameters

None

Returns

A tuple with two MessageId:

(MessageId, MessageId)

post_message()

(POST /message)

Submit a message. The node takes care of missing fields and tries to build the message. On success, the message will be stored in the Tangle. This endpoint will return the identifier of the message.

Parameters

ParameterRequiredTypeDefinition
messageMessageThe message object.

Returns

The MessageId of the message object.

get_output()

(GET /outputs)

Get the producer of the output, the corresponding address, amount and spend status of an output. This information can only be retrieved for outputs which are part of a confirmed transaction.

Parameters

ParameterRequiredTypeDefinition
output_idUtxoInputIdentifier of the output.

Returns

An OutputMetadata that contains various information about the output.

get_address()

(GET /addresses)

Parameters

ParameterRequiredTypeDefinition
address[String]The address to search for.

Returns

Depend on the final calling method, users could get different outputs they need:

  • balance(): Return confirmed balance of the address.
  • outputs([options]): Return UtxoInput array (transaction IDs with corresponding output index).

find_outputs()

Find all outputs based on the requests criteria.

Parameters

ParameterRequiredTypeDefinition
output_id[UtxoInput]The identifier of output.
addresses[[String]]The Bech32 encoded address.

Returns

A vector of OutputMetadata.

get_milestone()

(GET /milestones)

Get the milestone by the given index.

Parameters

ParameterRequiredTypeDefinition
indexu32Index of the milestone.

Returns

An Milestone object.

get_milestone_utxo_changes()

(GET /milestones/{}/utxo-changes)

Get all UTXO changes of a given milestone.

Parameters

ParameterRequiredTypeDefinition
indexu32Index of the milestone.

Returns

MilestoneUTXOChanges {
index: 1,
created_outputs: [],
consumed_outputs: [],
}

get_receipts()

(GET /receipts)

Get all receipts.

Returns

Vec<ReceiptDto/>

get_receipts_migrated_at()

(GET /receipts/{migratedAt})

Get all receipts for a given milestone index.

Returns

Vec<ReceiptDto/>

get_treasury()

(GET /treasury)

Get the treasury amount.

Returns

pub struct TreasuryResponse {
#[serde(rename = "milestoneId")]
milestone_id: String,
amount: u64,
}

get_included_message()

(GET /transactions/{transactionId}/included-message)

Get the included message of the transaction.

Parameters

ParameterRequiredTypeDefinition
transaction_id[TransactionId]The id of the transaction.

Returns

struct Message {
parents: Vec<MessageId/>,
payload: Option<Payload/>,
nonce: u64,
}

Objects

Here are the objects used in the API above. They aim to provide a secure way to handle certain data structures specified in the Iota stack.

MessageId

MessageId is a 32 bytes array which can represent as hex string.

struct MessageId([u8; MESSAGE_ID_LENGTH]);

Seed

pub enum Seed {
/// Ed25519 variant
Ed25519(Ed25519Seed)
}

An IOTA seed that inner structure is omitted. Users can create this type by passing a String. It will verify and return an error if it’s not valid. |

Message

The message object returned by various functions; based on the RFC for the Message object. Here's the brief overview of each components in Message type would look like:

struct Message {
parents: Vec<MessageId/>,
payload: Option<Payload/>,
nonce: u64,
}

enum Payload {
Transaction(Box<Transaction/>),
Milestone(Box<Milestone/>),
Indexation(Box<Indexation/>),
}

struct Transaction {
pub essence: TransactionPayloadEssence,
pub unlock_blocks: Vec<UnlockBlock/>,
}

struct Milestone {
essence: MilestoneEssence,
signatures: Vec<Box<[u8]>>,
}

struct Indexation {
index: String,
data: Box<[u8]>,
}

struct TransactionPayloadEssence {
pub(crate) inputs: Box<[Input]>,
pub(crate) outputs: Box<[Output]>,
pub(crate) payload: Option<Payload/>,
}

enum Input {
UTXO(UtxoInput(OutputId)),
}

struct OutputId {
transaction_id: TransactionId,
index: u16,
}

enum Output {
SignatureLockedSingle(SignatureLockedSingleOutput),
}

struct SignatureLockedSingleOutput {
address: Address,
amount: u64,
}

enum UnlockBlock {
Signature(SignatureUnlock),
Reference(ReferenceUnlock),
}

enum SignatureUnlock {
Ed25519(Ed25519Signature),
}

struct Ed25519Signature {
public_key: [u8; 32],
signature: Box<[u8]>,
}

struct ReferenceUnlock(u16);

MessageMetadata

pub struct MessageMetadata {
/// Message ID
pub message_id: String,
/// Message IDs of parents
pub parents: Vec<String/>,
/// Solid status
pub is_solid: bool,
/// Should promote
pub should_promote: Option<bool/>,
/// Should reattach
pub should_reattach: Option<bool/>,
/// Referenced by milestone index
pub referenced_by_milestone_index: Option<u32>,
/// Ledger inclusion state
pub ledger_inclusion_state: Option<String/>,
}

OutputMetadata

The metadata of an output:

pub struct OutputMetadata {
/// Message ID of the output
pub message_id: Vec<u8>,
/// Transaction ID of the output
pub transaction_id: Vec<u8>,
/// Output index.
pub output_index: u16,
/// Spend status of the output
pub is_spent: bool,
/// Corresponding address
pub address: Address,
/// Balance amount
pub amount: u64,
}

Address

An Ed25519 address can be encoded in Bech32 or Hex, with Bech32 being preferred and also used in most functions.

pub enum Address {
Ed25519(Ed25519Address),
}

AddressBalancePair

pub struct AddressBalancePair {
/// Address, bech32 encoded
pub address: String,
/// Balance in the address
pub balance: u64,
/// If dust is allowed on the address
pub dust_allowed: bool,
}

Milestone

A milestone metadata.

pub struct MilestoneMetadata {
/// Milestone index
pub milestone_index: u32,
/// Milestone ID
pub message_id: String,
/// Timestamp
pub timestamp: u64,
}

Api

pub enum Api {
/// `get_health` API
GetHealth,
/// `get_info`API
GetInfo,
/// `get_tips` API
GetTips,
/// `post_message` API
PostMessage,
/// `post_message` API with remote pow
PostMessageWithRemotePow,
/// `get_output` API
GetOutput,
/// `get_milestone` API
GetMilestone,
}

BrokerOptions

pub struct BrokerOptions {
#[serde(default = "default_broker_automatic_disconnect", rename = "automaticDisconnect")]
pub(crate) automatic_disconnect: bool,
#[serde(default = "default_broker_timeout")]
pub(crate) timeout: std::time::Duration,
#[serde(rename = "maxReconnectionAttempts", default)]
pub(crate) max_reconnection_attempts: usize,
}

Topic

A string with the exact MQTT topic to monitor, can have one of the following variations:

milestones/latest
milestones/confirmed

messages
messages/referenced
messages/indexation/{index}
messages/{messageId}/metadata
transactions/{transactionId}/included-message

outputs/{outputId}

addresses/{address}/outputs
addresses/ed25519/{address}/outputs