Wallet Operations


Contents




Introduction


Once you create a user, a wallet is automatically created and associated to their user's ID. Throughout these docs you will learn all the actions you can do with the wallets of the users.




Operations


Get wallet info


You can get the information of a wallet by using the id of the wallet or by using the id of the user that owns it. You can do so by using the following requests:


HTTP Request


GET /api/v1/public/wallets/{walletId} where the parameter id stands for the id of the wallet.

GET /api/v1/public/wallets?userId="XXX" where the parameter userId is the user's ID from which you want to get the associated wallet info. This request will return all the wallets info that the user owns in the system. In our example, using the user ID, the whole request would look like this: /api/v1/public/wallets?userId=91af1cb8-1caa-47d0-8ef8-2c11948baaba.


HTTP Response


As response, you will get all the information of that wallet. If the user had more than one wallet, they would all appear. In our example it would look like this:


{
   "_embedded": {
       "wallets": [
           {
               "id": "cd496094-a77a-4e4e-bcd9-3361ff89294a",
               "availableBalance": 1002.32,
               "balance": 1002.32,
               "clientAlias": "alias_test",
               "clientId": "f34ed6d7-6703-4486-b591-23ee8f20d8b4",
               "dltAddress": "0x95066cdf6a5ac9489eeb28755f0e878eb3de711d",
               "iban": "ES7002320521100021450612",
               "status": "READY",
               "userId": "91af1cb8-1caa-47d0-8ef8-2c11948baaba"
           }
      ]
}


Where:


HTTP Response parameters


Parameter Datatype Description
id string UUID of the wallet
availableBalance numeric Balance with which the user can operate
balance numeric Total balance of the wallet without taking into account pending operations
clientAlias string Name of the client as it is saved in the system
clientId string The UUID of the client which was used to create the user
dltAddress string DLT address associated to the wallet
iban string IBAN number associated to the wallet
status string The status can be either READY or PENDING
userId string The UUID of the user introduced and that owns the wallet

Note that the status of the wallet in the JSON example is READY and therefore it can be used for any payment or funding operation.





Get wallets list


If you want to get the list of all the wallets that exist in your system make the following request:


HTTP Request


GET /api/v1/public/wallets

As a response, you will get a JSON array with the information of all the wallets in your system.

If you want to try any of these two functionalities yourself, please go to the API catalogue.




Create an extra wallet


If your use case needs it, you can create extra wallets for your users. Note, that to be able to create an extra wallet for a user, this one has to be in status ACTIVATED i.e. it already has a first operative wallet. For creating an extra wallet, you have to make the following request:


HTTP Request

POST /api/v1/public/wallets


With the following information provided as JSON:


{
    "dltAddress": "0x485De9F4580eDEDB5b16a84028e4Bac64434c36D",
    "userId": "a5fec227-17cf-4be8-b2aa-b514e38e2b29",

Request body parameters


Parameter Mandatory Datatype Description
dltAddress yes string The Ethereum address of the new wallet.
The client can either use an already existing address, if the user provides it, or create a new one.
userId yes string The UUID of the user that is creating the new wallet

As response, you will get the following JSON object:


{
   "dltAddress": "0x485De9F4580eDEDB5b16a84028e4Bac64434c36D"
   "dltNetwork": "Alastria Telsius",
   "status": "PENDING_IBAN",
   "userId": "91af1cb8-1caa-47d0-8ef8-2c11948baaba",
   "walletId": "c86db278-6eb4-4af2-b023-753eba091d1c",
}

Where:

HTTP Response parameters


Parameter Datatype Description
dltAddress string The value which was provided in the request
dltNetwork string Default network of the client where the wallet is created and in which it will be operating.
status string The status can be either PENDING_IBAN or READY.
userId string The value which was provided in the request
walletId string The UUID generated for the created wallet


Get movement info


If you want to access to the information of a movement of a specific wallet you have to send the following request:


HTTP Request


GET /api/v1/public/wallets/{walletId}/movements/{movementId} where the parameter walletId in our example would be: cd496094-a77a-4e4e-bcd9-3361ff89294a and the movementID can be for example a5fec227-17cf-4be8-b2aa-b514e38e2b29. Therefore, the whole request would look like this: /api/v1/public/wallets/cd496094-a77a-4e4e-bcd9-3361ff89294a/movements/a5fec227-17cf-4be8-b2aa-b514e38e2b29.


HTTP Response


As response, you will get a JSON with all the information of that movement. Below, it is shown a movement of a transfer-in in which the wallet requested made a transaction to another wallet with an amount of 10.


{
   "id": "a5fec227-17cf-4be8-b2aa-b514e38e2b29",
   "accountOrigin": "cd496094-a77a-4e4e-bcd9-3361ff89294a",
   "accountTarget": "2c36f452-2ea4-4448-962b-365cdb5ae027",
   "amount": 10,
   "concept": "cash-in from my credit card",
   "createdAt": "2018-11-28T10:21:20.198+0000",
   "dltAddressOrigin": "0x95066cdf6a5ac9489eeb28755f0e878eb3de711d",
   "dltAddressTarget": "0xd6341daf46ecb065b00c0baebc098ae06ed01c90",
   "iban": null,
   "status": "SUCCESS",
   "type": "TRANSFER_IN",
   "updatedAt": "2018-11-28T10:21:21.966+0000"
}


Where:


HTTP Response parameters


Parameter Datatype Description
id string UUID of the movement
accountOrigin string ID of the sender's wallet if the movement type is TRANSFER_IN or TRANSFER_OUT. Owner's name of the external bank account from where the money is being sent if the movement type is BANK_ACCOUNT_CASHIN. Empty if the movement type is any other
accountTarget string ID of the receiver's wallet if the movement type is TRANSFER_IN or TRANSFER_OUT. Owner's name of the external bank account to which the money is being transferred if the movement type is BANK_ACCOUNT_CASHOUT. Empty if the movement type is any other
amount numeric Amount of money moved
concept string Description with the purpose of the movement
createdAt string Timestamp of the movement creation
dltAddressOrigin string DLT address associated to the sender's wallet if the movement type is TRANSFER_IN or TRANSFER_OUT. Empty if the movement type is any other
dltAddressTarget string DLT address associated to the receiver's wallet if the movement type is TRANSFER_IN or TRANSFER_OUT. Empty if the movement type is any other
iban string IBAN number of the external bank account that participates in the transaction if the movement type is BANK_ACCOUNT_CASHIN or BANK_ACCOUNT_CASHOUT. It appears empty in any other movement type.
status string The status can be either SUCCESS, PENDING or ERROR
type string The type of movement can be either CARD_CASHIN, BANK_ACCOUNT_CASHIN, BANK_ACCOUNT_CASHOUT, TRANSFER_IN or TRANSFER_OUT
updatedAt string Timestamp of the movement update

It is important to know that when a transfer is made between two accounts, there are two movements generated: one when the money leaves the origin account TRANSFER_IN and another when it reaches the target accountTRANSFER_OUT. In addition, when the movement consulted is a cash-in or a cash-out, the fields accountTarget or accountOrigin respectively should appear empty.




Get movements list


If you want to get the list of all the movements of a specific wallet make the following request:


HTTP Request


GET /api/v1/public/wallets/{walletId}/movements

As a response, you will get a JSON array with the information of all the movements of that wallet.

If you want to try any of these two functionalities yourself and know more about them, please go to the API catalogue.




Card Cash-in


In order to fund the user’s wallet you can make a credit or debit card top up with the API. Card data should be encrypted prior to performing cash-in operations using symmetric-key encryption algorithm AES 256 ECB. Our API provides a temporal encryption key to encrypt the data, to get this key you should make the following request:


HTTP Request


POST /api/v1/public/wallets/temporalpk


HTTP Response


As response, you will get the key as shown below:


{
    "temporalPK": "iOeuSHZgOoO23GKoSMzLhJa+tCzfF1/ZfHL8ByUcDZMfa8QhAKzW1sX/FJj8Ipa5OY6IPVz5tsv3l4IBtAKOaha2y9XsI+0hJ++XacPYeXclHb063iHwxKqN/rQ9S9dV0E9ynvECwxJJv5CPJlVCLuoWoIa7k37BDCSpbwp+HnWiHEe4ni7KtgeXTDo0MEaLjQpeZ+EMqmmzd8EeTVlugfOd258x1P5smJSY6c6u1x3zuBB/Qbs+gguG8wXcaD0WLYCize96ZkML66LZKbe+pP6NQe9mireJi3wNFJT2NXgygJO9dtItlJzLImFAUbluCNdRnkrSQ2HB8us9O/WjEw=="
}

Where:


Parameter Datatype Description
temporalPK string Temporary encryption key encrypted with your public key so that only you can decrypt it

It is recommended to get the temporal private key every time you want to make a cash-in.

To get the AES key for encrypting the data, you should decrypt the temporal key with your RSA asymmetric private key related to the public key you sent us. Here is an example of decrypting the temporal key in Java code:


KeyFactory kf = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode("Base64 encoded private key"));

Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, kf.generatePrivate(keySpec));
return new String(cipher.doFinal(Base64.getDecoder().decode("temporal key")), StandardCharsets.UTF_8);

