Transactions

Overview

This guide explains how to enable your customers to create Transactions on the Solaris Digital Assets platform.

About Transactions

A Transaction represents a deposit, transfer, or withdrawal of funds to or from an Account.

A Transaction resource will always have the following properties:

Name Type Description
id String Unique ID of the Transaction.
account_id String ID of the Account with which the Transaction is associated.
state String Current state of the transaction. See the table below for a list of possible status values.
amount Integer (Decimal) The transacted amount. Can be positive or negative.
fee_amount Integer (Decimal) The fee charged for the Transaction. This value will always be positive or equal 0.
fee_account_id String ID of the Account from which the fee is collected if a fee applies to the Transaction.
note

Depending on the type of Transaction, the schema may have more fields than the ones listed above. See the API reference for complete information about the schema for each Transaction type.

Transaction types

All Transactions belong to one of three general categories: deposits, transfers, and withdrawals.

Below is a list of possible type values:

Transaction type Definition
DEPOSIT The customer deposited funds to their SDA Account.
TRANSFER_INCOMING The customer received a transfer from another SDA Account.
TRANSFER_OUTGOING The customer transferred funds to another SDA Account.
WITHDRAWAL The customer withdrew funds to an external blockchain address.
WITHDRAWAL_FEE Fee charged by Solaris for withdrawing funds.

Transaction processing workflow

The SDA platform keeps track of a Transaction's progress using the state property. The possible values for the state property are:

  • PENDING
  • APPROVED
  • COMPLETED
  • FAILED
  • CANCELLED

All Transactions have an initial state value of PENDING when created.

After creation, each Transaction must be approved by the Transaction initiator. For transactions initiated by you (i.e., Transfers and Withdrawals), you must collect approval from the corresponding Account holder. In some cases (e.g., if a Deposit is created whenever a blockchain transaction is spotted on the network and approved when the blockchain transaction has been confirmed), the platform automatically approves transactions. Once the initiator approves the Transaction, it will transition to the APPROVED state.

Once a Transaction reaches the APPROVED state, the platform will queue it for processing. Depending on the type of Transaction, it can stay in this state for a significant amount of time, for example:

  • A high volume of Transactions can lead to a delay in their processing.
  • Compliance checks performed by Solaris can also lead to delays.

When Solaris successfully processes the Transaction and updates the Account balance accordingly, then the Transaction will transition to the COMPLETED state. This state is final.

If an error occurs that prevents the successful processing of the Transaction, then it will transition to the FAILED state. Any locked funds will be released, and the Account's available balance will be updated. This state is final.

Transactions can be canceled up until they reach the APPROVED state. If you or the customer cancel a Transaction, then it will transition to the CANCELLED state and any locked funds will be released. This state is final.

note

You may decide how to present the various Transaction states to the end customer. Solaris recommends clearly indicating that Transactions in the PENDING and APPROVED are still being processed, and that only Transactions in the COMPLETED state have been finalized.

Transaction validation checks

Whenever a Transaction is requested by the partner, the platform runs validation checks on the request. These validation checks depend on a number of properties defined on the Asset resource:

Validation check Description
Amount precision The decimal precision of the requested transaction must fall within the range of the corresponding Asset's precision property.
Minimum amount The transacted amount must meet the tx_min_amount value of the corresponding Asset.
Address format The API validates the Address for outgoing transactions according to the Regex string defined in the Asset's address_validation property.

If any of these checks fail, the API will return a 400 - Invalid Request error.

Copy
Copied
{
  "message": "Invalid request",
  "params": {
    "address": "invalid"
  }
}

If other validation checks fail, then the API will create a Transaction and immediately set the state to FAILED. This can happen, for example, when the corresponding Account does not have enough funds for the requested Transaction.

Transaction API endpoints

Use the following endpoints to query information about transactions:

GET List all Transactions for an Account

This endpoint returns an array containing all Transactions associated with the Account specified in the request URL.

Request URL:

GET /v1/entities/{entity_id}/accounts/{account_id}/transactions

Response example:

Copy
Copied
// 200 OK

