TokenD (4.6.0)

TokenD is a multifunctional white label platform that consolidates the experience gained by Distributed Lab in building the production-ready tokenization solutions. It allows you to issue, transfer, and exchange your assets with high level of privacy, security, and auditability while following regulations of your jurisdiction. TokenD is designed for building tokenization solutions which you fully own and can customize; using its ready-to-use toolkit, one can release their blockchain product in a short time to market and without having to maintain the team of blockchain developers.

In the following video you can see sub-set of features supported by TokenD applied to the tokenized tickets use-case.


TokenD is designed for entrepreneurs and enterprises willing to take advantage of tokenization or experiment with the blockchain technology. TokenD can be used to build your own tailored next-generation accounting system: flexible, secure, auditable, and adaptive in terms of legislation.


Flexibility lies in the separation of processes in accounting: identity management, wallet management, asset transfer and exchange, role management, token lifecycle management, and deposit/withdraw. All these processes are performed by independent modules and can be customized through adjustable template smart contracts that the platform supports. Combination of these approaches allows for an easy integration with existing legacy systems.


User secret data never touch the servers. The system allows for interaction in which users never transfer their secret data (e.g., password) to the server. This means that the compromise of this data during the network transfer—as well as through hacking the key server—is excluded. Therefore, the platform owner no longer has to consider risks related to storing the user secret data as well as spend time and resources on providing additional security.

Hacker compromise won’t corrupt the system state. The state of the ledger entirely depends on transactions performed. Since all transactions are initiated by the users themselves via cryptographic keys, a malicious party won’t be able to modify the shared ledger even having full access to one of the servers storing it.


Accounting system can be real-time audited by an independent party 24/7. In particular, an auditor can be given a node with blockchain synchronized in real time and automatically (using the dedicated software) verify the correctness of ongoing processes.


The system supports adaptive permission management, which relates to both users and admins. Access levels can be fully customized for each account according to factors you adjust (e.g., country, age, income, etc.). This allows adapting the system's business logic according to regulations of particular legislation.

Why we built TokenD?

  • There are no out-of-box operating solutions available.
  • Average delivery time for MVP using other platforms ~1 year.
  • 70% of development work is the same for all projects.
  • Basic features require changes on the blockchain level.
  • High entry threshold for new developers.

How TokenD differs from other platforms?

Feature Set R3 Corda Hyperledger Fabric Ethereum TokenD
Consensus RAFT Kafka pBFT FBA
Smart Contracts
Private Transactions
External System
Integration toolkit
Web/iOS/Android Wallet
Commercial-scale funds
management kit
Role-based Access Control
Vanilla Regulatory
compliance framework

External System Integration toolkit

  • Consistent sequence of all operations occurring in the system with a set of changes applied to the ledger.
  • SDKs, intuitive REST API.
  • Unique ID tracking for crucial operations.
  • Reference implementation of external systems integration.

Web/iOS/Android Wallet

  • Fully featured opensource native web, iOS and Android apps.
  • Secure on device key storage;
  • Designed to ease customization;
  • Native SDKs to build your own implementation;

Commercial-scale funds management kit

  • Tasks based issuance and withdrawal requests designed for secure integrations with external systems;
  • Secure offline app for tokens issuance authorization;
  • On-chain crowdfunding module with several price finding algorithms;
  • Decentralized exchange;

Role-based Access Control & Multi-signature

  • Define on-chain user access rights to follow regulations;
  • Tasks based approach to review critical user’s operations in the system;
  • Define signers rules to distribute rights among admins of the system to minimize risks of fraud;
  • Use multi-signature for decentralized decision making.

Vanilla Regulatory compliance framework

  • Manage deposit, transfer, withdrawal limits to follow regulation and/or secure the system;
  • Tasks based approach for user roles transition;
  • GDPR compilate off-chain personal data storage with guaranty of integrity;
  • Direct user-admin communication to resolve issues.

Run your first network

Quick way for running TokenD local development environment with Docker. For production deployment use this guide.


Bootstraping your environment

# drop any persistent state to make sure you are working with clean install
$ docker-compose down -v && docker-compose pull
# spin everything up
$ docker-compose up -d
# wait while environment initialization is complete
$ docker-compose logs -f initscripts

Now you should be able to access web client at http://localhost:8060 and admin dashboard at http://localhost:8070 default seed for login is SAMJKTZVW5UOHCDK5INYJNORF2HRKYI72M5XSZCBYAHQHR34FFR4Z6G4

These instructions are just a guideline for what you should generally do. You may modify provided docker-compose.yml or configuration files in configs directory to accommodate your needs.


If you need any help with TokenD or would like to suggest a feature, please reach us via


TokenD is a highly modular system built using the microservices architecture. TokenD can be divided into two parts: DLT-based logic (node) responsible for the key functionalities such as tokens management and distribution, rights management, etc.; auxiliary modules, which interconnect DLT with external systems, store user data, etc. A detailed overview of these modules and their connections is specified in figure below.

Architecture of TokenD system