Once this is done you can use the resulting key to encrypt the user's credit/debit card data using symmetric-key encryption algorithm AES 256 ECB. Fields need to be encoded to Base64 prior to sending them to the API. An example in Java code is shown below:

// Hex is a class from the Apache Commons Codec library
SecretKeySpec secretKeySpec = new SecretKeySpec(Hex.decodeHex("decrypted temporal key"), "AES");

Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
return Base64.getEncoder().encodeToString(cipher.doFinal("card data field to encrypt".getBytes(StandardCharsets.UTF_8)));

Fields that need to be encrypted are: Owner, number, expiration date in MMYY format and CVV.

Now you can perform a top up by making the following request:


HTTP Request


POST /api/v1/public/wallets/{walletId}/cards/cashIns where the walletId is the UUID of the wallet which will receive the money. In our example, the whole request will be /api/v1/public/wallets/cd496094-a77a-4e4e-bcd9-3361ff89294a/cards/cashIns

An example of the JSON with an encrypted credit card data is shown below:


{
     "amount" :  "1000",
     "card": {
         "owner": "sJEdXGTBSdVGrZq7dBrc0Q==",
         "brand": "VISA",
         "number": "44D22AuX5Kpkh3ikBiQKjPLNdu/KRw7/C1OYY9L549A=",
         "expiration": "NHGI+g5uD8tsA+uvqGsqYQ==",
         "cvv": "7SV2eco0RRyiPVgUhVn0Xg=="
     },
     "concept": "cash-in from my credit card"
}