{
  "items": [
    {
      "id": "bf20c716075ea82a4b1f3f0b49657161atrx",
      "account_id": "9c41ec8a82fb99b57cb5078ae0a8b569acct",
      "type": "DEPOSIT",
      "state": "PENDING",
      "amount": "1.12340000",
      "fee_amount": "0.00000000",
      "fee_account_id": "9c41ec8a82fb99b57cb5078ae0a8b569acct",
      "address": "1F1tAaz5x1HUXrCNLbtMDqcw6o5GNn4xqX",
      "blockchain_txid": "0dfd5b293f62780ef18eb85c6cdbbad408217576ac0e4f610d2f7a145a7f8de2",
      "blockchain_output_n": 1,
      "created_at": "2019-04-02T13:15:47Z",
      "updated_at": "2019-04-02T13:15:47Z"
    },
    {
      "id": "4368fe9ac68c3215b2432a6acffddee8atrx",
      "account_id": "9c41ec8a82fb99b57cb5078ae0a8b569acct",
      "type": "WITHDRAWAL",
      "state": "COMPLETED",
      "amount": "-0.80000000",
      "fee_amount": "0.12340000",
      "fee_account_id": "9c41ec8a82fb99b57cb5078ae0a8b569acct",
      "address": "2N7M3hr2d8BDJUX1ttd8oC2a3gZPr8MGo8C",
      "reference": "unique-a8e530db9b0e3ba8-ref",
      "blockchain_txid": "2950ce725f529c5ea6dcedeeceaea7f42a62eeeb81c7da0bb08eb52e0f96d9d6",
      "blockchain_output_n": 0,
      "linked_tx_ids": [
        "1556f5f4fa23e81e6bbdc313fa1707f5atrx"
      ],
      "created_at": "2019-04-02T13:18:51Z",
      "updated_at": "2019-04-02T13:18:51Z"
    },
    {
      "id": "1556f5f4fa23e81e6bbdc313fa1707f5atrx",
      "account_id": "9c41ec8a82fb99b57cb5078ae0a8b569acct",
      "type": "WITHDRAWAL_FEE",
      "state": "COMPLETED",
      "amount": "0.12340000",
      "fee_amount": "0",
      "fee_account_id": "9c41ec8a82fb99b57cb5078ae0a8b569acct",
      "linked_tx_ids": [
        "4368fe9ac68c3215b2432a6acffddee8atrx"
      ],
      "created_at": "2019-04-02T13:18:51Z",
      "updated_at": "2019-04-02T13:18:51Z"
    },
    {
      "id": "27341700f516438c28632e8d973a6c59atrx",
      "account_id": "9c41ec8a82fb99b57cb5078ae0a8b569acct",
      "type": "TRANSFER_OUTGOING",
      "state": "COMPLETED",
      "amount": "-0.50000000",
      "fee_amount": "0.00000000",
      "fee_account_id": "9c41ec8a82fb99b57cb5078ae0a8b569acct",
      "reference": "example of reference",
      "sender_account_id": "9c41ec8a82fb99b57cb5078ae0a8b569acct",
      "receiver_account_id": "f0cfb103e6c3d4a37c2750a1256862a3acct",
      "created_at": "2019-04-02T13:18:51Z",
      "updated_at": "2019-04-02T13:18:51Z"
    }
  ]
}

Click here to view the full API reference.

GET Retrieve a Transaction

This endpoint returns information about the Transaction specified in the request URL.

Request URL:

GET /v1/entities/{entity_id}/accounts/{account_id}/transactions/{transaction_id}

Response example:

Copy
Copied
{
  "id": "f59e8c8188500efce5be51eb71e9db08tran",
  "account_id": "ff6dc60c4f76dcea784bdc2ffed66e6facct",
  "type": "WITHDRAWAL",
  "state": "PENDING",
  "amount": "-1.23450000",
  "fee_amount": "0.00100000",
  "reference": "someting-fe8cbeecef486fe6edf9c3690e4f6b0a-unique",
  "address": "1HesYJSP1QqcyPEjnQ9vzBL1wujruNGe7R",
  "blockchain_txid": "0d0baf05852a856366a302ce9c9a9bbd36f95685a1e3d3bc9ef7715424ed577b",
  "blockchain_output_n": 4,
  "created_at": "2019-03-01T20:48:38Z",
  "updated_at": "2019-03-01T20:49:07Z"
}

Click here to view the full API reference.

POST Cancel a Transaction

This endpoint cancels the Transaction specified in the request URL.

Request URL:

POST /v1/entities/{entity_id}/accounts/{account_id}/transactions/{transaction_id}/cancel

Response example:

Copy
Copied
{
  "id": "f59e8c8188500efce5be51eb71e9db08tran",
  "account_id": "ff6dc60c4f76dcea784bdc2ffed66e6facct",
  "type": "WITHDRAWAL",
  "state": "CANCELLED",
  "amount": "-1.23450000",
  "fee_amount": "0.00100000",
  "total_amount": "-1.23550000",
  "reference": "someting-fe8cbeecef486fe6edf9c3690e4f6b0a-unique",
  "address": "1HesYJSP1QqcyPEjnQ9vzBL1wujruNGe7R",
  "blockchain_txid": "0d0baf05852a856366a302ce9c9a9bbd36f95685a1e3d3bc9ef7715424ed577b",
  "blockchain_output_n": 4,
  "created_at": "2019-03-01T20:48:38Z",
  "updated_at": "2019-03-01T20:49:07Z"
}

Click here to view the full API reference.

Deposits

A Deposit is a type of Transaction that represents a single incoming blockchain-level transfer to some Account Address.

Blockchain transactions made to an Address created using the SDA follow this sequence:

  1. The platform detects the transaction on the network and registers it as a new Transaction of type DEPOSIT.
  2. You will be able to view the Deposit using the GET List all Transactions for an Account endpoint. Store its ID and use the GET Retrieve a Transaction endpoint to track its state.
  3. When the network confirms the transaction, the Transaction resource on the SDA platform will transition to the COMPLETED state and the platform will credit the funds to the customer.

Deposits for Assets of type TOKEN

Customers can receive Deposits of type TOKEN at an Address associated with the TOKEN's underlying Asset (e.g., customers can receive ERC-20 Deposits at an Address of an ETH Account).

A customer must have an Account of type BASE if they wish to receive such Deposits. The underlying Asset of the BASE Account must match the underlying Asset of their desired TOKEN.

When you create an Account of type TOKEN for them, provide the ID of the BASE Account in the request body. Then, if the customer receives a Deposit of a TOKEN at an Address on their BASE Account, the SDA platform will automatically transfer the TOKEN funds to the TOKEN Account.

Example: Deposit resource

{
  "id": "bf20c716075ea82a4b1f3f0b49657161atrx",
  "account_id": "9c41ec8a82fb99b57cb5078ae0a8b569acct",
  "type": "DEPOSIT",
  "state": "PENDING",
  "amount": "1.12340000",
  "fee_amount": "0.00000000",
  "fee_account_id": "9c41ec8a82fb99b57cb5078ae0a8b569acct",
  "address": "1F1tAaz5x1HUXrCNLbtMDqcw6o5GNn4xqX",
  "blockchain_txid": "0dfd5b293f62780ef18eb85c6cdbbad408217576ac0e4f610d2f7a145a7f8de2",
  "blockchain_output_n": 1,
  "created_at": "2019-04-02T13:15:47Z",
  "updated_at": "2019-04-02T13:15:47Z"
}

Transfers

A Transfer represents an exchange of funds from one Account to another Account of the same Asset. This operation is not reflected externally as a blockchain transaction or any other observable event.

The API creates two Transaction resources for each transfer:

  1. A TRANSFER_OUTGOING Transaction on the sender's account, and
  2. A TRANSFER_INCOMING Transaction on the receiver's account.

Processing a Transfer

To create a Transfer on behalf of an Account holder, call the POST Create a Transfer endpoint. For each Transfer, you must provide a reference value that must be unique across all Transactions, as it serves as an idempotency key.

Optionally, you can set an end_to_end_id when requesting a Transfer. This ID will be applied to both Transaction resources created for the Transfer and allows you to identify the Transfer. If you don't supply an end_to_end_id, then the platform will generate one automatically. It must be a unique string of no more than 64 7-bit ASCII characters.

Before the platform can process the Transfer, the sender must approve the transaction.

The API will create a Transaction of type TRANSFER_OUTGOING on the sender's account, which debits the transacted funds, and a Transaction of type TRANSFER_INCOMING on the receiver's account, which credits the transacted funds.

transfer_flow_partner

POST Create a Transfer

This endpoint creates a transfer from the Account specified in the request URL to the Account specified in the request body. Please note the following:

  • If you make two requests with identical attributes, including the value of the reference attribute, the API will respond with the same response body each time and only create one Transfer.
  • You must specify either the amount or the total_amount in this request.

    • The amount property indicates the "transacted amount," i.e., the exact amount that will be sent to the recipient Account.
    • The total_amount property indicates indicates the amount that will be deducted from the sender Account balance. Solaris determines the amount that will be sent to the recipient after calculating and applying the fees. Use total_amount if, for example, the sender wishes to transfer the entire Account balance.
  • The 201 response contains an ID for a Transaction, but the API will not create the underlying Transaction right away. If you attempt to get this Transaction by its ID and receive a 404 error, then please wait a bit before trying again.