Node is a key component of the platform. It processes transactions, manages history, and provides an easy to use API to access the blockchain data. It consists of two modules:

  • Core — a replicated state machine that maintains a local copy of cryptographic ledger and processes transactions against it in consensus with a set of peers. It implements the federated consensus protocol and is responsible for tokens accounting and roles management. Documentation for the API is available here.

  • Horizon is the client-facing REST API server. It acts as an interface between the core and applications that want to access the network. It allows submitting transactions to the network, checking the status of accounts, and viewing transaction history. Documentation is available here.

Identity Service (KYC Storage)

Identity Service is a GDPR compliant module which stores data collected during the KYC (know your customer) procedure. To access the data, a user or admin needs to provide the digital signature, which is verified against the most recent state of the ledger. Such an approach provides a high level of security. This module also stores client-side-encrypted private keys of users. This prevents a malicious actor from getting access to the accounts of the system even having a full access to the storage. Documentation for this module is available here.

Web, iOS, Android wallets

Web Client Web, iOS, Android wallets are client facing applications that provide a wide range of functionalities: from storage of encrypted private keys on the device, to token transfers, withdrawals, and trading. They interact with the core of the system directly through the Horizon module and signs all transactions and requests locally. Such an approach ensures that users’ private keys are safe even in case of MITM (man in the middle) attacks.

Auxiliary Modules

Auxiliary modules connect blockchain with real world. Different modules are responsible for different processes: external integrations, payment system, exchange, identity verification, etc.

Modules communicate with nodes via API. Such a separation of accounting by the processes performed allows for easy integration with existing — even legacy-systems. Each module can be configured, replaced, and enhanced according to particular business requirements.

[PSIM] (Payment Services Integration Module) is a set of modules that play the role of a bridge between TokenD public blockchains, banks, payment gateways, exchanges. They reflect corresponding operations like deposit, withdrawal and exchange rate changes in another system.

ESIM (External System Integration Module) is a set of modules that interconnects TokenD with various external systems. They are responsible for a wide range of functionalities: from transfer notifications to automatization of the user identity verification.

Key Concepts


Accounts are the central data structure in TokenD. Each account has:

  • Cryptographic keys (with their weight)
  • Permissions representing which operations can be performed

Key pair

All accounts are identified by a public key and, basically, are a piece of data stored on the ledger. All other data on the ledger, such as assets, offers, or KYC data, are associated with accounts.

The weight of a key determines its level of access for initiating a specific operation. Weight is needed to define the threshold for an operation to be performed.


To perform operations, for all accounts there is a set of permissions. Permissions are configured by administrators and can be customized for each individual account (this also relates to administrators who should have appropriate permission to configure the permissions of other accounts).

Types of accounts

All accounts in TokenD can be split into two types: admin and user. Admins make decisions on configuring the system and setting business rules as well as verify users and grant them rights (permissions) to perform certain activity on the platform.

Users take advantage of the system functionality by performing operations—which they have permission to perform.

Transactions and Operations

Each operation in the system (e.g., send a payment, manage orders, change account settings, etc.) is represented by a transaction. Moreover, one transaction may contain up to 100 operations. The result of each transaction is the modification of the TokenD ledger state.

Transactions are atomic, meaning that if there are multiple operations in one transaction, either all operations are performed successfully or none is. Thus, if one operation from the list fails, an entire transaction fails as well.

Each operation:

  • Is performed by an account directly, via keys;
  • Requires permission;
  • Has a weight threshold which the signer must have to be able to perform it.

Keys. Each operation is signed by keys. Only the keys owner is able to perform operations associated with their account.

Permission. An account should have appropriate permission to perform a particular operation.

Threshold. Weight threshold is the signer’s access level, meaning that in order to perform a particular operation, a signer or group of signers should have the total weight equal or higher than the operation threshold. This is implemented via the multisignature mechanism.

Keys Management

Like any other system, TokenD requires users to register and authorize. The crucial difference, however, lies in the following aspects:

  • Password never leaves the user's device. There is no sense for an attacker in listening to the communication between a user and server (no sensitive data is ever transferred).
  • Server does not store the user confidential/sensitive data. User confidential data is no longer under the leakage threat, meaning that platform owners can focus on their service—provision of a playground for operation with tokenized assets—rather than on providing the security of the user secret data (e.g., passwords, keys).
  • No password authentication. User flow stays the same: enter a password. Under the hood, however, the process is entirely different (for more details, see authorization).
  • Database compromise is senseless. Information transferred and stored on the server doesn’t present value for an attacker because it is encrypted by the keys which are known ONLY to a user.
  • Keys are stored on a server, but only a user has access. The server is only a custodian storing encrypted keys which only a user knows how to decrypt.


For a user, the registration in TokenD is not much different from that on any regular website, social media (e.g., Facebook), online shopping services (e.g., Amazon), etc.

User flow

  1. Enter an email and password
  2. Confirm the registration via their email
  3. Receive the recovery seed and save it in a safe place (the recovery seed will be needed to restore the keys in case a user has forgotten or lost their password).

Under the hood