Where:


Request body parameters


Parameter Required Datatype Description
amount yes numeric Amount of money to cash in
card yes object A card object
concept no string Optional description with the purpose of the card cash-in

Card object


Parameter Required Datatype Description
brand yes string Brand of the credit/debit card (unencrypted). Should be VISA or MCAR for Mastercard cards
cvv yes string Encrypted CVV of the credit/debit card
expiration yes string Encrypted expiration date of the credit/debit card in MMYY format
number yes string Encrypted number of the credit/debit card
owner yes string Encrypted full name of the owner of the credit/debit card

If card data is encrypted with an old temporal private key, it is not encrypted properly or data is not correct, API request will response with a Bad Request with the following body:


{
      "errors": [
        {
          "status": 400,
          "detail": "Card data not encrypted."
        }
      ]
}

As a summary, steps needed to make a cash-in operation are the following:

  • Get temporal private key from the API.
  • Decrypt AES temporal private with your RSA private key.
  • Use decrypted temporal AES key to encrypt credit/debit card data using AES 256 ECB
  • Call cash-in API with encrypted card data and amount


Movement generated


This action will generate a movement of type CARD_CASHIN that will turn its status from PENDING to SUCCESS when the operation has been finished.


If you want to try this functionality yourself and learn more about the card cash-in, please go to the API catalogue.




SEPA Cash-in