Request URL:

POST /v1/entities/{entity_id}/accounts/{account_id}/transactions/transfer

Request example:

Copy
Copied
{
  "reference": "unique-32d57e1d72b9b5fa-ref",
  "receiver_account_id": "e0c7cea27569ba4c59572e4073ee823bacct",
  "amount": "1.00000000",
  "end_to_end_id": "1a37702e42ca8b999b8750655208"
}

Response example:

Copy
Copied
// 201 Created

{
  "transaction_id": "fd213476ad3a1f2df48c7cbca394f3edatrx",
}

Click here to view the full API reference.

Withdrawals

A Withdrawal is a Transaction that represents a transfer of funds from an SDA Account to an external blockchain-level address.

Withdrawal fee model

The SDA platform offers a flexible solution for paying blockchain fees. When creating a Withdrawal on behalf of an Account holder, you can specify which Account pays the withdrawal fee. This can either be the Account from which the Withdrawal originates, or any other Account owned by the customer or by you. This allows you to cover the withdrawal fee for your customers if you choose.

The API uses the originating Account for paying the fee by default. If the originating Account is a TOKEN Account, then the API will use the corresponding BASE Account by default.

The platform will charge the specified Account and create a Transaction of type WITHDRAWAL_FEE in the originating Account.

note

You must pay fees for Withdrawals from TOKEN Accounts in the base Asset of said Account.

Processing a Withdrawal

To create a Withdrawal on behalf of an Account holder, call the POST Create a Withdrawal endpoint. For each Withdrawal, you must provide a reference value that must be unique across all Transactions, as it serves as an idempotency key.

Optionally, you can set an end_to_end_id when requesting a Withdrawal. This ID will be applied to both Transaction resources created for the Withdrawal and allows you to identify the Withdrawal. If you don't supply an end_to_end_id, then the platform will generate one automatically. It must be a unique string of no more than 64 7-bit ASCII characters.

After the platform registers and validates the Withdrawal, the customer must approve it so that the platform may add it to the queue for processing.

Periodically, the platform groups multiple Withdrawals together in a single blockchain-level transaction, which is signed and eventually broadcasted. After the corresponding transaction is broadcasted on the network, the platform marks all included Withdrawals as COMPLETED and updates their blockchain reference attributes.

POST Create a Withdrawal

This endpoint creates a Withdrawal on the Account specified in the request URL. Please note the following:

  • If you make two requests with identical attributes, including the value of the reference attribute, the API will respond with the same response body each time and only create one Withdrawal.
  • You must specify either the amount or the total_amount in this request.

    • The amount property indicates the "transacted amount," i.e., the exact amount that will be withdrawn to the recipient Address.
    • The total_amount property indicates indicates the amount that will be deducted from the sender Account balance; Solaris determines the amount that will be withdrawn after calculating and applying the fees. Use total_amount if, for example, the sender wishes to withdraw the entire Account balance.
  • The 201 response contains an ID for a Transaction, but the API will not create the underlying Transaction right away. If you attempt to get this Transaction by its ID and receive a 404 error, then please wait a bit before trying again.

Request URL:

POST /v1/entities/{entity_id}/accounts/{account_id}/transactions/withdrawal

Request example:

Copy
Copied
{
  "reference": "unique-a8e530db9b0e3ba8-ref",
  "address": "3D2oetdNuZUqQHPJmcMDDHYoqkyNVsFk9r",
  "amount": "1.00000000",
  "fee_account_id": "b4b7525ae27160d582b9a2305aba9e00acct",
  "end_to_end_id": "d97fbb01ed496dea646809dd"
}

Response example:

Copy
Copied
// 201 Created

{
  "transaction_id": "bede420fae7624091f337c22f9714fc0atrx"
}

Click here to view the full API reference.

Ledger Entries

A Ledger Entry is an immutable accounting entry that describes a change to the Account balance.

The platform creates Ledger Entries when it processes transactions. A Ledger Entry always describes the change that occurred in the past.

The type attribute on a Ledger Entry resource describes the change in the Account balance:

  • DEPOSIT_AMOUNT
  • DEPOSIT_FEE
  • TRANSFER_AMOUNT
  • TRANSFER_FEE
  • WITHDRAWAL_AMOUNT
  • WITHDRAWAL_FEE