While a user is only asked to perform simple and common actions, the under-the-hood of registration is entirely different. In simple terms, the user password is used to encrypt the user’s wallet before sending it to the server as well as to derive data by which a user will later authenticate to later obtain their encrypted wallet.

Since the function used for derivation is one-way, neither the server nor the man-in-the-middle can use authentication data to restore the user password.


As in the case of registration, the user authorization flow is the same as in any regular system: enter an email and password. However, as has already been mentioned, user passwords never touch the servers neither during the authorization nor ever else.

To make this happen, the under-the-hood of authorization is entirely different from traditional systems.


Firstly, a user sends their email address to the server, which, in turn, verifies the presence of such an address in its database. If such exists, the identification process can be considered finished.

After identification, a user should prove their authenticity. For this, he/she enters their password into a device (locally), after which an authentication data is derived and then sent to the server. The server, in turn, verifies the received data, and if it matches, the authentication process can be considered finished (for higher security, an additional confirmation via email can be used).

Receiving an encrypted wallet

After the successful authentication, the server sends an encrypted wallet to a user, who then decrypts it using their encryption key (generated through entering the password, locally in the device) and gains access to their keys. Authorization is finished, and a user is ready to use their keys for signing further operations that they would like to perform in the system.

Note: if an attacker manages to obtain the user’s authentication data (for example, an attacker has bribed an admin of the system who has access to the database), this knowledge wouldn’t present any value because all that an attacker would receive is just an encrypted wallet, which only the user knows how to decrypt.

Password Change/Recovery

The user password is the most crucial data which is needed to derive (generate) an encryption key. Losing or forgetting a password leaves the user without access to their keys. In such a case, there is a password change procedure.

User flow

Since the server never knows the user’s password, the password recovery procedure is radically different from traditional systems, yet possible. A user needs to enter the recovery seed (which had been previously shown to him/her during the registration) and a new password. The password will be recovered and new seed created (do not forget to save the new seed!).

Note: recovery seed is your cornerstone; if the password and recovery seed are lost, then the access to an account (as well as to all funds associated with this account) will be lost as well. No one except the user knows this seed, and it is shown ONLY ONCE, during the registration.

Under the hood

After a user has entered the seed into their application, a new wallet for him/her is created. This means that:

  • Old keys are deleted (with their weight and permissions)
  • New key is generated (i.e., wallet creation)
  • Permissions and weight are set for the new key
  • Newly created wallet is encrypted using the new user password


Know Your Customer (KYC)

The Know Your Customer (KYC) solution needed for a specific case varies greatly on a number of factors such as the business requirements, budget, field of implementation, etc.

For this reason, instead of providing a ready-made, out-of-the-box solution, TokenD offers a toolkit for configuring your own as well as for integrating with third-party verification services.

Build your own KYC solution

As has been mentioned, TokenD doesn’t limit you in the number and type of user access levels as well as what data should be provided and for what access level. The KYC flow is fully customizable. You configure:

  • Data a user should provide (e.g., name, home address, health insurance, etc.)
  • How it is being checked (this can depend on the data provided: by an admin of the platform; by multiple admins; by an admin + third-party verification service; etc.)
  • What is the access level a user will be upgraded to (different access levels vary according to permissions presumed in them; on each operation, there is separate permission—thus the number of access levels can be immense)

Note: the user access level can also be dropped at any time; to do this, an admin must be granted with a corresponding right.

Integrate with third-party verification services

An outsourcing solution is beneficial when you need to delegate the hardships of verifying the user KYC data.

For example, companies that build online trading platforms in the USA are strictly obliged to limit the investment choices of unaccredited investors. In such a case, the identification of whether an individual is accredited or not can be outsourced to corresponding services (e.g., IdentityMind)

Note: the development of external integration module and user access levels configuration takes approximately two weeks.

Multilevel identification

It is possible to define how specifically a user will be verified depending on the data provided, and thus implement multilevel, several-step identification. This is most beneficial in terms of various regulatory requirements.

For example. All users are verified manually by the platform admins, except for those from the USA, who need to prove they are accredited. In such a case, you can configure that if a user has filled the country box as “USA”, he/she will be automatically redirected (via API) to an outsourcing service that will proceed with identification.

Out-of-the-box solutions

United States accreditation

TokenD team has already implemented some basic KYC flows. It is possible for user to be verified as a General, U.S. verified and U.S. accredited investor. Web application will authomatically define the verification flow depending on user's country and requested role will be visible for application reviewer. Thus, US residents, that are not able to prove their accreditation status won't have the ability to hold and invest to security assets.

Automatic verification

TokenD provides an open-source reference implemenation of automatic verification service, that is integrated with IdentityMind sandbox environment. When connected to the real Identity Mind environment, such service will automatically handle most KYC applications without any need of involving human resources.

The implementation of the service is available on Gitlab


TokenD limits management is not only about enabling/disabling particular actions for particular users. Rather, it allows admins to define limit ranges within which users perform activity on the platform.

Limits can be imposed on:

  • Accounts
  • Assets
  • Time bounds (daily, weekly, monthly limits).