Another option to fund the user's ioCash wallet is through a SEPA cash-in. With this method, a bank transfer is done from an external bank account to the IBAN associated to the user's ioCash wallet. This implies that you do not need to make any request against the API for the accomplishment of this action. The system will read the change in the IBAN and update the ioCash wallet balance. Since the operation is a bank transfer, it can take some time from the order of the cash-in till it reaches ioCash.


Movement generated


This action will generate a movement of type BANK_ACCOUNT_CASHIN that will turn its status from PENDING to SUCCESS when both the available balance (DLT account balance) and the total balance (system balance) are increased with the quantity cashed in.




Cash-out


In order for a user to send money from his IoCash wallet to another bank account, the following request has to be sent.


HTTP Request


POST /api/v1/public/wallets/{walletId}/cashOuts where the walletId is the UUID of the wallet, which should execute the money cash-out. In our example, the whole request will be /api/v1/public/wallets/cd496094-a77a-4e4e-bcd9-3361ff89294a/cashOuts.


With the following information provided as JSON:


{
    "iban": {
       "accountNumber": "ES7921000813610123456789"
   },
    "amount": "1.50",
    "concept": "Cash out from my account"
}

Where:


Request body parameters


Parameter Required Datatype Description
iban yes object An IBAN object
amount yes string The cash.out amount represented as integer or numeric value
concept no string Optional description with the purpose of the card cash-out

IBAN object


Parameter Required Datatype Description
accountNumber yes string The IBAN of the bank account, which should receive the payment


Movement generated


This action will generate a movement of type BANK_ACCOUNT_CASHOUT that will turn its status from PENDING to SUCCESS when both the available balance (DLT account balance) and the total balance (system balance) are decreased with the quantity cashed out.


If you want to try this functionality yourself and learn more about the cash-out, please go to the API catalogue.





Transfer


In ioCash, transfers are decentralized, which means that the action must be executed directly against the smart contract. You do not have to make any request in the API. Instead, an ERC-20 native transfer transaction needs to be executed. There are two types of transfers:

  • One-step transfers: The transfer is directely executed after KYC limits are checked on-chain. After completion, the available balance of both accounts are updated. Then, the EME license agent will be notified about the transfer and the total balance of both users will be updated.
  • Two-step transfers: The transfer requires of an offchain third-party verification. There is one first transaction in which the user orders the transfer -here the KYC limits are checked and the available balance of the sender is updated- and a second one in which the designated operator accepts or rejects the transfer. After that, the available and total balances of sender and receiver are updated accordingly

Methods on DLT


To make a one-step transfer you have to call the transfer method that resides in our token contract.

To make a two-step transfer you have to call the orderTransfer method that resides in our token contract.

For more details check the Interacting with EmToken docs

You must make this call through the web3 api, and be connected to a network node in order to perform this operation in the DLT.


Movement generated


Both one and two step transfers generate two movements:


  1. Movement of type TRANFER_OUT that will turn its status from PENDING to SUCCESS when the origin user's wallet balance (system balance) is decreased with the transferred quantity .

  2. Movement of type TRANFER_IN that will turn its status from PENDING to SUCCESS when the receiver user's wallet balance (system balance) is increased with the transferred quantity.



Hold


Holds make funds unavailable to users until they are executed. As well as transfers, they are executed directly against the smart contract and thus there is not and API endpoint to call them.

When a hold is declared, the user has to define the amount that will be blocked in his/her account, the target account that will receive the money when the hold is executed and the notary that will decide if the hold execution is accepted (the money is sent to the target account) or rejected (the money is unlocked in the sender's account).


Methods on DLT


To create a hold the user has to call the hold method that resides in our token contract. The hold can also be done on behalf of another user using holdFrom if he/she has beforehand given permission to the orderer using authorizeHoldOperator

To execute a hold the address that was defined as notary should call the executeHold method. The money will be transferred from the sender to the receiver.

To release a hold the notary has to call the releaseHold method. The money will be not sent to the receiver but unlocked into the sender's wallet so that he/she can use it again.

For more information about all the hold methods you can check the Interacting with EmToken docs.


Movement generated


Hold executions generate transfers that create movements TRANFER_OUT and TRANFER_IN as explained above for the transfer operation.