Ledger Entries have an amount attribute.

  • If the amount is positive, then the event that led to its creation increased the balance of the Account.
  • If the amount is negative, then the event that led to its creation decreased the balance of the Account.

Ledger Entry API endpoints

GET List all Ledger Entries for an Account

This endpoint returns an array containing all Ledger Entries associated with the Account specified in the request URL.

Request URL:

GET /v1/entities/{entity_id}/accounts/{account_id}/ledger_entries

Response example:

Copy
Copied
// 200 OK

{
  "items": [
    {
      "id": "1c0fb8dbafa519adba070bba252b1263lent",
      "account_id": "1570f8eba8a6cffebf6354b718c138e7acct",
      "transaction_id": "ce9e6e3d62d7d0811a3f8c8aabbac466tran",
      "type": "WITHDRAWAL_AMOUNT",
      "amount": "-1.00000000",
      "created_at": "2019-03-01T22:31:06Z",
      "updated_at": "2019-03-01T22:31:06Z"
    }
  ],
  "pagination": {
    "next": 0,
    "prev": 0
  }
}

Click here to view the full API reference.

GET Retrieve a Ledger Entry

This endpoint returns information about the Ledger Entry specified in the request URL.

Request URL:

GET /v1/entities/{entity_id}/accounts/{account_id}/ledger_entries/{ledger_entry_id}

Response example:

Copy
Copied
// 200 OK

{
  "id": "1c0fb8dbafa519adba070bba252b1263lent",
  "account_id": "1570f8eba8a6cffebf6354b718c138e7acct",
  "transaction_id": "ce9e6e3d62d7d0811a3f8c8aabbac466tran",
  "type": "WITHDRAWAL_AMOUNT",
  "amount": "-1.00000000",
  "created_at": "2019-03-01T22:31:06Z",
  "updated_at": "2019-03-01T22:31:06Z"
}

Click here to view the full API reference.

Tiers

The SDA platform uses Tiers to place limits on Withdrawals by Entities.

Solaris configures a set of Tiers for each partner, and each Entity belongs to a Tier. The Tier specifies the amount of money that an Entity can withdraw in the configured time interval.

Every Tier has a level and over time, Entities can move up to Tiers with higher levels. An Entity can only move up one Tier level, and only if it meets the eligibility criteria specified in its current Tier. Examples include:

  1. The Entity has transacted at least a certain amount of money in the given time interval.
  2. The Entity has spent at least a certain amount of time in the current Tier.

The SDA platform automatically advances Entities up to the next Tier once they become eligible, usually within a day of meeting the given criteria.

Tier API endpoints

GET List all Tiers

This endpoint returns an array containing all available Tiers.

Request URL:

GET /v1/tiers

Response example:

Copy
Copied
{
  "items": [
    {
      "id": "56fae07897534327a5275ab2a28a15ff",
      "level": 1,
      "send_limit": "20000",
      "send_interval": 604800,
      "advancement_volume": "200000",
      "advancement_interval": 6048000,
      "created_at": "2022-10-27T14:25:53Z",
      "updated_at": "2022-10-27T14:25:53Z"
    }
  ],
  "pagination": {
    "next": 0,
    "prev": 0
  }
}

Click here to view the full API reference.

GET Retrieve a Tier

This endpoint retrieves the Tier specified in the request URL.

Request URL:

GET /v1/tiers/{tier_id}

Response example:

Copy
Copied
{
  "id": "56fae07897534327a5275ab2a28a15ff",
  "level": 1,
  "send_limit": "20000",
  "send_interval": 604800,
  "advancement_volume": "200000",
  "advancement_interval": 6048000,
  "created_at": "2022-10-27T14:25:53Z",
  "updated_at": "2022-10-27T14:25:53Z"
}

Click here to view the full API reference.

GET Retrieve an Entity's current Tier

This endpoint retrieves the currently activated Tier (if any) for the Entity specified in the request URL.

Request URL:

GET /v1/entities/{entity_id}/tier

Response example:

Copy
Copied
{
  "id": "56fae07897534327a5275ab2a28a15ff",
  "send_limit": "20000",
  "send_interval": 604800,
  "advancement_volume": "200000",
  "advancement_interval": 6048000,
  "volume": "1000",
  "activated_at": "2022-10-27T14:25:53Z"
}

Click here to view the full API reference.