Operation limits can be imposed on a type of account (e.g., unverified; verified; all users under 21 years old; all users without insurance documents; etc.) or a specific account.


Operation limits can be imposed on a particular asset type (e.g., to avoid speculation, one account cannot buy more than 5 tickets on one concert/show/etc.).

Time bounds

Operation limits can be imposed on specific time bounds (e.g., users from other than gold miner countries will not be able to buy more than 100g per day).


In TokenD, any account with corresponding permission can issue their tokens. Since there are two basic types of accounts (user and admin) tokens can also be nominally split into two types:

  • Admin-issued tokens
  • User-issued tokens

The only distinction between these two lies in the access level: users requests on token creation, pre-issuance, etc. are to be approved by admins. While an admin, if has the corresponding permission, manages a token throughout its lifecycle directly.

Token Lifecycle

Token lifecycle consists of following steps:

  • Creation
  • Pre-issuance
  • Issuance
  • Transfer
  • Trade
  • Redemption


At this stage, a token cannot be traded or transferred because it doesn’t actually exist. This is simply an announcement of token details: name, max issuance amount, permissions required to interact with this token.


After the pre-issuance stage, actual tokens already exist, but no one yet owns them—they are all locked up on a smart contract. Pre-issuance is either done automatically or manually.

Automatic pre-issuance means that a certain number of tokens, which were specified during the token creation, will be pre-issued immediately after one of the admins approves the token creation request.

Manual pre-issuance means that a user creates a pre-issuance file via an offline application, uploads it on the platform and waits for an admin approval (more detail in offline application).

Offline application is an instrument which allows increasing the level of security during the token pre-issuance as well as provides for the diversification of risks.

In a direct sense, an offline application is a separate software you download to your device to perform operations related to the token pre-issuance. It is available for both users and admins.

Using an offline application, token pre-issuance can be split into two stages both performed by different parties: one uses an offline application to generate the pre-issuance file and sign it with their keys, another uploads this file to the platform so that actual tokens are pre-issued. In this way, the risk of unauthorized token issuance on the platform is diversified due to the correct allocation of duties.

Offline application includes the following functionality:

  • Pre-issue tokens
  • Change asset issuer
  • Generate a new key pair

Pre-issue tokens. This process means that a user/admin creates a pre-issuance file, where they specify the pre-issuance details (which token, how much to pre-issue). This file contains a transaction for pre-issuance, which, before being sent, has to be signed by the creator of the file and also by another party that uploads this file to the platform (these actually could be one person, but to increase the security and diversify the risks, it is recommended to allocate the pre-issuance process into two stages).

Change asset issuer. One example when this might be needed is when one of the parties responsible for pre-issuance had been fired from your organization, and you have to make sure that their key can no longer be used for signing the transaction for pre-issuance.

Generate a new key pair. For higher security, it is assumed that the keys that will be later used for the tokens pre-issuance are generated in an offline application. This is done to have higher confidence that they haven’t been exposed by hackers during the generation.

Offline issuance application, which allows you to securely create new preissuanceAssetSigner and pre authorize tokens to be issued, is available here:


At this stage, tokens are put into circulation. This process can be performed either by direct issuance (manually or through PSIM) or through crowdinvesting.

Direct issuance presumes the manual transfer of tokens to user balances.

Crowdinvesting campaign can be created by any user with corresponding permission and should be approved by an admin (only the token creator is able to put their token up for sale on a campaign; for more details, see crowdinvesting campaigns).

Guide on integration with external fiat system is available here.


Unlike traditional order execution model—where users send requests to the main server to transfer funds—TokenD supports direct transfers between users. In particular, all transactions are initiated by the users themselves, through cryptographic keys.

Note: for a token to be transferred, both the sender and receiver need to have corresponding permissions. Otherwise, the system will return error, and the transaction won’t be submitted.

The FBA consensus implemented in TokenD allows achieving full finality of transactions. This means that a transaction is irreversible: once it has taken place on a blockchain (i.e., was accepted by validators), it cannot later be canceled.


TokenD supports an internal exchange module that allows users to exchange tokens issued on the platform without the need for integrating with external exchange services.

Note: which of assets can be traded on the exchange is defined by the platform admins. For this, an admin should create an asset pair and specify it as tradable.


Token redemption is the process of taking the corresponding amount of tokens out of circulation. One example of token redemption is during the withdraw process. Guide for withdrawal process in TokenD system integrated with Bank is available here

Crowdinvesting Campaigns

TokenD comes with a crowdinvesting marketplace solution that is implemented through smart contracts, which are performed directly on a blockchain. This allows for the following benefits:

  • Investors money are locked up by a smart contract, meaning that the sale creator is technically incapable of stealing investors’ money.
  • Investors can re-invest their funds into another sale or simply cancel their investment in real time.
  • In case a sale didn’t reach its softcap, the campaign is considered failed, and all funds are automatically returned to all the investors.
  • In case a sale is successful (softcap and end time or hardcap reached), the required number of tokens which have been put up for sale are distributed among all investors automatically.

Requirements for users to start their own campaign

To start their own crowdinvesting campaign, a user should:

  • have appropriate permission
  • create and pre-issue a token that will be put up for sale
  • create a crowdinvesting campaign request
  • have this request approved by an admin with the corresponding right


TokenD is provided with a flexible and feature-rich set of tools for fees management, which allows creating custom fees imposition rules by choosing and combining the following parameters and modes:

  • Account (type of account, any specific account, group of accounts, or all);
  • Asset (this is related to any asset on the platform, whether it is issued by an admin or user);
  • Operation type (withdrawal, invest, issuance, payment (outgoing, incoming), and order match).

Also, it is possible to choose whether a fee is flat or percentage and define the range in which the imposition of particular fee-charging scenarios takes place. For example, you can specify that USD withdrawals in the range between $0 and $100 are imposed with a flat fee of $0.5, and above $100, a percentage fee of 2% is imposed.


TokenD doesn’t presume a complete suite of admins with standard rights, but it rather gives you a toolset for realizing your own platform management policy. It is possible to customize:

  • Number of admins on the platform
  • Set of permissions available for each admin
  • Weight each admin has when providing the permissioned operation (multisignature)

Delegation of responsibilities

Most decentralized blockchain systems do not support the allocation of duties—users are mostly equal in their rights. This doesn’t work in the business sector, where you must have competent people each with their own tasks and responsibilities.

Being not just a system supporting accounts of different access levels, TokenD allows setting up your own hierarchy of permissions which is strictly controlled via cryptographic keys.

Each admin is given a key that allows performing only a strict set of operations which you entirely select (e.g., approve/reject KYC requests of users from Europe + impose fees;)

Diversification of risks

TokenD supports account weights. To perform an operation, an initiator should have both required permission and enough weight.

Moreover, an operation can also be initiated and fulfilled by multiple admins whose total weight matches the operation threshold. This mechanism allows distributing the authority over processes among a specific number of parties.

Therefore, you can diversify risks related to individual admin’s censorship by distributing responsibility among others and thus increase the objectiveness of decisions taken in the system.

Admin registration

The process of admin registration, unlike the user registration, is rather more earnest and implies greater responsibility. In particular, a party will be asked to go through the sign-up flow and thus get an account ID.

Using an external communication channel, a party should send their account ID to an existing admin (with the corresponding permission) who will subsequently add a new admin account.


Guides will mostly cover the logic of submitting transactions, so here are a few statements about transactions you may want to know before starting to work with TokenD SDK and TokenD API:

  • Transaction MAY contain one or more operations
  • Transaction MUST have a source - the ID of the existing account in the TokenD system
  • Transaction MUST be signed with any valid ed25519 keypair
  • Preventing transactions from one network to be sent to another is achieved via "Network Passphrase" that should be unique for every TokenD Network and is being set during deployment

Javascript SDK exposes the ApiCaller and Wallet classes that will simplify the process of crafting/signing the transactions.

Let's assume our user has the TokenD account with ID - GD2XNPQCN6A6IRWJDADOVAL4YMDPYB6VTQRIXW7MVQAHCNBMO46KBCIC and one of it's signers has the secret seed - SBW7DY3ZEYGGWQJG7JOPYXDIQFZYAC4DKIO75VINZXPIWWIQIJDCDCMZ. It's important to know that the seed of the signer and the account ID MAY NOT correspond to one key pair - the list of account signers can be changed, while any account ID is permanent.

To submit the transaction to the TokenD network, we should create an ApiCaller instance and provide it a Wallet instance that we want to be used for signing transactions.

  import { Wallet, ApiCaller } from '@tokend/js-sdk'

  const wallet = new Wallet(
    "", // email param, usually be ommited here
  const api = ApiCaller.getInstance('')
  api.usePassphrase("Our network passphrase")

Now api will automatically sign any transaction and set it's source from the Wallet we've provided.

  await api.postOperations(op1, op2, op3)

Add custom email notifications

TokenD already has necessary notifications for email verification and 2FA. But you are free to add any new notifications for any system event.

To set custom notifications, you need:

1. Deploy notification sender

Set following section in your_project.env.yaml file.

  image: tokend/notification-sender-svc:0.1.0
  signer: S... 
  defaultchannel: 'email' # 'device' | 'email'
    local: true # will create postgres container in cluster
    # local: false # will use provided postgres_connection_url
    # url: postgres_connection_url
    migrationscount: 1 # Do not change this, please
    key: "key-..." # your private mailgun key
    publickey: "pubkey-..." # your public validation mailgun key
    domain: ""
    fromname: AwesomeProject
    url: "" # URL to your bucket (mind region)
    bucket: awesome-bucket # Your bucket name
    accesskey: ""
    secretkey: ""
    region: ""
    usestaticcredentials: true # Do not change this, please
    projectid: ''
    serviceaccountid: ''
    # Please, insert here whole content of your firebase access json file
    accessfile: '' 
    androidpackagename: ''
    disabled: true # Will not use sentry
    # disabled: false
    # dsn: ...
    - name: withdraw-success  # will be used to identify template
      subject: Your withdrawal request has been processed
      # file with exactly this name must be in your s3 bucket
      email: withdraw-success.html  # will be used to send in email body
      push: withdraw-success.json  # will be used to send push notifications

Then generate your_project.k8s.yaml file using tokend-cli:

tokend-cli gen k8s -f your_project.env.yaml -o your_project.k8s.yaml

Upload templates themselves to s3 bucket (their file names must be the same as in config).

Now you are ready to deploy to your aws kubernetes cluster. Run kubectl apply -f your_project.k8s.yaml and you are ready to go!

2. Create your custom notification templates

You can use any HTML code. If you want to set some values dynamically, you need to set placeholders for them in your template:

{{ .Name }}

3. Upload templates to Amazon s3 bucket

You are free to choose the way you prefer to upload your templates, named as in the config, to the root of the bucket, you set in the config.

4. Create a service that will listen for system events

To listen any system change you can use transactions endpoint

After getting needed update, you can use notification service API to send notification.

Integration with Coinpayments

With Coinpayments you can enable deposit and withdraw of cryptocurrencies for your TokenD system.

Set up your Coinpayments account

  1. Create an account and complete KYC verification
  2. Create an API key:
    • Go to "Account" menu and select "API keys"
    • Create a key by clicking on "Generate new key" button
    • Once the key is created click "Edit permissions" button and check all actions
  3. Go to "Coin Settings" and select coins you want to process in TokenD

Configure Coinpayments integration service

  1. In coinpayments configuration section you must fill public_key and private_key attributes with the corresponding values of your Coinpayments API key created before
  2. For each service – deposit, deposit-verify and withdraw, – you must specify signer as a secret seed of your TokenD master account and source as it's account ID

In Developer edition files to edit are configs/coinpayments-deposit-verify.yaml, configs/coinpayments-deposit.yaml and configs/coinpayments-withdraw.yaml

Set up assets in TokenD

Every coin must be represented as an asset in your system. Follow this guide to create one:

  1. Sign in to admin panel
  2. Pick "Assets" section and click "Create asset" button
  3. Fill in the form:
    • "Asset code" – must be a cryptocurrency code as it is displayed in Coinpayments, can't be changed later
    • "Maximum assets" – must be 9223372036853 (maximum possible amount)
    • "Initial preissued amount" – must be 9223372036853 (maximum possible amount)
    • "Withdrawable" – must be checked to enable withdraw, can be changed later
    • "Use Coinpayments" in "Advanced" section – must be checked
    • "External system type" in "Advanced" section - must be 0
  4. Click "Create asset" button below the form and confirm your action

How to deposit

  1. In client app go to "Movements" and select required balance
    • If there is no balance in the required asset you can create it in "Assets" section
  2. Click "Deposit" button
  3. Enter amount of deposit and click "Request the address"
  4. Send crypto to given address. Once funds are received and confirmed the amoun will be available in your balance in TokenD as well as in Coinpayments

How to withdraw

  1. In client app go to "Movements" and select required balance
  2. Click "Withdraw" button
  3. Fill in amount and address and confirm the action

Create Account

First of all, we need the accountID to identify the account:

  import { base } from '@tokend/js-sdk'

  const keypair = base.Keypair.random()
  const accountId = keypair.accountId()

Then we need to add the signer to our account. For simplicity, we'll use the keypair we've created as a first signer of the account.

  const signerPublicKey = accountId

Hovewer, any keypair can be used, and even more, every account can have multiple signers.

After generating the account ID and the keypair of account's first signer, we can create the operation that can be submitted to the TokenD system:

  const operation = base.CreateAccountBuilder.createAccount({
    destination: accountId,
    signersData: {
      publicKey: signerPublicKey,
      weight: 1000,
      identity: 1,
      details: {}

  // The detailed description of fields is provided via js-doc in the sources.

  await api.postOperations(operation)

Fiat Deposit

Fiat deposit/withdrawals is one of the most important functionalities an asset management system should provide for. In this document, we will review how it works in TokenD.

In this guide, we consider an example of integrating with SafeCharge. However, this knowledge can be further used to integrate with any other similar systems and platforms.

As in any other system, in order to integrate TokenD with external payment systems (e.g., banks, payment gateways, other blockchains, etc.), a "bridge" module needs to be developed. Further in the text, we will appeal to it as PSIM (Payment Services Integration Module).


Requirements for the Deposit flow:

  1. Issuer of the token that represents an external asset must have account in the external system. This account will be used to store collateral of the issued tokens. Issuer is able to decide what ratio to maintain between collateral and tokens. In this example, we will stick to the 1:1 ratio.
  2. Corresponding token in TokenD must be created. A sufficient amount of tokens should be preissued and a valid preissuanceAssetSigner should be controlled by a trusted party (token issuer). In this example, USDT is an asset issued in TokenD, and USD is a collateral for this token.
  3. Admin (or signer of account) must be created, that is able to request issuance of the USDT.


In the deposit flow, the role of PSIM is to monitor the state of an account in the external system as well as to perform the issuance of the corresponding amount of tokens to the corresponding user once a new incoming transfer takes place. Deposit Flow

  1. User is willing to perform the deposit into the TokenD via web or mobile application. It is possible to mark assets created in TokenD as depositable using the details of an asset (details could be any JSON object, so you can pass any additional data if needed). To start the deposit flow, a user sends a request to PSIM.
    1. PSIM sends a request to the payment system (in our case, SafeCharge). Payment system (further referred to as "PS" or "SafeCharge") generates a unique session ID for the deposit and returns it back to PSIM. PSIM returns it back to the User.
  2. Using their application, a user sends a request where they specify card details to SafeCharge and receives their unique identifier.
  3. User passes a unique identifier of the card, amount to deposit and additional details to PSIM.
    1. PSIM creates a request for the issuance to the TokenD Core. This request contains the amount to be issued, account on which issuance should be performed as well as all the required tasks that have to be processed to have the issuance performed.
    2. TokenD Core returns a unique identifier of the request.
    3. PSIM passes all the data to PS. PS performs the transfer of funds from the user’s credit card to the account of the issuer in PS.
    4. PSIM approves the issuance request of the corresponding amount of tokens to a user. For big amounts, it is recommended to request manual verification by an admin. To do this, PSIM needs to remove tasks that it is supposed to process and add a new one for an admin (tasks to be processed are defined by the developers depending on their needs). After the confirmation that the transfer is legitimate, an admin removes these tasks and tokens are issued to the user account
    5. User receives confirmation that the deposit is successful.

Fiat Withdrawal

Withdrawal is the process of exchanging tokens issued in one system to the collateral controlled by another system. To be able to create the Withdrawal Request, a user must have a corresponding permission, and an asset must have AssetPolicy::WITHDRAWABLE enabled. For more details, check Create Withdrawal Request Operation. In order to integrate TokenD with external payment systems (e.g., banks, payment gateways, other blockchains, etc.), a "bridge" module needs to be developed. Further in the text, we will appeal to it as PSIM (Payment Services Integration Module). Integration with payment systems that provides end-to-end IDs is trivial (integration module is able to specify a unique identifier of the transfer; if another transfer is sent with the same identifier, the request will be rejected). In this guide, we propose a solution for payment systems that does not provide such mechanics.

Fiat Withdrawal

  1. User creates a withdrawal request specifying a token, amount, and destination details (e.g., bank account).
    1.1 TokenD Core verifies that a user has corresponding permission, that an asset is withdrawable as well as that a user has a sufficient balance. TokenD Core locks the corresponding amount of tokens and creates a pending withdrawal request with default tasks.
  2. PSIM gets all pending requests, where pending tasks are equal to 2 or 4.

    [Pending task = 2]
  3. To mark that it has started the processing withdrawal request, PSIM approves the request and removes task 2 and adds 4.
    3.1 PSIM sends a request to the Bank to transfer the corresponding amount of fiat to the bank account specified by a user in details of the withdrawal request

    [Transfer succeeded]
    3.2. PSIM removes task 4.
    3.3 Core removes the request and redeems all the withdrawn tokens. (Flow is finished succesfully)

    [Transfer failed due to invalid destination]
    3.2 PSIM markes the request as permanently rejected and specifies the reason.
    3.3 TokenD Core unlocks the corresponding amount of tokens and removes the request. A user can see the reject reason in the history and is able to create the new one. (flow is finished)

    [Transfer failed due to unknown reason]
    3.2 PSIM removes task 4, adds 1, and adds the reason. Admin is able to see the reason why the transfer was failed and resolve it manually. (Flow finished)

    [Pending task = 4]
  4. Request is in an unknown state. PSIM has crashed before or after the transfer has been sent to the bank. In such a case, it requests help from the admin removing task 4 and adding task 1. (Flow finished)

Issue Asset

The asset issuance is performed to the specific balance, not the account. So, if we need to issue 5 example assets (EXT) to the account with ID GBGEKARFDSXC6XJHTFPTKLONELARRWIHEVDR2TPBIPUAMFZCV5JLVBAA, we need to know the EXT balance ID from this account:

  const { data: account } = await api.get('/v3/accounts', {
    include: ['balances', 'balances.state'],
  const extBalanceId = account.balances.find(b => b.asset.code === 'EXT')

If such balance doesn't exist, we can create one with the help of ManageBalance operation:

  const operation = base.operation.ManageBalance({
    action: base.xdr.ManageBalanceAction.createUnique()
    asset: 'EXT',

  await api.postOperations(operation)

Now we have the balance exists and can issue EXT asset.

The issuance itself is performed in 2 steps - requesting the issuance and approving the request

To create the issuance request, use the CreateIssuanceBuilder exposed by SDK:

  const operation = base.CreateIssuanceRequestBuilder.createIssuanceRequest({
    asset: 'EXT',
    amount: '100.000000',
    reference: 'Some unique random string',
    creatorDetails: {
      foo: 'bar'

  await api.postOperations(operation)

Before doing so, we can manage the key/value storage to define the tasks should be set, once request is created.

  const key = 'issuance_tasks:EXT' // or 'issuance_tasks:*' to spread the rule for every asset
  const operation = base.ManageKeyValueBuilder.putKeyValue({
    value: 8,

Setting the value to 8 means that the request will be created with 8 pending tasks. 8 is a bitmask and every approving review can remove any amount of bits. Once there is no pending tasks for the request, it becomes approved. We can also make all the requests become automatically approved by setting the value to 0.

To review the issuance request, use the ReviewRequestBuilder exposed by SDK:

  const requestId = 10
  const { data: request } = await api.getWithSignature(`/v3/requests/${requestId}`)

  const operation = base.ReviewRequestBuilder.reviewRequest({
    requestID: requestId,
    requestHash: request.hash,
    requestType: request.xdrType.value,
    action: xdr.ReviewRequestOpAction.approve().value
    reason: '',
    reviewDetails: {
      tasksToAdd: 0,
      tasksToRemove: 8, // depends on our configuration

  await api.postOperations(operation)

Integration with RegTech Solutions

The Know Your Customer (KYC) solution needed for a specific case varies greatly on a number of factors such as the business requirements, budget, field of implementation, etc.

For this reason, instead of providing a ready-made solution, TokenD offers a toolkit. This toolkit allows configuring your own identification solution as well as integrating with third-party services in case you need to delegate the process and only receive data based on which to configure custom user permissions.

TokenD presumes a separate module which is responsible for storing the KYC (know your customer) data, and it is called Identity Storage. Who has permission to operate with Identity Storage is specified via keys given to the system admins—-to prove their permission, an admin provides the corresponding signature.

In order to integrate TokenD with external RegTech compliance solutions (e.g., IdentityMind, IDnow, etc.), a "bridge" module needs to be developed. Further in the text, we will appeal to it as ESIM (External System Integration Module).


To upgrade their account (i.e., change its type to the one with higher access level), a user has to pass the KYC procedure.

TokenD doesn’t limit you in the number and type of user access levels as well as in what data should be provided and for which access level; it is all customizable.

The flow of how a client upgrades their account to a higher type is as follows: KYC Flow

  1. Client sends the required KYC data to Identity Storage.
  2. Client sends the request to the platform to change their account type (this request has the KYC data hash value attached which acts as an identifier in Identity Storage).
  3. A number of pending tasks appear on the platform; fulfilling them is required to have the user KYC request performed. Which tasks appear depends on how a particular case is customized. For example, depending on the information provided, different tasks may appear. If a user is from Europe, then there could be one one task: need for approval by the platform admin. And if a user is from the USA, then there could be two tasks: approval by the platform admin + additional approval by the external service (in this flow, we consider this particular example).
  4. Next, admin reviews the request:
    • If an admin rejects the request (e.g., a user hasn’t provided the required data), then a user will have to start the procedure again starting from the first step.
    • If an admin approves the request, then one of the tasks required to perform the user request is marked is complete.
  5. ESIM monitors the platform for requests which contain an admin’s approval and a pending task for external service approval.
  6. If such a request exists, ESIM requests Identity Storage for the KYC data provided by the corresponding user.
  7. After receiving this data, ESIM sends a request to the exterior KYC service.
  8. Service processes the request.
    • Service confirms the request
      1. Service sends a message to ESIM that the request has been accepted
      2. ESIM confirms the request on upgrading the user’s account type (i.e., marks the second pending task as complete)
      3. User account type is changed
    • Service rejects the request
      1. Service sends a message to ESIM that the request has been rejected
      2. ESIM sends a message to the platform that the request has been canceled.
      3. User account type is not changed, but a user can start the identification processes from step 1.

KYC recovery

KYC recovery allows recovering access to the user account even if they lost all keys. KYC recovery consists of two main steps.

Initiate KYC recovery

The client fills out the registration form. The system sends an email with a verification code. After successful email verification, the system saves encrypted keys and sends InitiateKycRecoveryOperation. Initiate KYC recovery operation drops all existing user keys and adds a new key with a specific signer role. This role doesn't allow the user to access any data or send any ordinary transactions until the user proceeds with the second step.

Finish KYC recovery

A user sends a create KYC recovery request operation and provides his KYC data. Admin reviews this request and accepts it. After accepting the request, user signer role changes to default so they will be able to perform all actions allowed to their role.

Ledger Entry Changes

Sending each operation can make one or more changes in current system state. Them are called LedgerEntryChanges.

LedgerEntryChange contains information about:

  • changed LedgerEntry type

  • change type

  • payload that describes change

Possible change types:

  • created

  • updated

  • removed

  • state - LedgerEntry was used in operation, but no changes was added

You are able to get transactions and related ledger changes using transactions list endpoint

Manage Poll

This is an experimental API. Experimental APIs may be changed or removed without notice.

Before creating the poll entry, you may want to configure the system to define what type of voters can participate in the poll. For doing so, you can map the permissionType of the poll with one or many account rules.

To create poll request, use the ManageCreatePollRequestBuilder exposed by SDK:

Create poll request:


  const operation = base.ManageCreatePollRequestBuilder.createPollRequest({
    permissionType: SAMPLE_PERMISSION_TYPE,