NAV

Introduction

The Copper platform is equipped with a powerful API to provide integration with your applications. This documentation describes composition and usage of available API endpoints.

To stay informed on new methods as well as changes in actual endpoints, please check this documentation regularly.

API methods

To learn more about specific endpoints of Copper API, refer to following sections:

Webhooks

The Copper platform provides the webhook service which can send information about platform events to your resource for further handling. This way of data exchange is recommended for usage together with a conventional API polling.

To learn more, refer to the Webhooks section.

Copper Unlimited Online

Copper Unlimited Online is an alternative to the Copper Unlimited desktop application: a Docker image deployed independently on the client side and providing swift signing of transactions from Hot Vaults.

Follow the guide stated in the Copper Unlimited Online section to configure and deploy Copper Unlimited Online for your application.

Updates

To keep track of all changes related to the Copper platform API, refer to the changelog of this documentation.

Getting started

Copper API is based on the REST API interface provided for data exchange between a client and a server with the use of HTTPS requests and responses.

Copper API utilises three types of requests: GET, POST and PATCH. All data is sent and received as JSON. Examples in this documentation will reflect the actual method endpoint.

By default, the request should include a Content-Type header set as application/json. Some requests require different header fields, as well as other Content-Type values. In this case, a proper header will be stated in an example (see the right panel).

You can try our API using Postman.

To do this, use our Postman API collection.

Platform REST API URL: https://api.copper.co.

For Demo environment (demo.copper.co), you can use https://api.stage.copper.co

Authorisation

The majority of Copper API methods require authorisation via Copper API key. The API key can be obtained at the Copper platform. As a result, you will receive two strings required for authentication: API key and API key secret.

The only method available without an API key:

Below, you will find request authorisation examples for Bash and Python.

#!bash

API_KEY='ksgJrNOT1...i02V1hLfZs1I'
SECRET='W02cN5UDsF...SJtTyjDtq5SN'

TIMESTAMP="$(($(date +%s) * 1000))"
METHOD="GET"
URL_PATH="/platform/accounts"
BODY=""

SIGNATURE="$(echo -n "${TIMESTAMP}${METHOD}${URL_PATH}${BODY}" | openssl dgst -sha256 -hmac ${SECRET})"

curl -v "https://api.copper.co${URL_PATH}" \
  -H "Authorization: ApiKey ${API_KEY}" \
  -H "Content-Type: application/json" \
  -H "X-Signature: ${SIGNATURE}" \
  -H "X-Timestamp: ${TIMESTAMP}"
#!python

import hashlib
import hmac
import requests
import time

ApiKey = 'ksgJrNOT1X...i02V1hLfZs1I'
Secret = 'W02cN5UDsF...SJtTyjDtq5SN'

timestamp = str(round(time.time() * 1000))
method = "GET"
path = "/platform/accounts"
body = ""

signature = hmac.new(
    key=bytes(Secret, 'utf-8'),
    msg=bytes(timestamp + method + path + body, 'utf-8'),
    digestmod=hashlib.sha256
).hexdigest()

print(signature)  # example: 1b6064ca0d052d1a08d831c915ead54e6c5ff17237c845dab8b8c1cb8439a9c1

url = 'https://api.copper.co' + path

resp = requests.get(url, headers={
    'Authorization': 'ApiKey ' + ApiKey,
    'X-Signature': signature,
    'X-Timestamp': timestamp
})

print(resp.json())

Headers

To provide access to the API, all requests must contain the following headers:

Authorization: ApiKey 6a7eef41b0e160b27eb***********6af970fa77e45a8e20581e4ffd8

Signature

To sign your request, generate the X-Signature header as follows:

  1. Concantenate and pre-hash following strings:

    • X-Timestamp (value of the corresponding header);
    • HTTP request method in capitals: GET, POST or PATCH;
    • Path of a requested endpoint including additional parameters (e.g. /platform/orders?limit=1000);
    • All fields of the request body (set an empty string if a request does not include a body). For example:

    {"externalOrderId": "F7FCCFD3-B61B-4467-B456-B0FC27CE4494", "orderType": "buy", "baseCurrency": "BTC", "quoteCurrency": "USD", "amount": "5"}

  2. Sign the pre-hashed strings with your API Secret using HMAC SHA256 method.

  3. Encode the generated signature in the hexadecimal format.

After this, you can use the resulting string as the request X-Signature header.

Complete examples are provided on the right panel of this page.

Important note: To run the Bash script, use the bash mode: bash script.sh.

Request limitations

Copper API limits the number of API requests. The rate limit depends on request type. If the limit is exceeded, the request processing for the IP address or UserID is blocked for the specified lockup period.

Request type Limit Lockup period
HTTP request 30000 requests per last 5 minutes for a single IP address Until the number of requests in last 5 minutes is less than 30000
Authorization errors (wrong API key or signature) 200 failed requests per 1 hour for a single IP address 1 hour
Erroneous API requests (any business logic errors - bad request, missed required parameters, wrong amounts, currencies, etc) 60 requests per 1 minute for a single UserID 3 minutes

If either of the limits is exceeded, the Copper API returns Error 429.

API responses

+ Response 200 (application/json)
  {
    "orderId": "14697072",
    "externalOrderId": "ck2m90bpq000i3i5qwinf48ap",
    "status": "waiting-counterparty-approve",
    "orderType": "sell",
    "portfolioId": "9a7b6398-d4ac-4b26-ab62-f4dd7396aedb",
    "portfolioType": "trading",
    "accountId": "d961e420-cbcf-4642-83fd-82b184828a1e",
    "amount": "10",
    "baseCurrency": "XRP",
    "quoteCurrency": "USD",
    "limitType": "otc",
    "priceLimit": "0.02",
    "extra": {
      "reportingCurrencyRate": "0.31",
      "counterpartyPortfolioId": "666",
      "counterpartyOrderId": "14697073",
      "daysToSettle": "0",
      "feesPercent": "0.05"
    },
    "createdBy": "cc1bafa6-eb87-4a1e-ae6d-d27d0ea921aa",
    "organizationId": "TESTORG",
    "createdAt": "1572982234471",
    "updatedAt": "1572982234585"
  }

Successful responses are indicated with 2xx HTTP status codes.

Some responses may include a body containing data returned by Copper platform. Examples of returned fields are described in this documentation under a definite request.

+ Response 401 (application/json)
{
  "error":"incorrect-api-key",
  "message":"Incorrect API key"
}

Unless otherwise stated, invalid requests will return HTTP 4xx status codes. The returned body will also contain information about the error.

If you use an HTTP library to automate your API calls, it should be configured to provide message bodies for non-2xx requests so that you are able to read the message field from the body.

Common Error Codes

Status code Brief description Details
400 Bad Request Validation errors: empty required fields, unsupported values
401 Unauthorized Invalid API Key
403 Forbidden Access to the requested resource is denied
404 Not Found The requested endpoint has not been found
409 Conflict Validation error or the request cannot be completed due to an internal issue
429 Request Limit Exceeded The request rate limit is exceeded. Request processing is temporarily blocked
500 Internal Server Error Problems with the Copper platform server

All errors have standard response format:

NB: Not all errors of the Copper API have the error field. In this case, only the message field will be returned.

Account API

Get information about the organisation account

+ GET /platform/accounts

This method allows to retrieve the full volume of information on an organisation account.

On the API level, an account is similar to an organisation: each organisation has one account which includes portfolios. Portfolios, in turn, include wallets.

Required API Key permissions: View

Make sure you have granted access to definite portfolios: you will not be able to retrieve any account information of your API key is not assigned to this account while created.

Properties

+ Response 200 OK (application/json)
  {
    "accounts": [
      {
        "accountId": "d961e420-cbcf-4642-83fd-82b184828a1e",
        "organizationId": "TESTORG",
        "reportingCurrency": "USD",
        "accountName": "Default Account",
        "createdBy": "dc188f74-7f50-46e9-8925-d134f72209a8",
        "createdAt": "1566300620914",
        "_embedded": {
          "wallets": [
            {
              "walletId": "cjzjuf9ok000b3j5hv8eu73ya",
              "portfolioId": "9a7b6398-d4ac-4b26-ab62-f4dd7396aedb",
              "currency": "BTC",
              "balance": "0",
              "reserve": "0",
              "createdBy": "cc1bafa6-eb87-4a1e-ae6d-d27d0ea921ff",
              "createdAt": "1566306458090",
              "updatedAt": "1566306458090",
              "extra": {},
              "accountId": "d961e420-cbcf-4642-83fd-82b184828a1e",
              "organizationId": "TESTORG",
              "_embedded": {
                "depositTargets": [
                  {
                    "targetType": "crypto",
                    "mainCurrency": "BTC",
                    "address": "1AkwMcn1akvxBPEKJixKnhKKaBoQxDPcy9"
                  }
                ]
              }
            },
            {
              "walletId": "08f49895-34ea-4804-9cfe-0644c2e68e19",
              "portfolioId": "9a7b6398-d4ac-4b26-ab62-f4dd7396aedb",
              "currency": "XRP",
              "balance": "0",
              "reserve": "0",
              "createdBy": "cc1bafa6-eb87-4a1e-ae6d-d27d0ea921ff",
              "createdAt": "1567009192348",
              "updatedAt": "1567009192348",
              "extra": {},
              "accountId": "d961e420-cbcf-4642-83fd-82b184828a1e",
              "organizationId": "TESTORG",
              "_embedded": {
                "depositTargets": [
                  {
                    "targetType": "crypto",
                    "mainCurrency": "XRP",
                    "address": "rQUmVCVzbN9X91UzoiUKVs3sNRtpE5xWxi",
                    "destinationTag": "1339786120"
                  }
                ]
              }
            },
            {
              "walletId": "cjzjt2cxv000d3j5hh6asqx7v",
              "portfolioId": "3de435b4-e03c-48ab-a40c-cc2571bd9955",
              "currency": "BTC",
              "balance": "0",
              "reserve": "0",
              "createdBy": "dc188f74-7f50-46e9-8925-d134f72209a8",
              "createdAt": "1566304176754",
              "updatedAt": "1572979747481",
              "extra": {},
              "accountId": "d961e420-cbcf-4642-83fd-82b184828a1e",
              "organizationId": "TESTORG",
              "_embedded": {
                "depositTargets": [
                  {
                    "targetType": "crypto",
                    "mainCurrency": "BTC",
                    "address": "1K853Hd32yiSJcZc1KQoXVpcxAk21KwLPt"
                  }
                ]
              }
            },
            {
              "walletId": "ck0h1dan6000b3j5nfekpgi6x",
              "portfolioId": "9a7b6398-d4ac-4b26-ab62-f4dd7396aedb",
              "currency": "USD",
              "balance": "0",
              "reserve": "0",
              "createdBy": "cc1bafa6-eb87-4a1e-ae6d-d27d0ea921ff",
              "createdAt": "1568313507384",
              "updatedAt": "1568313507384",
              "extra": {},
              "accountId": "d961e420-cbcf-4642-83fd-82b184828a1e",
              "organizationId": "TESTORG",
              "_embedded": {
                "depositTargets": [
                  {
                    "targetType": "bank-account",
                    "accountName": "Copper Technologies (Switzerland) AG",
                    "recipientAddress": "1-4 Argyll Street, London W1F 7LD United Kingdom",
                    "iban": "-",
                    "swiftCode": "SIGNUS33XXX",
                    "aba": "026013576",
                    "bankName": "Signature Bank",
                    "bankAddress": "565 Fifth Avenue New York NY 10017",
                    "accountNumber": "1503750496",
                    "referenceNumber": "TESTORGQWJ89N"
                  },
                  {
                    "targetType": "bank-account",
                    "accountName": "Dolfin Financial Client Money Account",
                    "recipientAddress": "50 Berkeley Street, London W1J 8HA",
                    "iban": "GB77MYMB23058019927587",
                    "swiftCode": "MYMBGB2L",
                    "aba": "-",
                    "bankName": "Metro Bank plc",
                    "bankAddress": "1 Southampton Row, London WC1B 5HA",
                    "accountNumber": "19927587",
                    "referenceNumber": "Credit to CLN1988 TESTORGQWJ89N"
                  },
                  {
                    "targetType": "bank-account",
                    "accountName": "Signet",
                    "recipientAddress": "-",
                    "iban": "-",
                    "swiftCode": "-",
                    "aba": "-",
                    "bankName": "-",
                    "bankAddress": "-",
                    "accountNumber": "0x207f012ce4882f9bcd56d5907a3cf411f402437f",
                    "referenceNumber": "TESTORGQWJ89N"
                  },
                  {
                    "targetType": "bank-account",
                    "accountName": "Silvergate",
                    "recipientAddress": "Coming soon!",
                    "iban": "-",
                    "swiftCode": "-",
                    "aba": "-",
                    "bankName": "-",
                    "bankAddress": "-",
                    "accountNumber": "-",
                    "referenceNumber": ""
                  },
                  {
                    "targetType": "bank-account",
                    "accountName": "SEN",
                    "recipientAddress": "Coming soon!",
                    "iban": "-",
                    "swiftCode": "-",
                    "aba": "-",
                    "bankName": "-",
                    "bankAddress": "-",
                    "accountNumber": "-",
                    "referenceNumber": ""
                  }
                ]
              }
            },
            {
              "walletId": "ck0m6345z000d3j5n4v0dmfuj",
              "portfolioId": "c98af32b-c3e9-4bfb-972e-7e413bb5ce7e",
              "currency": "BNB",
              "mainCurrency": "BNB",
              "balance": "0.0000000",
              "reserve": "0.00000000",
              "createdBy": "cc1bafa6-eb87-4a1e-ae6d-d27d0ea921ff",
              "createdAt": "1568623763772",
              "updatedAt": "1568623763772",
              "extra": {
              },
              "accountId": "d961e420-cbcf-4642-83fd-82b184828a1e",
              "organizationId": "TESTORG",
              "_embedded": {
                "depositTargets": [
                  {
                    "targetType": "crypto",
                    "mainCurrency": "BNB",
                    "address": "bnb1evas9qm5xj38xek2klmq2u49qf5cg8g0u82s4c"
                  }
                ]
              }
            }
          ],
          "portfolios": [
            {
              "portfolioId": "9a7b6398-d4ac-4b26-ab62-f4dd7396aedb",
              "accountId": "d961e420-cbcf-4642-83fd-82b184828a1e",
              "portfolioName": "Default Trading",
              "portfolioType": "trading",
              "createdBy": "dc188f74-7f50-46e9-8925-d134f72209a8",
              "createdAt": "1566300620921",
              "updatedAt": "1566300620921",
              "isActive": true,
              "organizationId": "TESTORG",
              "extra": {}
            },
            {
              "portfolioId": "c98af32b-c3e9-4bfb-972e-7e413bb5ce7e",
              "accountId": "d961e420-cbcf-4642-83fd-82b184828a1e",
              "portfolioName": "Default Vault",
              "portfolioType": "custody",
              "createdBy": "dc188f74-7f50-46e9-8925-d134f72209a8",
              "createdAt": "1566300620925",
              "updatedAt": "1566300620925",
              "isActive": true,
              "organizationId": "TESTORG",
              "extra": {}
            },
            {
              "portfolioId": "3de435b4-e03c-48ab-a40c-cc2571bd9955",
              "accountId": "d961e420-cbcf-4642-83fd-82b184828a1e",
              "portfolioName": "Bittrex",
              "portfolioType": "external",
              "createdBy": "dc188f74-7f50-46e9-8925-d134f72209a8",
              "createdAt": "1566300770963",
              "updatedAt": "1566300770963",
              "isActive": true,
              "organizationId": "TESTORG",
              "extra": {
                "exchange": "bittrex"
              }
            }
          ]
        }
      }
    ]
  }

Request

The method request can include following parameters:

Parameter Data type Description
organizationId Optional<String> Unique identifier of an organisation including this account. Please note that you have to be a member of an organisation you are going to filter out
isArchive Optional<Boolean> false (default value) - the requested account is active, true - the requested account is archived
portfolioType Optional<String> Filter the accounts by portfolio type (see the PortfolioType variants below)

Response

The main field of the method response is "accounts" including following fields:

Field Data type Description
accountId String Unique account identifier
organizationId String Unique identifier of an organisation including this account
reportingCurrency Currency Currency code used for reports and in the platform UI for estimation
accountName String Name of the account
createdBy String User ID of account creator
createdAt Long Time of account creation
updatedAt Optional <Long> Time of last account update
updatedBy Optional <String> User ID of last account updater

Each account field includes an "_embedded" section which contains information on account's "wallets" and "portfolios":

Field Data type Description
walletId String Unique wallet identifier
portfolioId String Unique portfolio identifier that includes this wallet
currency Currency Wallet currency
mainCurrency Optional<Currency> Currency of main blockchain of the vault (e.g. For USDT, it could be either ETH or BTC)
balance String Current total balance
reserve String Reserved balance
createdBy String User ID of wallet creator
updatedBy Optional<String> User ID of the last wallet updater
createdAt String Time of wallet creation
updatedAt Optional<String> Time of the latest wallet updated
extra WalletExtra Additional wallet data (includes the WalletExtra model below)
accountId String unique account identifier that includes this wallet
organizationId String Unique identifier of an organisation including this wallet
_embedded Optional<WalletEmbedded> Additional information on the wallet (includes the WalletEmbedded model below)

WalletExtra

Field Data type Description
externalAccountId Optional<String> Identifier of an external account associated with this portfolio. This field is used for external portfolios (see the PortfolioType section below)
stakeInfos Optional List<StakeInfo> Information about staked assets of the wallet (see the StakeInfo model below ). If the account has no staked assets, this field is returned blank

WalletEmbedded

Field Data type Description
depositTargets List<DepositTarget> List of deposit targets attached to the wallet (includes the DepositTarget model below)
outstandingBalance BigDecimal Amount of outstanding balances, if any

StakeInfo

Field Data type Description
poolId Optional<String> Staking pool identifier (can be returned as a list)
poolName Optional<String> Staking pool name
rewardAmount Optional<BigDecimal> Reward amount of the wallet
stakedAmount Optional<BigDecimal> Staked amount of the wallet
stakedFrozen Optional<Boolean> true - the staked amount is blocked, false - the staked amount is available
readyToWithdrawal Optional<Boolean> true - the reward is ready to withdrawal, false - the reward is not ready to withdrawal
stakePublicKey Optional<String> For Solana staking: public key of the stake

DepositTarget

Field Data type Description
targetType String Type of the deposit target: may be crypto or bank-account

For crypto targetType:

Field Data type Description
mainCurrency Optional<Currency> Currency of the main blockchain (e.g. BTC or ETH for USDT currency)
address Optional<String> Blockchain address
destinationTag Optional<Long> Destination tag (for XRP addresses)
memo Optional<String> Address memo (if any)

For bank-account targetType, the fields contain information according to the bank account details:

Field Data type Description
accountName Optional<String> Bank account name
accountDescription Optional<String> Bank account description
recipientAddress Optional<String> Recipient address
iban Optional<String> Bank IBAN
swiftCode Optional<String> Bank SWIFT
aba Optional<String> Bank ABA number (for U.S. banks)
bankName Optional<String> Bank name
bankAddress Optional<String> Bank address
accountNumber Optional<String> Bank account number
referenceNumber Optional<String> Bank account reference number
billingAddress Optional<String> Bank billing address
sortCode Optional<String> Bank sort code

Portfolio

Field Data type Description
portfolioId String Unique portfolio identifier
accountId String Unique identifier of the account including this portfolio
portfolioName String Portfolio name
portfolioType PortfolioType Type of the portfolio
createdBy String User ID of the portfolio creator
updatedBy Optional<String> User ID of the last portfolio updater
createdAt Long Time of portfolio creation
updatedAt Optional<String> Time of the last portfolio update
isActive Boolean Boolean flag showing is portfolio active (true) or archived (false)
organizationId Optional<String> Unique identifier of the organisation including this portfolio
extra PortfolioExtra Additional portfolio data (see the PortfolioExtra model below)

PortfolioExtra

Field Data type Description
exchange Optional<Exchange> External exchange associated with this portfolio (see the Exchange list below)
exchangeAccountType Optional<ExchangeAccountType> External portfolio exchange account type (see the ExchangeAccountType list below)
tradingKeys Optional<Map<String, ExternalTradingKey>> Trading keys for the external portfolio (see the ExternalTradingKey model below)
viewKeys Optional<Map<String, ExternalViewKey>> View keys of the external portfolio (see the ExternalViewKey model below)
customerId Optional<String> External customer identifier from an exchange
parentPortfolioId Optional<String> Identifier of a parent portfolio, if any
clearLoopPortfolioId Optional<String> Identifier of a ClearLoop portfolio
usdWithdrawalLimit Optional<BigDecimal> Withdrawal limit of the portfolio in USD
baseCurrency Optional<Currency> Base currency for external accounts that use margin pair
quoteCurrency Optional<Currency> Quote currency for external account that use margin pair
showWalletBalance Optional<BalanceType> Type of balance demonstrated for the external account (see the BalanceType list below)
externalAccountId Optional<String> Identifier of an external third-party account related to the portfolio

Exchange

This field contains strings with identifiers of exchanges supported within Walled Garden, Open Garden and ClearLoop (may change in the future):

ExchangeAccountType

This field contains the enum reflecting an account on a specified exchange (see the list above) associated with this portfolio. The clearloop value means that an exchange has been connected to this portfolio within the ClearLoop. Other account types are related to Walled Garden and Open Garden technologies. This enum may be changed in the future:

ExternalTradingKey

Field Data type Description
tradingKey String Public part of a portfolio trading key

ExternalViewKey

Field Data type Description
viewKey String Public part of a portfolio view-only key

BalanceType Enum with following values (may be changed in future):

Get information about a particular portfolio of an organisation

+ GET /platform/portfolios/{portfolioId}

This method allows to retrieve information about a definite portfolio according to the portfolio identifier. Information about each portfolio includes data of all wallets related to the portfolio. The method does not require any request fields.

Required API Key permissions: View

Make sure you have granted access to definite portfolios: you will not be able to retrieve any account information of your API key is not assigned to this account while created.

Properties

+ Response 200 (application/json)
  {
    "portfolioId": "9a7b6398-d4ac-4b26-ab62-f4dd7396aedb",
    "accountId": "d961e420-cbcf-4642-83fd-82b184828a1e",
    "portfolioName": "Default Trading",
    "portfolioType": "trading",
    "createdBy": "dc188f74-7f50-46e9-8925-d134f72209a8",
    "createdAt": "1566300620921",
    "updatedAt": "1566300620921",
    "isActive": true,
    "organizationId": "TESTORG",
    "extra": {},
    "_embedded": {
      "wallets": [
        {
          "walletId": "cjzjuf9ok000b3j5hv8eu73ya",
          "portfolioId": "9a7b6398-d4ac-4b26-ab62-f4dd7396aedb",
          "currency": "BTC",
          "balance": "130.45",
          "reserve": "10.45",
          "available": "120",
          "createdBy": "cc1bafa6-eb87-4a1e-ae6d-d27d0ea921ff",
          "createdAt": "1566306458090",
          "updatedAt": "1566306458090",
          "extra": {},
          "accountId": "d961e420-cbcf-4642-83fd-82b184828a1e",
          "organizationId": "TESTORG",
          "_embedded": {
            "depositTargets": [
              {
                "targetType": "crypto",
                "mainCurrency": "BTC",
                "address": "1AkwMcn1akvxBPEKJixKnhKKaBoQxDPcy9"
              }
            ]
          }
        },
        {
          "walletId": "08f49895-34ea-4804-9cfe-0644c2e68e19",
          "portfolioId": "9a7b6398-d4ac-4b26-ab62-f4dd7396aedb",
          "currency": "XRP",
          "balance": "12",
          "reserve": "0",
          "available": "12",
          "createdBy": "cc1bafa6-eb87-4a1e-ae6d-d27d0ea921ff",
          "createdAt": "1567009192348",
          "updatedAt": "1567009192348",
          "extra": {},
          "accountId": "d961e420-cbcf-4642-83fd-82b184828a1e",
          "organizationId": "TESTORG",
          "_embedded": {
            "depositTargets": [
              {
                "targetType": "crypto",
                "mainCurrency": "XRP",
                "address": "rQUmVCVzbN9X91UzoiUKVs3sNRtpE5xWxi",
                "destinationTag": "1339786120"
              }
            ]
          }
        }
      ]
    }
  }

Response

The main field of the method is "portfolio" including following model:

Field Data type Description
portfolioId String Unique portfolio identifier
accountId String Unique identifier of the account including this portfolio
portfolioName String Portfolio name
portfolioType PortfolioType Type of the portfolio
createdBy String User ID of the portfolio creator
updatedBy Optional<String> User ID of the last portfolio updater
createdAt Long Time of portfolio creation
updatedAt Optional<Long> Time of the last portfolio update
isActive Boolean Boolean flag showing is portfolio active (true) or archived (false)
organizationId Optional<String> Unique identifier of the organisation including this portfolio
extra PortfolioExtra Additional portfolio data (see the PortfolioExtra model below)

PortfolioExtra

Field Data type Description
exchange Optional<Exchange> External portfolio exchange (see the Exchange list below)
exchangeAccountType Optional<ExchangeAccountType> External portfolio exchange account type (see the ExchangeAccountType list below)
tradingKeys Optional<Map<String, ExternalTradingKey>> Trading keys for the external portfolio (see the ExternalTradingKey model below)
viewKeys Optional<Map<String, ExternalViewKey>> View keys of the external portfolio (see the ExternalViewKey model below)
customerId Optional<String> External customer identifier from an exchange
parentPortfolioId Optional<String> Identifier of a parent portfolio, if any
clearLoopPortfolioId Optional<String> Identifier of a ClearLoop portfolio
usdWithdrawalLimit Optional<BigDecimal> Withdrawal limit of the portfolio in USD
baseCurrency Optional<Currency> Base currency for external accounts that use margin pair
quoteCurrency Optional<Currency> Quote currency for external account that use margin pair
showWalletBalance Optional<BalanceType> Type of balance demonstrated for the external account (see the BalanceType list below)
externalAccountId Optional<String> Identifier of an external third-party account related to the portfolio

Exchange

This field contains strings with identifiers of exchanges supported within Walled Garden, Open Garden and ClearLoop (may change in the future):

ExchangeAccountType

This field contains the enum reflecting an account on a specified exchange (see the list above) associated with this portfolio. The clearloop value means that an exchange has been connected to this portfolio within the ClearLoop. Other account types are related to Walled Garden and Open Garden technologies. This enum may be changed in the future:

ExternalTradingKey

Field Data type Description
tradingKey String Public part of a portfolio trading key

ExternalViewKey

Field Data type Description
viewKey String Public part of a portfolio view-only key

BalanceType Enum with following values (may be changed in future):

Each account field includes an "_embedded" section which contains information on account's "wallets" and "portfolios":

Field Data type Description
walletId String Unique wallet identifier
portfolioId String Unique portfolio identifier that includes this wallet
currency Currency Wallet currency
mainCurrency Optional<Currency> Currency of main blockchain of the vault
balance String Current total balance
reserve String Reserved balance
createdBy String User ID of wallet creator
updatedBy Optional<String> User ID of the last wallet updater - displayed if account has been updated
createdAt String Time of wallet creation
updatedAt Optional<String> Time of the latest wallet update - displayed if account has been updated
extra WalletExtra Additional wallet data (includes the WalletExtra model below)
accountId String unique account identifier that includes this wallet
organizationId String Unique identifier of an organisation including this wallet
_embedded Optional<WalletEmbedded> Additional information on the wallet (includes the WalletEmbedded model below)

WalletExtra

Field Data type Description
externalAccountId Optional<String> Third-party identifier (ID of an external account)
stakeInfos Optional List<StakeInfo> Information about staked assets of the wallet (see the StakeInfo model below )

WalletEmbedded

Field Data type Description
depositTargets List<DepositTarget> List of deposit targets attached to the wallet (includes the DepositTarget model below)
outstandingBalance BigDecimal Amount of outstanding balances, if any

StakeInfo

Field Data type Description
poolId Optional<String> Staking pool identifier (can be returned as a list)
poolName Optional<String> Staking pool name
rewardAmount Optional<BigDecimal> Reward amount of the wallet
stakedAmount Optional<BigDecimal> Staked amount of the wallet
stakedFrozen Optional<Boolean> true - the staked amount is blocked, false - the staked amount is available
readyToWithdrawal Optional<Boolean> true - the reward is ready to withdrawal, false - the reward is not ready to withdrawal
stakePublicKey Optional<String> For Solana staking: public key of the stake

DepositTarget

Field Data type Description
targetType String Type of the deposit target: may be crypto or bank-account

For crypto targetType:

Field Data type Description
mainCurrency Optional<Currency> Currency of the main blockchain (e.g. BTC or ETH for USDT currency)
address Optional<String> Blockchain address
destinationTag Optional<Long> Address destination tag
memo Optional<String> Address memo

For bank-account targetType, the fields contain information according to the bank account details:

Field Data type Description
accountName Optional<String> Bank account name
recipientAddress Optional<String> Recipient address
iban Optional<String> Bank IBAN
swiftCode Optional<String> Bank SWIFT
aba Optional<String> Bank ABA number (for U.S. banks)
bankName Optional<String> Bank name
bankAddress Optional<String> Bank address
accountNumber Optional<String> Bank account number
referenceNumber Optional<String> Bank account reference number
billingAddress Optional<String> Bank billing address
sortCode Optional<String> Bank sort code

Get information about wallets of an organisation or a particular wallet

+ GET /platform/wallets/{walletId}

The /platform/wallets method allows to retrieve information about all wallets related to the account. Possible request parameters of this method are stated below.

The /platform/wallets/{walletId} method returns information about a particular wallet according to its identifier. It does not require any request fields.

Required API Key permissions: View

Properties

+ Response 200 (application/json)
  {
    "wallets": [
      {
        "walletId": "cjzjuf9ok000b3j5hv8eu73ya",
        "portfolioId": "9a7b6398-d4ac-4b26-ab62-f4dd7396aedb",
        "currency": "BTC",
        "balance": "0",
        "reserve": "0",
        "createdBy": "cc1bafa6-eb87-4a1e-ae6d-d27d0ea921ff",
        "createdAt": "1566306458090",
        "updatedAt": "1566306458090",
        "extra": {},
        "accountId": "d961e420-cbcf-4642-83fd-82b184828a1e",
        "organizationId": "TESTORG",
         "_embedded": {
           "depositTargets": [
             {
               "targetType": "crypto",
               "mainCurrency": "BTC",
               "address": "1AkwMcn1akvxBPEKJixKnhKKaBoQxDPcy9"
             }
           ]
         }
      },
      {
        "walletId": "08f49895-34ea-4804-9cfe-0644c2e68e19",
        "portfolioId": "9a7b6398-d4ac-4b26-ab62-f4dd7396aedb",
        "currency": "XRP",
        "balance": "0",
        "reserve": "0",
        "createdBy": "cc1bafa6-eb87-4a1e-ae6d-d27d0ea921ff",
        "createdAt": "1567009192348",
        "updatedAt": "1567009192348",
        "extra": {},
        "accountId": "d961e420-cbcf-4642-83fd-82b184828a1e",
        "organizationId": "TESTORG",
        "_embedded": {
          "depositTargets": [
            {
              "targetType": "crypto",
              "mainCurrency": "XRP",
              "address": "rQUmVCVzbN9X91UzoiUKVs3sNRtpE5xWxi",
              "destinationTag": "1339786120"
            }
          ]
        }
      },
      {
        "walletId": "cjzjt2cxv000d3j5hh6asqx7v",
        "portfolioId": "3de435b4-e03c-48ab-a40c-cc2571bd9955",
        "currency": "BTC",
        "balance": "0",
        "reserve": "0",
        "createdBy": "dc188f74-7f50-46e9-8925-d134f72209a8",
        "createdAt": "1566304176754",
        "updatedAt": "1572980507472",
        "extra": {},
        "accountId": "d961e420-cbcf-4642-83fd-82b184828a1e",
        "organizationId": "TESTORG",
        "_embedded": {
          "depositTargets": [
            {
              "targetType": "crypto",
              "mainCurrency": "BTC",
              "address": "1K853Hd32yiSJcZc1KQoXVpcxAk21KwLPt"
            }
          ]
        }
      },
      {
        "walletId": "ck0h1dan6000b3j5nfekpgi6x",
        "portfolioId": "9a7b6398-d4ac-4b26-ab62-f4dd7396aedb",
        "currency": "USD",
        "balance": "0",
        "reserve": "0",
        "createdBy": "cc1bafa6-eb87-4a1e-ae6d-d27d0ea921ff",
        "createdAt": "1568313507384",
        "updatedAt": "1568313507384",
        "extra": {},
        "accountId": "d961e420-cbcf-4642-83fd-82b184828a1e",
        "organizationId": "TESTORG",
        "_embedded": {
          "depositTargets": [
            {
              "targetType": "bank-account",
              "accountName": "Copper Technologies (Switzerland) AG",
              "recipientAddress": "1-4 Argyll Street, London W1F 7LD United Kingdom",
              "iban": "-",
              "swiftCode": "SIGNUS33XXX",
              "aba": "026013576",
              "bankName": "Signature Bank",
              "bankAddress": "565 Fifth Avenue New York NY 10017",
              "accountNumber": "1503750496",
              "referenceNumber": "TESTORGQWJ89N"
            },
            {
              "targetType": "bank-account",
              "accountName": "Dolfin Financial Client Money Account",
              "recipientAddress": "50 Berkeley Street, London W1J 8HA",
              "iban": "GB77MYMB23058019927587",
              "swiftCode": "MYMBGB2L",
              "aba": "-",
              "bankName": "Metro Bank plc",
              "bankAddress": "1 Southampton Row, London WC1B 5HA",
              "accountNumber": "19927587",
              "referenceNumber": "Credit to CLN1988 TESTORGQWJ89N"
            },
            {
              "targetType": "bank-account",
              "accountName": "Signet",
              "recipientAddress": "-",
              "iban": "-",
              "swiftCode": "-",
              "aba": "-",
              "bankName": "-",
              "bankAddress": "-",
              "accountNumber": "0x207f012ce4882f9bcd56d5907a3cf411f402437f",
              "referenceNumber": "TESTORGQWJ89N"
            },
            {
              "targetType": "bank-account",
              "accountName": "Silvergate",
              "recipientAddress": "Coming soon!",
              "iban": "-",
              "swiftCode": "-",
              "aba": "-",
              "bankName": "-",
              "bankAddress": "-",
              "accountNumber": "-",
              "referenceNumber": ""
            },
            {
              "targetType": "bank-account",
              "accountName": "SEN",
              "recipientAddress": "Coming soon!",
              "iban": "-",
              "swiftCode": "-",
              "aba": "-",
              "bankName": "-",
              "bankAddress": "-",
              "accountNumber": "-",
              "referenceNumber": ""
            }
          ]
        }
      },
      {
        "walletId": "ck0m6345z000d3j5n4v0dmfuj",
        "portfolioId": "c98af32b-c3e9-4bfb-972e-7e413bb5ce7e",
        "currency": "BNB",
        "mainCurrency": "BNB",
        "balance": "0.0000000",
        "reserve": "0.00000000",
        "createdBy": "cc1bafa6-eb87-4a1e-ae6d-d27d0ea921ff",
        "createdAt": "1568623763772",
        "updatedAt": "1568623763772",
        "extra": {
        },
        "accountId": "d961e420-cbcf-4642-83fd-82b184828a1e",
        "organizationId": "TESTORG",
        "_embedded": {
          "depositTargets": [
            {
              "targetType": "crypto",
              "mainCurrency": "BNB",
              "address": "bnb1evas9qm5xj38xek2klmq2u49qf5cg8g0u82s4c"
            }
          ]
        }
      }
    ]
  }

Request parameters of the /platform/wallets method

The method request can include following optional parameters:

Parameter Data type Description
portfolioId Optional<String> Unique identifier of a portfolio
organizationId Optional<String> Unique identifier of an organisation including the requested portfolio
includeOutstandingBalance Optional<Boolean> Show outstanding balances of a wallet

Response

The main field of the method response is "wallets" including following model:

Field Data type Description
walletId String Unique wallet identifier
portfolioId String Unique portfolio identifier that includes this wallet
currency Currency Wallet currency
mainCurrency Optional<Currency> Currency of main blockchain of the vault (e.g. For USDT, it could be either ETH or BTC)
balance Optional<BigDecimal> Current total balance
reserve Optional<BigDecimal> Reserved balance
createdBy String User ID of wallet creator
updatedBy Optional<String> User ID of the last wallet updater
createdAt Long Time of wallet creation
updatedAt Optional<Long> Time of the latest wallet update
extra WalletExtra Additional wallet data (includes the WalletExtra model below)
accountId String unique account identifier that includes this wallet
organizationId Optional<String> Unique identifier of an organisation including this wallet
_embedded Optional<WalletEmbedded> Additional information on the wallet (includes the WalletEmbedded model below)

WalletExtra

Field Data type Description
externalAccountId Optional<String> Third-party identifier (ID of an external account)
stakeInfos Optional List<StakeInfo> Information about staked assets of the wallet (see the StakeInfo model below )

WalletEmbedded

Field Data type Description
depositTargets List<DepositTarget> List of deposit targets attached to the wallet (includes the DepositTarget model below)
outstandingBalance Optional<BigDecimal> Amount of outstanding balances, if any

StakeInfo

Field Data type Description
poolId Optional<String> Staking pool identifier (can be returned as a list)
poolName Optional<String> Staking pool name
rewardAmount Optional<BigDecimal> Reward amount of the wallet
stakedAmount Optional<BigDecimal> Staked amount of the wallet
stakedFrozen Optional<Boolean> true - the staked amount is blocked, false - the staked amount is available
readyToWithdrawal Optional<Boolean> true - the reward is ready to withdrawal, false - the reward is not ready to withdrawal
stakePublicKey Optional<String> For Solana staking: public key of the stake

DepositTarget

Field Data type Description
targetType String Type of the deposit target: may be crypto or bank-account

For crypto targetType:

Field Data type Description
mainCurrency Optional<Currency> Currency of the main blockchain (e.g. BTC or ETH for USDT currency)
address Optional<String> Blockchain address
destinationTag Optional<Long> Address destination tag
memo Optional<String> Address memo

For bank-account targetType, the fields contain information according to the bank account details:

Field Data type Description
accountName Optional<String> Bank account name
recipientAddress Optional<String> Recipient address
iban Optional<String> Bank IBAN
swiftCode Optional<String> Bank SWIFT
aba Optional<String> Bank ABA number (for U.S. banks)
bankName Optional<String> Bank name
bankAddress Optional<String> Bank address
accountNumber Optional<String> Bank account number
referenceNumber Optional<String> Bank account reference number
billingAddress Optional<String> Bank billing address
sortCode Optional<String> Bank sort code

Activate a multi-chain wallet

+ POST /platform/wallets/assets

Activates a wallet for a specific currency using a multi-chain shard.

Requirements: the shard with the specific cryptography must be activated by the account manager first.

Required API Key permissions: Withdraw

Properties

+ Response 200 (application/json)
  {
    "wallets": [
      {
        "walletId": "cjzjuf9ok000b3j5hv8eu73ya",
        "portfolioId": "9a7b6398-d4ac-4b26-ab62-f4dd7396aedb",
        "currency": "BTC",
        "balance": "0",
        "reserve": "0",
        "createdBy": "cc1bafa6-eb87-4a1e-ae6d-d27d0ea921ff",
        "createdAt": "1566306458090",
        "updatedAt": "1566306458090",
        "extra": {
               "isMultiChain": false,
               "signatureScheme": "ecdsa"
                  },
        "accountId": "d961e420-cbcf-4642-83fd-82b184828a1e",
        "organizationId": "TESTORG",
         "_embedded": {
           "depositTargets": [
             {
               "targetType": "crypto",
               "mainCurrency": "BTC",
               "address": "1AkwMcn1akvxBPEKJixKnhKKaBoQxDPcy9"
             }
           ]
         }
      }
    ]
  }

Request parameters of the /platform/wallets/assets method

The method request must include the following parameters:

Parameter Data type Description
walletId <String> Unique identifier of a wallet which is being activated
portfolioId <String> Unique identifier of a portfolio. The portfoio must be created as multi-chain
currency <String> Currency of the wallet to be activated ,
mainCurrency <String> Main currency of the blockchain

Response

The main field of the method response is "wallets" (see above).

Get whitelisted bank accounts

+ GET /platform/bank-accounts

This method allows to retrieve information about all bank accounts for fiat withdraw, whitelisted in your organisation on the Copper platform. The fields of the method response include full bank account details.

The method does not require any request fields.

Required API Key permissions: View

Make sure you have granted access to definite portfolios: you will not be able to retrieve any account information of your API key is not assigned to this account while created.

Properties

+ Response 200 (application/json)
  {
    "bankAccounts": [
      {
        "bankAccountId": "cjzjqt53c00063j5hgp7c6rya",
        "bankAccountType": "international",
        "accountId": "d961e420-cbcf-4642-83fd-82b184828a1e",
        "organizationId": "TESTORG",
        "bankAccountName": "TSK",
        "beneficiaryAccountName": "AccName",
        "beneficiaryAccountAddress": "AccAdress",
        "beneficiaryAccountPostalCode": "AccPostalCode",
        "beneficiaryAccountCity": "AccPostalCity",
        "beneficiaryAccountCountry": "BD",
        "iban": "ibannumber",
        "swift": "swiftnumber",
        "bankName": "BankName",
        "bankAddress": "BankAdress",
        "bankPostalCode": "BankPostalCode",
        "bankCity": "PostalCity",
        "bankCountry": "AL",
        "createdBy": "0802703c-11d4-4e49-8b9b-d0c909301709",
        "updatedBy": "0802703c-11d4-4e49-8b9b-d0c909301709",
        "createdAt": "1566300620934",
        "updatedAt": "1569402415337",
        "coinbasePaymentReference": "coinbaseRef",
        "senId": "senNum",
        "senDescription": "senDesc",
        "comment": "test"
      }
    ]
  }

Request

The method request does not have any optional parameters.

Response

The main field of the method response is "bank-account" including following model:

Field Data type Description
bankAccountId String Unique bank account identifier
bankAccountType BankAccountType Type of the bank account (see the BankAccountType below)
accountId String Unique account identifier
organizationId Optional<String> Unique identifier of the organisation including the related account
bankAccountName Optional<String> Bank account name
beneficiaryAccountName Optional<String> Beneficiary account name
beneficiaryAccountAddress Optional<String> Beneficiary account address
beneficiaryAccountPostalCode Optional<String> Beneficiary account postal code
beneficiaryAccountCity Optional<String> Beneficiary account city
beneficiaryAccountCountry Optional<String> Beneficiary account country
iban Optional<String> Bank IBAN
swift Optional<String> Bank SWIFT
bankName Optional<String> Bank name
bankAddress Optional<String> Bank address
bankPostalCode Optional<String> Bank postal code
bankCity Optional<String> Bank city
bankCountry Optional<String> Bank country
lastUsedAt Optional<Long> Time of last account usage
createdBy String User ID of the bank account creator
updatedBy Optional<String> User ID of the bank account updater
createdAt Long Time of bank account creation
updatedAt Optional<Long> Time of last bank account update
coinbasePaymentReference Optional<String> Coinbase bank account ID for this bank account
senId Optional<String> Silvergate Network ID for this bank account
senDescription Optional<String> Silvergate Network description for this bank account
comment Optional<String> Additional comments for this bank account

BankAccountType Enum with following values (may be changed in future):

CryptoAddresses

Field Data type Description
cryptoAddresses List<CryptoAddress>

CryptoAddress

Field Data type Description
cryptoAddressId String Unique crypto address identifier
accountId String Unique account identifier
organizationId Optional<String> Unique identifier of the organisation including the related account
currency Currency Crypto address currency
mainCurrency Optional<Currency> Currency of main blockchain (e.g. may be BTC or ETH for USDT currency)
name String Crypto address name
address String
destinationTag Optional<Long> Destination tag (for XRP addresses)
memo Optional<String> Address memo (if any)
lastUsedAt Optional<Long> Time of last usage of the crypto address
createdBy String User ID of the crypto address creator
updatedBy Optional<String> User ID of the last crypto address updater
createdAt Long Time of crypto address creation
updatedAt Optional<Long> Time of last crypto address update

Get whitelisted crypto addresses

+ GET /platform/crypto-addresses

This method allows to retrieve information about all whitelisted crypto addresses related to the account. The method does not require any request fields.

Required permissions: View Make sure you have granted access to definite portfolios: you will not be able to retrieve any account information of your API key is not assigned to this account while created.

Properties

+ Response 200 (application/json)
{
  'cryptoAddresses': [
    {
      'accountId': 'c0576ce4-00aa-4bdc-82fb-c4101fbe491b',
      'address': 'SomeBTCwalletAddress',
      'createdAt': '1567522689656',
      'createdBy': 'd4248500-5f57-4199-8f5e-6512ff075a52',
      'cryptoAddressId': 'ck03yjay5000a215urupkajfa',
      'currency': 'BTC',
      'isWhitelist': True,
      'lastUsedAt': '1606237167221',
      'mainCurrency': 'BTC',
      'name': 'SomeBTCwallet',
      'organizationId': '123456'
    }
  ]
}

Request

The method request does not have any optional parameters.

Response

The main field of the method response is "CryptoAddresses" including following model:

Field Data type Description
cryptoAddressId String Unique crypto address identifier
accountId String Unique account identifier
organizationId Optional<String> Unique organization identifier
currency Currency Crypto address currency
mainCurrency Optional<Currency> Currency of main blockchain (e.g. may be BTC or ETH for USDT currency)
name String Name of the crypto address
address String Address string
destinationTag Optional<Long> Destination tag (for XRP addresses)
memo Optional<String> Address memo (if any)
lastUsedAt Optional<Long> Time of last usage of the crypto address
createdBy String User ID of the crypto address creator
updatedBy Optional<String> User ID of the crypto address creator
createdAt Long Time of crypto address creation
updatedAt Optional<Long> Time of the last crypto address update

Download account reports

+ POST /platform/reports/wallets/{report-type}

This method is designed for generation of an account report. The method required the report-type string in the endpoint:

Request

The request header of this method may include following field:

Field Data type Description
Accept Optional <String> Set to application/zip and the generated binary report file is contained within a .zip file format. This is now the recommend approach when downloading account reports.

The request body of this method includes following fields:

Field Data type Description
dateFrom Long Timestamp in milliseconds for the initial report entry
dateTo Long Timestamp in milliseconds for the last report entry
organizationId Optional <String> Filter entries by a definite organisation identifier
organizationId Optional <String> Filter entries by a definite portfolio identifier
portfolioIds Optional Set<String> Filter entries by a number of portfolio identifiers
portfolioTypes Optional Set<PortfolioType> Filter entries by a number of portfolioType

Response

The return field of the method is "fileID" string containing the relative path to the generated report.

+ Response 201 Created
  {
    "fileId": "wallets-snapshots/30c1464a6774d85b1a5802d15826c7ad.xlsx"
  }

Alternatively, when Accept header is set to application/zip shell + Response 201 Created { "fileId": "wallets-snapshots/30c1464a6774d85b1a5802d15826c7ad.zip" }

To download the generated report, use the subsequent method GET /platform/files/{fileId}. In response, you will receive the binary content of the file.

Note: You may receive a 404 (Not Found Error), even if the relative path is correct. This occurs while the report is not fully generated. Carry on pulling this route until you receive the 200 OK response.

Shared Order API methods

This section includes the most common operations with the Copper platform API unified for the subsequent sections:

Operations with orders (create, cancel) are described in the corresponding sections above as well but include links to the models in this section and operation-specific examples.

Also, each subsequent section includes specific order statuses.

Retrieve orders

+ GET /platform/orders

Required API Key permissions: View

Properties

+ Response 200 (application/json)
  {
    "orders": [
      {
        "orderId": "36097872",
        "externalOrderId": "ckr4t9gfp00113b5z94j02dlo",
        "status": "executed",
        "orderType": "withdraw",
        "portfolioId": "ckmx8iv1s001o3g5zenbx1ku3",
        "portfolioType": "custody",
        "accountId": "29af7ea0-5878-4a6a-93de-6647e0d287fa",
        "amount": "0.031685614938804011",
        "baseCurrency": "ETH",
        "mainCurrency": "ETH",
        "extra": {
          "toPortfolioId": "ckr4sbit000153f5zz3frjta8",
          "transactionRequest": {
            "publicKeyHash": "f7486bca5ccacacc88b72460448da45b5da1e35bbf00a9fbf7b8866591e06b79",
            "currency": "ETH",
            "mainCurrency": "ETH",
            "amount": "31685614938804011",
            "toAddress": "0xcf76cc2abf1f4c09543d75213f5614ceae1e5ad6",
            "includeFee": true,
            "transactionRequest": {
              "fee": "672000000000000",
              "outputs": [
                {
                  "value": "31685614938804011",
                  "address": "0xcf76cc2abf1f4c09543d75213f5614ceae1e5ad6"
                }
              ],
              "gasLimit": "21000",
              "gasPrice": "32000000000",
              "sequence": "7",
              "includeFee": true,
              "nonceNumber": "26"
            }
          },
          "toAddress": "0xcf76cc2abf1f4c09543d75213f5614ceae1e5ad6",
          "reportingCurrencyRate": "1972.3",
          "terminatedReportingCurrencyRate": "1972.3",
          "feesPercent": "0",
          "transactionId": "0x4c360211513c43681e8bb94e4d6bf01b32d35408b4a73d10f01a8257975fdfe7",
          "partSigned": {
            "uploadBy": "6bc831ef-277b-4299-8c7e-0b1364a1e853",
            "transaction": {
              "type": "part-signed-tx",
              "value": "12woxmfrcjsk3Msdf8w="
            },
            "orderId": "36097872",
            "partSignNumber": "1"
          },
          "signed": {
            "uploadBy": "system",
            "transaction": {
              "txId": "0x4c360211513c43681e8bb94e4d6bf01b32d35408b4a73d10f01a8257975fdfe7",
              "txRaw": "0xf86b0785077359400082520894cf76cc2abf1f4c09543d75213f5614ceae1e5ad6876e2eb7eda0cf2b8026a0ebf8e073ed2a379cde913f3f3e4e124710e9ba5fa18c6918526921203d5c051aa030906cc6408fb52c48d27668b56722ee90b3e5aaeffd1e4481093d3dfd8e37eb"
            },
            "orderId": "36097872"
          },
          "feeLevel": "low",
          "includeFeeInWithdraw": true,
          "withdrawFee": "0.000672",
          "blockchainTransactionType": "send",
          "estimatedFees": {
            "fee": "0.000672",
            "feeCurrency": "ETH",
            "estimatedTime": "600000",
            "reportingCurrencyRate": "1972.3",
            "gasPriceGwei": "32",
            "gasLimit": "21000"
          }
        },
        "createdBy": "6bc831ef-277b-4299-8c7e-0b1364a1e853",
        "organizationId": "1234567",
        "createdAt": "1626347420199",
        "updatedAt": "1636559739474",
        "terminatedAt": "1626347556431"
      }
    ]
  }

Request

The request of the method can have following optional parameters:

Parameter Data type Description
externalOrderId Optional <String> Filter by external order ID: in this case, the list will be returned with one item or empty if nothing is found
organizationId Optional <String> Filter by organization ID: in this case, the list will be returned with one item or empty if nothing is found
portfolioId Optional <String> Return orders that are related to this portfolio
portfolioType Optional Set<PortfolioType> Return orders that are related to specified portfolio types. If multiple types set, they should be comma-separated.E.g. trading,custody
currency Optional <String> Filter by the order currency
orderType Optional Set<OrderType> Filter by order type. If multiple types set, they should be comma-separated.E.g. buy,sell
limit Optional <Integer> Limit output of the orders: 1000 by default, max. 2000
offset Optional <Integer> an offset between the beginning of the deposit target list and a first displayed element; 0 by default
isArchived Optional<Boolean> false (default value) - the requested account is active, true - the requested account is archived
updatedSince Optional <String> Timestamp in milliseconds returning all orders updated since a requested timestamp and sorted in ASC (oldest first)
createdSince Optional <String> Timestamp in milliseconds returning all orders created since a requested timestamp
terminatedAtFrom Optional <Long> Timestamp in milliseconds returning all orders terminated since a requested timestamp
terminatedAtTo Optional <Long> Timestamp in milliseconds returning all orders terminated before a requested timestamp
baseCurrency Optional <Currency> Filter by the order base currency
mainCurrency Optional <Currency> Filter by blockchain main currency
quoteCurrency Optional <Currency> Filter by the order quote currency
transferChainId Optional <String> Filter by the identifier of the transfer blockchain
transactionId Optional <String> Filter by the identifier of a certain transaction

Please note that orders in the response are sorted by the createdAt timestamp in DESC (newest first) order. This is the case unless an updatedSince search parameter is provided, which changes the sorting order to ASC (oldest first) by the updatedAt timestamp.

If no parameters are set in the request, the response will contain the latest 1000 orders.

Response

The response of the method contains the orders list, each order includes the fields according to the order model: See Order

Retrieve an order by id

+ GET /platform/orders/{orderId}

This method allows to retrieve an order by its id

Properties

+ Response 200 (application/json)
  {
    "orderId": "36097872",
    "externalOrderId": "ckr4t9gfp00113b5z94j02dlo",
    "status": "executed",
    "orderType": "withdraw",
    "portfolioId": "ckmx8iv1s001o3g5zenbx1ku3",
    "portfolioType": "custody",
    "accountId": "29af7ea0-5878-4a6a-93de-6647e0d287fa",
    "amount": "0.031685614938804011",
    "baseCurrency": "ETH",
    "mainCurrency": "ETH",
    "extra": {
      "toPortfolioId": "ckr4sbit000153f5zz3frjta8",
      "toAddress": "0xcf76cc2abf1f4c09543d75213f5614ceae1e5ad6",
      "reportingCurrencyRate": "1972.3",
      "terminatedReportingCurrencyRate": "1972.3",
      "feesPercent": "0",
      "transactionId": "0x4c360211513c43681e8bb94e4d6bf01b32d35408b4a73d10f01a8257975fdfe7",
      "feeLevel": "low",
      "includeFeeInWithdraw": true,
      "withdrawFee": "0.000672",
      "blockchainTransactionType": "send"
    },
    "createdBy": "6bc831ef-277b-4299-8c7e-0b1364a1e853",
    "organizationId": "1234567",
    "createdAt": "1626347420199",
    "updatedAt": "1636559739474",
    "terminatedAt": "1626347556431"
  }

Response

See Order

Approve an order

+ PATCH /platform/orders/{orderId}

+ Header
  Content-Type: application/vnd.co-sign-order+json

+ Response 200 OK (application/json)

This method allows to approve an order in co-sign-require status

Properties

Response

This method returns an empty JSON object.

Cancel an order

+ PATCH /platform/orders/{orderId}

+ Header
  Content-Type: application/vnd.cancel-order+json

+ Request
  {}

This method allows to cancel an issued withdrawal or buy/sell order.

Properties

Response

This method returns an empty JSON object.

Validate a blockchain address

+ POST /platform/address-validations

This method allows to check if an entered blockchain address is valid (exists in a specified blockchain).

The method is functional for all blockchains supported by Copper.

Required API Key permissions: View

Properties

+ POST /platform/address-validations

+ Request
  {
    "address": "1CN8YbBhamkB62fq2BbR8BAq1HQ5cL4af4",
    "mainCurrency": "BTC",
    "currency": "BTC"
  } 

+ Response 200 OK (application/json)
  {
    "valid": "true"
    "address": "1CN8YbBhamkB62fq2BbR8BAq1HQ5cL4af4",
    "mainCurrency": "BTC",
    "currency": "BTC"
  }

Request

The request body of this method includes following fields:

Field Data type Description
mainCurrency String Blockchain main currency.
currency String Blockchain address currency.
address String Blockchain address to validate.

Response

The response body of this method includes following fields:

Field Data type Description
valid Boolean Address validation result.
mainCurrency Optional<Currency> Blockchain main currency.
currency Optional<Currency> Blockchain address main currency.
address Optional<String> Blockchain address that has been validated.

Trading API

Get token pairs for trading

+ GET /platform/pairs?eotc=true

+ Response 200 OK
  {
    "currenciesPairs": [
      {
        "baseCurrency": "AAVE",
        "quoteCurrency": "BTC",
        "tags": [
          "stream",
          "rfq"
        ]
      },
      {
        "baseCurrency": "AAVE",
        "quoteCurrency": "USD",
        "tags": [
          "rfq"
        ]
      }
    ]
  }

This method allows to obtain the token pairs available for trading operations.

Required API Key permissions: View

Request

The method request can include the boolean eotc parameter for filtering. It specifies if a definite token pair is available for Trading orders.

Response

The method response includes the currenciesPairs with following fields:

Field Data type Description
baseCurrency Currency Base currency
quoteCurrency Currency Quote currency
tags Array<String> Tags reflecting availability of the token pair for eotc and rfq orders

tags

The tags field can include following:

Place a trading offer


+ POST /platform/offers

+ Request
  {
    "portfolioId": "182be0c5cdcd5072bb1864cdee4d3d6e",
    "limitType": "rfq",
    "orderType": "buy",
    "baseCurrency": "BTC",
    "quoteCurrency": "USD",
    "amount": "0.01"
  } 

+ Response 201 Created
{
    "offerId": "284775",
    "status": "new",
    "orderType": "buy",
    "limitType": "rfq",
    "portfolioId": "182be0c5cdcd5072bb1864cdee4d3d6e",
    "amount": "0.01",
    "baseCurrency": "BTC",
    "quoteCurrency": "USD",
    "feesPercent": "0.05",
    "createdBy": "f68fd5f7-d740-47fe-8673-80e6111112eb",
    "createdAt": "1634819150709",
    "expiredAt": "1634819750709"
}

This method allows to place a trading offer to buy or sell currency.

Required API Key permissions: Trading

Request

To place a trading offer, the method should include following fields:

Field Data type Description
portfolioId String Identifier of the portfolio to trade from
limitType LimitType The limit type of the order. Acceptable rfq
orderType OrderType The type of the order. Acceptable buy or sell
baseCurrency Currency Base currency
quoteCurrency Currency Quote currency
amount Optional<BigDecimal> Amount of asset to trade (related to baseCurrency)
quoteAmount Optional<BigDecimal> Amount of asset to trade (related to quoteCurrency). Can be used to request a token price instead of the amount field.

To get the price of the placed offer, this method does not require any additional fields, but requires the offerId parameter of the placed offer.

Response

In the response, the method returns following fields:

Field Data type Description
offer String Identifier of the placed offer
limitType LimitType The limit type of the order.
orderType OrderType The type of the order.
baseCurrency Currency Base currency
quoteCurrency Currency Quote currency
amount Optional<BigDecimal> Amount of asset to trade (related to baseCurrency)
quoteAmount Optional<BigDecimal> Amount of asset to trade (related to quoteCurrency). Can be used to request a token price instead of the amount field.

Get the price of the placed Trading offer

+ GET /platform/offers/{offerId}

+ Response 200 OK

  {
      "offerId": "284775",
      "status": "working",
      "orderType": "sell",
      "limitType": "rfq",
      "portfolioId": "182be0c5cdcd5072bb1864cdee4d3d6e",
      "amount": "0.01",
      "quoteAmount": "647.81990000",
      "baseCurrency": "BTC",
      "quoteCurrency": "USD",
      "price": "64781.99",
      "feesPercent": "0.05",
      "createdBy": "f68fd5f7-d740-47fe-8673-80e6111112eb",
      "createdAt": "1634819150709",
      "expiredAt": "1634819157222"
  }

This method allows to get the price and additional data of the placed offer.

Required permissions: View

Create a trading order

+ POST /platform/orders

+ Request (application/json)
  {
    "externalOrderId": "F7FCCFD3-B61B-4467-B456-B0FC27CE4494",
    "offerId": "8822",
    "orderType": "buy",
    "baseCurrency": "BTC",
    "quoteCurrency": "USD",
    "amount": "5",
    "portfolioId": "oishiphoosaipho9ooTikohk5foo4Wah",
    "limitType": "rfq",
    "description": "Some description"
  }
+ Response 201 (application/json)
  {
    "orderId": "28",
    "externalOrderId": "B9185DA7-EBC4-467B-B515-0B8D95B5D624",
    "baseCurrency": "BTC",
    "quoteCurrency": "USD",
    "orderType": "buy",
    "amount": "5",
    "status": "executed",
    "portfolioId": "oishiphoosaipho9ooTikohk5foo4Wah",
    "organizationId": "1234567890",
    "limitType": "rfq",
    "priceLimit": "64045.67",
    "createdAt": "1536854681576",
    "createdBy": "test-user1",
    "extra": {}
  }

This method allows to create an order to buy or sell cryptocurrency.

Required API Key permissions: Trading

Properties

Request

This request should include the `following:

Field Data type Description
externalOrderId String Unique order identifier from client (should be unique for the portfolio, cannot be blank)
orderType OrderType The type of the order. Acceptable buy or sell
portfolioId String Unique identifier of the portfolio, for which the order will be created
baseCurrency Currency Base currency
quoteCurrency Currency Quote currency
amount Optional<BigDecimal> Amount of asset to trade (related to baseCurrency)
quoteAmount Optional<BigDecimal> Amount of asset to trade (related to quoteCurrency). Can be used to request a token price instead of the amount field.
limitType LimitType The limit type of the order. Acceptable rfq
offerId String Offer identifier
description Optional<String> Arbitrary description allowing to identify an order.

Response

See Order

Copper Network API

This section describes the workflows with the use of Copper Network.

Retrieve Copper Network participant

+ GET /platform/organizations/{organizationId}/counterparties

+ Response 200 OK:
{
    "counterparties": [
        {
            "counterpartyId": "e9caae7f-2b69-4513-b909-31531e07ad98",
            "counterpartyName": "Copper",
            "imageId": "counterparties/logos/725179f3d6bda5d8ae43e4681ba530725c8a1837dbf034474a61af27120a85caec.svg",
            "counterpartyType": "public",
            "backgroundImageId": "counterparties/backgrounds/defaults/5.png",
            "isCustody": true
        }
    ]

Retrieve the list of Copper Network Participants available for your organization

Required API Key permissions: Trading

Properties

Request

The request may include following filtering options:

Field Data Description
organizationId String Unique identifier of a counterparty on the Copper platform
search String String used to find one or more counterparties according to their counterpartyName. This string can include minimum three characters.
counterpartyPortfolioId String Unique portfolio identifier of a counterparty organisation used for OTC trading

Response

See Counterparties

Settle via Copper Network

Get currencies and tokens supported for trading

+ GET /platform/currencies?tags=show-trading

+ Response 200 OK:
 {
   "currencies": [
     {
       "currency": "ETC",
       "mainCurrency": "ETC",
       "name": "Ethereum Classic",
       "priority": "0",
       "confirmations": "120",
       "decimal": "18",
       "tags": [
         "show-trading"
       ]
     }
   ]
 }

The GET /platform/currencies method allows to obtain the list of currencies supported by the Copper platform. In order to get a list of currencies supported for trading, use the show-trading tag. The complete example is provided on the right panel.

Required permissions: View

Create a settle order via Copper Network

+ POST /platform/orders

+ Request
 {
   "externalOrderId": "F7FCCFD3-B61B-4467-B456-B0FC27CE4494",
   "orderType": "buy",
   "baseCurrency": "BTC",
   "quoteCurrency": "USD",
   "amount": "5",
   "portfolioId": "46",
   "limitType": "otc",
   "priceLimit": "3300.57",
   "toCounterpartyId": "e9caae7f-2b69-4513-b909-31531e07ad98",
   "description": "Some description"
 }  

+ Response 201 (application/json)
  {
     "orderId": "35981617",
     "externalOrderId": "F7FCCFD3-B61B-4467-B456-B0FC27CE4494",
     "status": "waiting-counterparty-approve",
     "orderType": "buy",
     "portfolioId": "46",
     ... 
   }

Required API Key permissions: Trading

Properties

Request

This request should include the following:

Field Data type Description
externalOrderId String Unique order identifier from client (should be unique for the portfolio)
orderType OrderType The type of the order. Acceptable buy or sell
portfolioId String Unique identifier of the portfolio, for which the order will be created
toCounterpartyId String Unique identifier of the counterparty
amount BigDecimal Order execution amount
baseCurrency Currency Currency of the amount
quoteCurrency Currency Trading quote currency
mainCurrency Optional<Currency> Currency defining a blockchain network for baseCurrency
quoteMainCurrency Optional<Currency> Currency defining a blockchain network for quoteCurrency
limitType LimitType The limit type of the order. Acceptable otc
priceLimit BigDecimal Price of a settle order
description Optional<String> Arbitrary description allowing to identify an order.
Response

See Order

Accept an OTC order (from the counterparty side)

+ PATCH /platform/orders/{counterpartyOrderId}

+ Header
  Content-Type: application/vnd.approve-counterparty-otc+json

+ Response 200 OK (application/json)

Required API Key permissions: Trading

This method allows to accept an OTC order by its identifier specified in the endpoint. The method does not require any additional fields, as well as it returns only the standard success or error codes.

Transfer via Copper Network

Create a one way transfer order via Copper Network

+ POST /platform/orders

+ Request
 {
   "externalOrderId": "484e89d6-0124-4193-b4f8-59ba2dc91008",
   "orderType": "withdraw",
   "baseCurrency": "BTC",
   "amount": "5",
   "portfolioId": "46",
   "toCounterpartyId": "e9caae7f-2b69-4513-b909-31531e07ad98",
   "description": "Some description"
 }  

+ Response 201 (application/json)
  {
     "orderId": "35981617",
     "externalOrderId": "F7FCCFD3-B61B-4467-B456-B0FC27CE4494",
     "status": "co-sign-require",
     "orderType": "withdraw",
     "portfolioId": "46",
     ...
   }

Required API Key permissions: Withdraw

Properties

Request

This request should include the CreateOrder model specific for trading:

Field Data type Description
externalOrderId String Unique order identifier from client (should be unique for the portfolio)
orderType OrderType The type of the term of the order. Acceptable withdraw
portfolioId String Unique identifier of the portfolio, for which the order will be created
toCounterpartyId String Unique identifier of the counterparty
amount BigDecimal Order execution amount
baseCurrency Currency Currency of the amount
mainCurrency Optional<Currency> Currency defining a blockchain network for baseCurrency
description Optional<String> Arbitrary description allowing to identify an order.
Response

See Order

Approve a transfer order

+ PATCH /platform/orders/{orderId}

+ Header
  Content-Type: application/vnd.co-sign-order+json

+ Response 200 OK (application/json)

Required API Key permissions: Withdraw

This method allows to approve a Transfer order by required approves specified in withdraw limits of an organization and of a team member, by whom the transfer order has been created.

Copper Network Datamodel

Counterparties

Field Data type Description
counterparties List<Counterparty> List of counterparties

Counterparty

Field Data type Description
counterpartyId String Unique identifier of a counterparty on the Copper platform
counterpartyName String Counterparty name as shown on the Copper platform
imageId String Counterparty image on the Copper platform
counterpartyType CounterpartyType Counterparty visibility within the network
backgroundImageId String Counterparty background image used on the Copper platform (one of standard backgrounds of a counterparty card)
isCustody Boolean This parameter indicates a type of custodial instance used for OTC operations by this organisation.

Counterparty Types

Name Description
public visible for all organisations
private visible for those who knows to portfolioId linked to the Network Card
personal personal counterparty visible only for your organization
lite visible for all organisations

Settle API (without usage of Copper Network)

The legacy settling API described bellow allows you to place a Settle order by directly specifying account id of another Copper Client. It is highly recommended to use new settle API — Settle via Copper Network

Get currencies and tokens supported for OTC trading

+ GET /platform/currencies?tags=show-trading

+ Response 200 OK:
 {
   "currencies": [
     {
       "currency": "AKRO",
       "mainCurrency": "ETH",
       "name": "Akropolis",
       "priority": "0",
       "confirmations": "30",
       "decimal": "18",
       "tags": [
         "show-trading"
       ]
     },
     {
       "currency": "ETC",
       "mainCurrency": "ETC",
       "name": "Ethereum Classic",
       "priority": "0",
       "confirmations": "120",
       "decimal": "18",
       "tags": [
         "show-trading"
       ]
     }
   ]
 }

Required permissions: View

The GET /platform/currencies method allows to obtain the list of currencies supported by the Copper platform. In order to get a list of currencies supported for trading, use the show-trading tag. The complete example is provided on the right panel.

Create a settle order

+ POST /platform/orders

+ Request
 {
   "externalOrderId": "F7FCCFD3-B61B-4467-B456-B0FC27CE4494",
   "orderType": "buy",
   "baseCurrency": "BTC",
   "quoteCurrency": "USD",
   "amount": "5",
   "portfolioId": "46",
   "limitType": "otc",
   "priceLimit": "3300.57",
   "counterpartyPortfolioId": "53453",
   "description": "Some description"
 }  

+ Response 201 (application/json)
  {
     "orderId": "35981617",
     "externalOrderId": "F7FCCFD3-B61B-4467-B456-B0FC27CE4494",
     "status": "waiting-counterparty-approve",
     "orderType": "buy",
     "portfolioId": "46",
     ...
     "extra": {
       ...
       "counterpartyOrderId": "35981618",   # A counterparty has to approve this order manually or via the API
       ...
     },
   }

Required API Key permissions: Trading

Properties

Request

This request should include the following:

Field Data type Description
externalOrderId String Unique order identifier from client (should be unique for the portfolio)
orderType OrderType The type of the order. Acceptable buy or sell
portfolioId String Unique identifier of the portfolio, for which the order will be created
counterpartyPortfolioId String Unique identifier of the portfolio, which will receive the opposite order
amount BigDecimal Order execution amount
baseCurrency Currency Currency of the amount
quoteCurrency Currency Trading quote currency
mainCurrency Optional<Currency> Currency defining a blockchain network for baseCurrency
quoteMainCurrency Optional<Currency> Currency defining a blockchain network for quoteCurrency
limitType LimitType The limit type of the order. Acceptable otc
priceLimit BigDecimal Price of a settle order
description Optional<String> Arbitrary description allowing to identify an order.

Response

See Order

Accept an OTC order

+ PATCH /platform/orders/{counterpartyOrderId}

+ Header
  Content-Type: application/vnd.approve-counterparty-otc+json

+ Response 200 OK (application/json)

Required API Key permissions: Trading

This method allows to accept an OTC order by its identifier specified in the endpoint. The method does not require any additional fields, as well as it returns only the standard success or error codes.

Transfer API

Create withdraw order

+ POST /platform/orders

This method creates a deposit or withdraw order on the Copper platform.

Required API Key permissions: Withdraw

Properties

+ Request (application/json)
  {
    "externalOrderId": "be70d9a8-2290-4692-9592-0fd572f6e864",
    "orderType": "withdraw",
    "baseCurrency": "XRP",
    "mainCurrency": "XRP",
    "amount": "10",
    "feeLevel": "low",
    "includeFeeInWithdraw": false,
    "portfolioId": "9a7b6398-d4ac-4b26-ab62-f4dd7396aedb",
    "toAddress": "rwCQk17fhC8G9UCoMgaxsEQb6fVy8HhUY6",
    "description": "Some description"
  }

+ Response 201 (application/json)
  {
    "orderId": "14703607",
    "externalOrderId": "be70d9a8-2290-4692-9592-0fd572f6e864",
    "status": "co-sign-require",
    "orderType": "withdraw",
    "portfolioId": "9a7b6398-d4ac-4b26-ab62-f4dd7396aedb",
    "portfolioType": "trading",
    "accountId": "d961e420-cbcf-4642-83fd-82b184828a1e",
    "amount": "10",
    "baseCurrency": "XRP",
    "mainCurrency": "XRP",
    "extra": {
      "description": "Some description",
      "toAddress": "rwCQk17fhC8G9UCoMgaxsEQb6fVy8HhUY6",
      "coSignersNumber": "2",
      "coSigners": [
        "cc1bafa6-eb87-4a1e-ae6d-d27d0ea921aa"
      ],
      "feesPercent": "0",
      "feeLevel": "low",
      "includeFeeInWithdraw": false
    },
    "createdBy": "cc1bafa6-eb87-4a1e-ae6d-d27d0ea921aa",
    "organizationId": "PSHENKIN",
    "createdAt": "1572984084262",
    "updatedAt": "1572984084447"
  }

Request

This request should include the CreateOrder model specific for withdrawals:

Field Data type Description
externalOrderId String Unique order identifier from client (should be unique for the portfolio, should not be blank)
orderType OrderType The type of the order. Use withdraw
portfolioId String Unique identifier of the portfolio, for which the order will be created
amount BigDecimal Order execution amount
baseCurrency Currency Currency for the amount
mainCurrency Optional<Currency> Currency of main blockchain (e.g. for USDT, it could be either ETH or BTC currency)
toAddress Optional<String> Withdraw address
toCryptoAddressId Optional<String> Withdraw crypto address identifier
toBankAccountId Optional<String> Withdraw bank account identifier
toPortfolioId Optional<String> Withdraw portfolioId identifier
destinationTag Optional<Long> Withdraw destination tag
memo Optional<String> Withdraw memo
withdrawalPassword Optional<String> Withdraw password for External portfolio (sha256 hash string)
description Optional<String> Arbitrary description allowing to identify an order.

Response

See Order

Create bulk Bitcoin transfer order

+ POST /platform/orders

This method creates a single withdraw order that moves the funds from a wallet to multiple wallets. This order should be signed once and requires paying one fee.

Note: This method supports only bitcoin transactions.

Required API Key permissions: Withdraw

Properties

+ Request (application/json)
    {
    "externalOrderId": "4e9dd69c-efd5-11ed-a05b-0242ac120010",
    "orderType": "multi-withdraw",
    "baseCurrency": "BTC",
    "mainCurrency": "BTC",
    "feeLevel": "low",
    "includeFees": false,
    "includeFeeInWithdraw": false,
    "portfolioId": "ckx0ddhzu000g3e64xlzh4522",
    "toReceivers": [
        {
          "toAddress": "mqJTMqUDRKM7ZjfzBX1oCXWerXNVsb8rx0",
          "amount": "0.001"
        },
        {
          "toPortfolioId": "cktwyhom0003c3a60wpx31a12",
          "amount": "0.002"
        },
        {
          "toCryptoAddressId": "cl4h3ogpo000u3b5nm78ecl11",
          "amount": "0.003"
        }
      ]
  }

+ Response 201 (application/json)
{
    "orderId": "1891",
    "externalOrderId": "4e9dd69c-efd5-11ed-a05b-0242ac120010",
    "status": "awaiting-settlement",
    "orderType": "multi-withdraw",
    "portfolioId": "ckx0ddhzu000g3e64xlzh4522",
    "portfolioType": "custody",
    "accountId": "34b1f836-2b0c-45ca-af6a-50e33c0f3100",
    "amount": "0.003",
    "baseCurrency": "BTC",
    "mainCurrency": "BTC",
    "extra": {
        "reportingCurrencyRate": "27422.965281279696",
        "includeFeeInWithdraw": false,
        "blockchainTransactionType": "multi-withdraw",
        "estimatedFees": {
            "fee": "0.0000026",
            "feeCurrency": "BTC",
            "estimatedTime": "7200000",
            "reportingCurrencyRate": "27422.965281279696",
            "transactionBytes": "260",
            "feePerByte": "1"
        },
        "includeFees": false,
        "toReceivers": [
            {
                "toAddress": "mqJTMqUDRKM7ZjfzBX1oCXWerXNVsb8rx0",
                "amount": "0.001"
            },
            {
                "toPortfolioId": "cktwyhom0003c3a60wpx31a12",
                "toAddress": "mzpZ5m6fm4dFyDknWMkVH6Mm5yGDoXr400",
                "amount": "0.002"
            },
            {
                "toAddress": "mv7vPkkHTSQmvog6tUWWuTZBy4Aher6123",
                "amount": "0.003"
            }
        ]
    },
    "createdBy": "b2270629-5917-433a-93dc-aae28e190b00",
    "organizationId": "CRP",
    "createdAt": "1683797101156",
    "updatedAt": "1683797101522"
}

Request

This request should include the CreateOrder model specific for bulk bitcoin withdrawals:

Field Data type Description
externalOrderId String Unique order identifier from client (should be unique for the portfolio, should not be blank)
orderType OrderType The type of the order. Use multi-withdraw
portfolioId String Unique identifier of the portfolio, for which the order will be created
baseCurrency Currency Currency for the amount. Use BTC
mainCurrency Optional<Currency> Currency of main blockchain. Use BTC
toReceivers toReceivers Array of JSON objects (see the variants below)
destinationTag Optional<Long> Withdraw destination tag
memo Optional<String> Withdraw memo
withdrawalPassword Optional<String> Withdraw password for External portfolio (sha256 hash string)
description Optional<String> Arbitrary description allowing to identify an order.

toReceivers array contains the JSON objects. Each JSON object contains two fields: one address field and the amount field:

Field Data type Description
amount BigDecimal The amount of funds to transfer

To specify the address use one of the following address fields:

Field Data type Description
toAddress Optional<String> Withdraw address
toCryptoAddressId Optional<String> Withdraw crypto address identifier
toPortfolioId Optional<String> Withdraw portfolioId identifier

Response

See Order

Dry-run for withdrawal orders

+ POST /platform/dry-run-orders

+ Request 
  {
    "orderType": "withdraw",
    "baseCurrency": "BTC",
    "amount": "0.02",
    "portfolioId": "9a7b6398-d4ac-4b26-ab62-f4dd7396aedb",    
    "toAddress": "rwCQk17fhC8G9UCoMgaxsEQb6fVy8HhUY6"
  }

This method performs a test run of a withdraw order and checks data you are going to enter. Currently, the method works for ETH itself, ETH tokens and for BTC.

Required API Key permissions: Withdraw

Properties

+ Response 200
{
    "orderType": "withdraw",
    "portfolioId": "ck8owwcvj000f3j5wrjoyip4d",
    "amount": "0.0001",
    "baseCurrency": "ETH",
    "extra": {
        "toAddress": "0x023ac7b2faeb5275e1c2868d107ae38978b34764",
        "estimatedFees": {
            "fee": "0.001344",
            "estimatedTime": "600000",
            "feeCurrency": "ETH",
            "gasPriceGwei": "64",
            "gasLimit": "21000"
        }
    }
}

Request

This request should include the following:

Field Data type Description
orderType OrderType The type of the order. Acceptable withdraw
portfolioId String Unique identifier of the portfolio, for which the order will be created
amount BigDecimal Order execution amount
baseCurrency Currency Currency for the amount
mainCurrency Optional<Currency> Currency of main blockchain (e.g. for USDT, it could be either ETH or BTC currency)
toAddress Optional<String> Withdraw address
toCryptoAddressId Optional<String> Withdraw crypto address identifier
toBankAccountId Optional<String> Withdraw bank account identifier
toPortfolioId Optional<String> Withdraw portfolioId identifier
destinationTag Optional<Long> Withdraw destination tag
memo Optional<String> Withdraw memo
withdrawalPassword Optional<String> Withdraw password for External portfolio (sha256 hash string)

Response

The method returns the details of the dry-run order:

Field Data type Description
orderType OrderType The type of the order. Acceptable withdraw
portfolioId String Unique identifier of the portfolio, for which the order will be created
amount BigDecimal Order execution amount
baseCurrency Currency Currency of the amount
mainCurrency Optional<Currency> Currency of main blockchain (e.g. for USDT, it could be either ETH or BTC currency)
extra Optional<OrderExtra> Additional order data

Deposit API

The Deposit API includes methods for creation and operations with Deposit Targets.

Create a new Deposit Target

+ POST /platform/deposit-targets

+ Request
    {
        "externalId": "[[external id]]",
        "portfolioId": "[[portfolio id]]",
        "currency": "USDT",
        "mainCurrency": "ALGO",
        "name": "Algo Wallet",
        "metadata": {
          "tags": ["test"]
        }
    }

This method creates a new Deposit Target.

Required API Key permissions: Trading or Withdraw

Properties

+ Response
    {
        "depositTargetId": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
        "externalId": "[[external Id]]",
        "portfolioId": "[[portfolio id]]",
        "portfolioType": "trading",
        "organizationId": "TEST",
        "targetType": "proxy",
        "name": "Algo Wallet",
        "address": "BIVPTF7GFBMYA3EUYCUIHRSE5F2IKVX4LDJNZEHDTQZPGFHE6AKGZXMZLY",
        "memo": "123",
        "status": "enabled",
        "mainCurrency": "ALGO",
        "createdBy": "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed",
        "updatedBy": "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed",
        "metadata": {
          "tags": ["test"]
        },
        "acceptAllTokens": true,
        "requireTokensActivation": true,
        "activatedTokens": [
            {
                "currency": "USDT",
                "status": "pending"
            }
        ]
    }

Request

The request body of the method includes the depositTarget model:

Field Data type Description
externalId String Unique external identifier (enter manually)
portfolioId String Identifier of a portfolio where a new Deposit Target will be created
currency Currency Deposit Target currency (standard exchange ticker)
mainCurrency Currency Deposit Target blockchain main currency (standard exchange ticker)
name Optional<String> Arbitrary name of a new Deposit Target (will be shown in the UI)
metadata Optional<Object> JSON object with any additional metadata you want to store with a new Deposit Target (will be shown in the API only)

Response

The response of the method includes following fields:

Field Data type Description
depositTargetId UUID Unique Deposit Target identifier
externalId String Unique external identifier
portfolioId String Identifier of a Deposit Target portfolio
portfolioType PortfolioType Portfolio type
organizationId String Unique identifier of an organisation which uses this portfolio
targetType DepositTargetTypeEnum Target type (see below)
address String Address of Deposit Target
memo Optional<String> Memo of Deposit Target
status DepositTargetStatusEnum Deposit Target status
currency Optional<Currency> If an address is same for MainCurrency and all tokens, this field can be left empty
mainCurrency Currency Deposit Target main currency (standard exchange ticker)
createdBy String User ID of a Deposit Target creator
updatedBy String ID of a user who has made last Deposit Target update
createdAt Long Time of Deposit Target creation
updatedAt Long Time of the latest target update
name Optional<String> Name of the created Deposit Target
metadata Object JSON object with any additional metadata that you want to store with Deposit Target
acceptAllTokens Boolean This parameter defines if this target is able to accept all tokens - for instance, this parameter is true for ETH Deposit Targets
requireTokensActivation Boolean true If this target can accept all tokens, but each token requires additional activation
activatedTokens Optional<List<ActivatedToken>> If tokens of a blockchain should be activated prior to any operation, this parameter includes a list of currencies to be activated with corresponding status - otherwise, the field is set as null

DepositTargetTypeEnum

Enum describing type of Deposit Target:

DepositTargetStatusEnum Enum describing a current status of a particular Deposit Target with following possible values (the values can be changed in the future):

ActivatedToken The list containing array of activatedToken includes following values for each Deposit Target token:

Field Data type Description
currency Currency token currency
status DepositTargetStatusEnum activation status (see above)

Get list of organisation Deposit Targets

+ GET /platform/deposit-targets?currency=ALGO&mainCurrency=ALGO&limit=1&offset=0

This method retrieves information on all Deposit Targets of the organisation. Deposit Targets are sorted by the createdAt criteria (creation timestamp).

Required API Key permissions: Trading or Withdraw

Properties

+ Response 200 (application/json)
  {
    "depositTargets": [
        {
          "depositTargetId" : "fe8eeea7-f21c-450f-9331-d779eecb5242",
          "externalId" : "hohodiggenapgatofocn-wallet-ALGO-activation",
          "portfolioId" : "hohodiggenapgatofocn",
          "portfolioType" : "custody",
          "organizationId" : "TEST",
          "targetType" : "direct",
          "address" : "J43B6OALMJRNMHLMVURTTEHQ65IOIGI7YMJV26RJF7P6WG5LPBRSBR75LA",
          "status" : "enabled",
          "mainCurrency" : "ALGO",
          "createdBy" : "admin",
          "updatedBy" : "admin",
          "createdAt" : "a3a2ddb4-3e74-4fbf-beeb-a9ea39d9fc4d",
          "updatedAt" : "a3a2ddb4-3e74-4fbf-beeb-a9ea39d9fc4d",
          "metadata" : { },
          "acceptAllTokens" : true,
          "requireTokensActivation" : true,
          "activatedTokens" : [ {
            "currency" : "ARCC",
            "status" : "pending"
          } ],
        }
    ],
  }

Request

The method request can include following parameters:

Field Data type Description
depositTargetId UUID Unique Deposit Target identifier
externalId Optional<String> Deposit target with specified externalId
portfolioId Optional<String> Identifier of a portfolio including the requested Deposit Targets
organizationId Optional<String> Identifier of an organisation including the requested Deposit Targets
currency Optional<String> Deposit Targets containing a specified currency
mainCurrency Optional<String> Deposit Target with a specified mainCurrency
targetType Optional<DepositTargetTypeEnum> direct or proxy
status Optional<DepositTargetStatusEnum> new, pending or enabled
sortDirection Optional<SortingDirection> ascending or descending sorting order
limit Optional<Int> 50 units by default, max. 1000 units
offset Optional<Int> an offset between the beginning of the Deposit Target list and a first displayed element; 0 by default

Response

The response of the method includes fields according to the depositTarget model:

Field Data type Description
depositTargetId UUID Unique Deposit Target identifier
externalId String Unique external identifier
portfolioId String Identifier of a Deposit Target portfolio
portfolioType PortfolioType Portfolio type (see below)
organizationId String Unique identifier of an organisation which uses this portfolio
targetType DepositTargetTypeEnum Target type (see below)
address String Address of Deposit Target
memo Optional<String> Memo of Deposit Target
status DepositTargetStatusEnum Deposit Target status
currency Optional<Currency> If an address is same for MainCurrency and all tokens, this field can be left empty
mainCurrency Currency Deposit Target main currency (standard exchange ticker)
createdBy String User ID of a Deposit Target creator
updatedBy String ID of a user who has made last Deposit Target update
createdAt Long Time of Deposit Target creation
updatedAt Long Time of the latest target update
name Optional<String> Name of the created Deposit Target
metadata Object JSON object with any additional metadata that you want to store with Deposit Target
acceptAllTokens Boolean This parameter defines if this target is able to accept all tokens - for instance, this parameter is true for ETH Deposit Targets
requireTokensActivation Boolean true If this target can accept all tokens, but each token requires additional activation
activatedTokens Optional<List<ActivatedToken>> If tokens of a blockchain should be activated prior to any operation, this parameter includes a list of currencies to be activated with corresponding status - otherwise, the field is set as null

Activate token for a Deposit Target

+ PATCH /platform/deposit-targets/{depositTargetId}

+ Header
  Content-Type: application/vnd.activate-deposit-target-currency+json

+ Request
    {
        "currency": "MCAU"
    }

This method activates a new token for a specified Deposit Target. It is required only in case when a Deposit Target accepts all tokens, but each of the accepted tokens requires activation. For instance, in the ALGO blockchain, each token should be activated separately.

Properties

+ Response
    {
        "depositTargetId": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
        "externalId": "[[external Id]]",
        "portfolioId": "[[portfolio id]]",
        "portfolioType": "trading",
        "organizationId": "TEST",
        "targetType": "proxy",
        "address": "BIVPTF7GFBMYA3EUYCUIHRSE5F2IKVX4LDJNZEHDTQZPGFHE6AKGZXMZLY",
        "memo": "123",
        "status": "enabled",
        "mainCurrency": "ALGO",
        "createdBy": "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed",
        "updatedBy": "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed",
        "metadata": {
          "tags": ["test"]
        },
        "acceptAllTokens": true,
        "requireTokensActivation": true,
        "activatedTokens": [
            {
                "currency": "USDT",
                "status": "enabled"
            },
            {
                "currency": "MCAU",
                "status": "pending"
            }
        ]
    }

Request

The endpoint of the method should include a valid Deposit Target identifier. The request body includes a currency field requiring a standard market ticker of a token to be activated.

Response

The response body includes the Deposit Target data (see above). Under the activatedToken field, you will find the activation status of the tokens.

Deposit processing

+ GET /platform/orders?limit=1&offset=0

+ Response 200 (application/json)
  {
  "orders": [
    {
      "orderId": "14694738",
      "externalOrderId": "BTC:3831041",
      "status": "waiting-approve",
      "orderType": "deposit",
      "portfolioId": "9a7b6398-d4ac-4b26-ab62-f4dd7396aedb",
      "portfolioType": "trading",
      "accountId": "d961e420-cbcf-4642-83fd-82b184828a1e",
      "amount": "19.99985645",
      "baseCurrency": "BTC",
      "mainCurrency": "BTC",
      "extra": {
        "confirmations": "2",
        "transactionId": "b408f62cd714a817af4915caf491e4fa9e753f1e2c333cca6d1fdedd511e90f3",
        "fromAddresses": ["1AkD7DkqWuV2UPZUKywM6PkSJUsr4SYuND", "14yZeGLUDrnmAWEBp3BoevYaF6EHi8jnoX"],
        "depositTargetId": "3803a59c-0652-45e9-acd0-825bfc684410",
        "transferFees": "0.00014355",
        "transferFeesCurrency": "BTC",
        "transferTransactionId": "9b7f573bcae690259fcb05bc6feceb4bd34d231d06ee5c4791c852b6815a0f24",
        "transferDepositTargetId": "9ef96061-26d6-4471-9da9-74ea711f0ec2"
      },
      "organizationId": "TESTORG",
      "createdAt": "1572981553305",
      "updatedAt": "1572981771848",
      "terminatedAt": "1572981771582"
    }
  ], 
  }

Staking API

The /platform/orders endpoint of the Copper API is used also for staking purposes. The orderType field defines the order purpose: earn-reward type for the rewards received for staking the assets.

Get staking reward orders

+ GET /platform/orders?orderType=earn-reward

This method returns the list of staking reward orders, including the orders with errors. Orders without the rewards are not included in the list.

Method: GET

Required API Key permissions: View

Properties

+ Response 200 (application/json)
  {
    "orders": [
        {
            "orderId": "36705489",
            "externalOrderId": "NEAR:f5fd82fc-199e-43d6-a2fa-2e907adb3ca6",
            "status": "executed",
            "orderType": "earn-reward",
            "portfolioId": "2CmdQOfcSx0ocqMxJGr23Bvl",
            "portfolioType": "trading-vault",
            "accountId": "52ed19ee-c4d6-40c6-be0f-c9496e06a694",
            "amount": "0.000015546001130188963516",
            "baseCurrency": "NEAR",
            "mainCurrency": "NEAR",
            "extra": {
                "reportingCurrencyRate": "1.5108232029644666",
                "terminatedReportingCurrencyRate": "1.5108232029644666",
                "balanceSnapshot": "1.8487099292701487",
                "availableSnapshot": "1.8487099292701487",
                "depositTargetId": "79379ad0-3680-4795-88f2-0d52e8d26429"
            },
            "organizationId": "SCTC",
            "createdAt": "1669118874888",
            "updatedAt": "1669119536964",
            "terminatedAt": "1669119536931"
        }
    ]
}

Request

The request can have the following optional parameters:

Parameter Data type Description
externalOrderId Optional<String> Filter by external order ID: in this case, the list will be returned with one item or empty if nothing is found
organizationId Optional<String> Filter by organization ID: in this case, the list will be returned with one item or empty if nothing is found
portfolioId Optional<String> Return orders that are related to this portfolio
currency Optional<String> Filter by the order currency
orderType Optional<String> Filter by order type: use earn-reward to view orders of earn-reward type
limit Optional<Integer> Limit output of the orders: 1000 by default, max. 2000
offset Optional<Integer> an offset between the beginning of the deposit target list and a first displayed element; 0 by default
isArchived Optional<Boolean> false (default value) - the requested account is active, true - the requested account is archived
updatedSince Optional<String> Timestamp in milliseconds returning all orders updated since a requested timetamp and sorted in ASC (oldest first)
createdSince Optional<String> Timestamp in milliseconds returning all orders created since a requested timetamp and sorted in DESC (newest first)
terminatedAtFrom Optional<Long> Timestamp in milliseconds returning all orders terminated since a requested timetamp (not sorted)
terminatedAtTo Optional<Long> Timestamp in milliseconds returning all orders terminated before a requested timetamp (not sorted)
portfolioType Optional<String> Filter the accounts by portfolio type (see the variants below)
baseCurrency Optional<String> Filter by the order base currency
transferChainId Optional<String> Filter by the identifier of the transfer blockchain
transactionId Optional<String> Filter by the identifier of a certain transaction

If no parameters are set in the request, the response will contain the latest 1000 orders.

PortfolioType Enum with the following values (may change):

Response

The response contains the orders list. Each order includes the fields according to the order model:

Field Data type Description
orderId String Unique order identifier generated upon its creation
externalOrderId String Unique order identifier passed in the request
status OrderStatus Operating status of the order
orderType OrderType Order type: earn-reward, deposit or withdraw
portfolioId String Unique identifier of the portfolio, for which the order will be created
portfolioType Enum<PortfolioType> Type of the portfolio (see the PortfolioType model below)
accountId String Account idenifier
amount BigDecimal Order execution amount
baseCurrency Currency Currency of the amount
mainCurrency Optional<Currency> Main currency of the blockchain
extra OrderExtra Additional order data including information about the corresponding blockchain transaction
createdBy Optional<String> User ID of the order creator
organizationId Optional<String> Unique ID of the organisation of the creator
createdAt Long Time of order creation
updatedAt Optional<Long> Time of the latest order update
terminatedAt Optional<Long> Time of the order termination

status

The status field can include following order statuses:

Status Description
error something went wrong, see the errorDescription field
new order has been created.
reserved required amount of funds has been reserved on the balance (for withdraw, buy and sell orders only)
working order processing
waiting-approve awaiting administrator approval (for deposit and withdrawal orders)
co-sign-require order still needs to be co-signed by an authorised organisation member
approved deposit or withdraw order has been approved by Copper’s admin, and will be processed shortly
processing waiting for the minimum required number of network confirmations from the blockchain (for withdraw orders)
executed order is completed
canceled order has been cancelled
rejected a request has been rejected by Copper’s admin, now waiting for rejection transaction signature

Create staking order

+ POST /platform/orders

This method creates a staking order on the Copper platform.

Method: POST

Required API Key permissions: Withdraw

Properties

Stake delegation order example (currency: NEAR)

+ POST /platform/orders

+ Request (application/json)
  {
    "externalOrderId": "clbam4hss000e3b6flvqb26gc",
    "baseCurrency": "NEAR",
    "mainCurrency": "NEAR",
    "orderType": "withdraw",
    "portfolioId": "JsFMjYC3FCRnAWv2Ud9MUNBm",
    "amount": "0.1",
    "blockchainTransactionType": "stake-delegation",
    "poolId": "cryptogarik.pool.f863973.m0"
  }

+ Response 201 (application/json)
{
    "orderId": "6054886",
    "externalOrderId": "clbam4hss000e3b6flvqb26gc",
    "status": "awaiting-settlement",
    "orderType": "withdraw",
    "portfolioId": "JsFMjYC3FCRnAWv2Ud9MUNBm",
    "portfolioType": "trading-vault",
    "accountId": "ab161f57-bec1-45b7-9a77-0dd33f741ef3",
    "amount": "0.1",
    "baseCurrency": "NEAR",
    "mainCurrency": "NEAR",
    "extra": {
        "reportingCurrencyRate": "1.753557057801753",
        "includeFeeInWithdraw": false,
        "blockchainTransactionType": "stake-delegation",
        "poolId": "cryptogarik.pool.f863973.m0",
        "poolName": "cryptogarik.pool.f863973.m0"
    },
    "createdBy": "a2a06805-db21-427f-94f3-67f3a779af8e",
    "organizationId": "QACS",
    "createdAt": "1670234358987",
    "updatedAt": "1670234366476"
}

Request

This request should include the CreateOrder model specific for staking:

Field Data type Description
externalOrderId String Unique order identifier from client (should be unique for the portfolio, should not be blank)
baseCurrency Currency Currency for the amount
mainCurrency Optional<Currency> Currency of main blockchain (e.g. for USDT, it could be either ETH or BTC currency)
orderType OrderType Order type: withdraw
portfolioId String Unique identifier of the portfolio, for which the order will be created. The portfolioId matches the Account ID on the Copper Platform
amount BigDecimal Order execution amount
blockchainTransactionType Optional<String> Blockchain transaction type (see the description below). send is used by default

The blockchainTransactionType is a list with the following values specific for staking orders:

Value Description
stake-delegation Delegate funds to staking or move them to other chains/wallets where it will be used for staking in future with other transactions
stake-nomination Nominate stake to specific pools
stake-undelegation Request funds back from staking to make them operable
complete-withdrawal Use to wait the unbonding period and sign transaction (required for some blockchains to get funds to operable balance after undelegation)
stake-complete-deposit Use to accept exported (via stake-delegation) transactions to perform stake operations for AVAX
take-reward Take rewards that were issued to operable balance
pool-creation Create transaction that registers new staking pool with specified vault address
unjail Unjail pool that is controlled by wallet (BSC)
importance-transfer Associate importance for XEM wallet to specific public key
transfer-stake Move stake from one pool to another
rebond-stake Stake funds in unbonding period before it ends
chill Disable active stake to get permission to unstake funds (DOT)
register-online Register ALGO funds to staking
register-offline Request ALGO funds from staking to make them operable

The blockchainTransactionType sets up the type of performed blockchain operation. Each currency has a set of available staking operations, which is shown in the table below.

Currency Staking operations
ADA pool-creation, stake-delegation, take-reward
ALGO register-offline, register-online
ATOM stake-delegation, stake-undelegation, take-reward
AVAX complete-withdrawal, stake-nomination, pool-creation, stake-complete-deposit, stake-delegation, stake-undelegation
AXL stake-delegation, stake-undelegation, take-reward
BLD stake-delegation, stake-undelegation, take-reward
BNB pool-creation, stake-delegation, stake-undelegation, unjail
CCD pool-creation, stake-delegation, stake-undelegation
DIVI stake-delegation
DOT chill, complete-withdrawal, stake-nomination, rebond-stake, stake-delegation, stake-undelegation
ETH pool-creation, stake-delegation
HNT pool-creation, stake-undelegation, transfer-stake
INJ stake-delegation, stake-undelegation, take-reward, transfer-stake
KSM chill, complete-withdrawal, stake-nomination, rebond-stake, stake-delegation, stake-undelegation
NEAR complete-withdrawal, stake-delegation, stake-undelegation
POKT stake-delegation, stake-undelegation
ROSE stake-delegation, stake-undelegation
SOL complete-withdrawal, stake-delegation, stake-undelegation
ZIL complete-withdrawal, stake-delegation, stake-undelegation, take-reward

Response

The response of the method includes the Order model.

DeFi API

This section describes the usage of /platform/orders endpoint for DeFi interactions.

Create send order with payload

+ POST /platform/orders

This method creates a send order containing a data payload field for a smart contract. The transaction can be signed using Copper Unlimited.

Required API Key permissions: Withdraw


+ Request (application/json)
{
    "amount": "0",
    "baseCurrency": "ETH",
    "externalOrderId": "464e66da-6183-44c5-a3c6-1a8655c44a95",
    "mainCurrency": "ETH",
    "orderType": "withdraw",
    "payload": "0x379607f50000000000000000000000000000000000000000000000000000000000000001",
    "portfolioId": "J4MZ46Jq27B3N74RI8tsYB5o",
    "toAddress": "0xd6cef1bce2810ca92ab2fa865283761d5bdec9e0",
    "origin": {
        "url": "https://etherscan.io",
        "icon": "https://etherscan.io/images/favicon3.ico"
    },
    "feeLevel": "low",
    "blockchainTransactionType": "send"
}

+ Response 201 (application/json)
{
    "orderId": "918",
    "externalOrderId": "164e66da-6183-44c5-a3c6-1a8655c44a95",
    "status": "awaiting-settlement",
    "orderType": "withdraw",
    "portfolioId": "J4MZ46Jq27B3N74RI8tsYB51",
    "portfolioType": "custody",
    "accountId": "34b1f836-2b0c-45ca-af6a-50e33c0f31a0",
    "amount": "0",
    "baseCurrency": "ETH",
    "mainCurrency": "ETH",
    "extra": {
        "toAddress": "0xd6cef1bce2810ca92ab2fa865283761d5bdec9e2",
        "payload": "0x379607f50000000000000000000000000000000000000000000000000000000000000001",
        "reportingCurrencyRate": "1212.8295821568893",
        "feesPercent": "0",
        "feeLevel": "low",
        "includeFeeInWithdraw": false,
        "blockchainTransactionType": "send",
        "estimatedFees": {
            "fee": "0.00000009157095183",
            "feeCurrency": "ETH",
            "estimatedTime": "600000",
            "reportingCurrencyRate": "1212.8295821568893",
            "gasPriceGwei": "0.001474905",
            "gasLimit": "62086"
        },
        "origin": {
            "url": "https://goerli.etherscan.io",
            "icon": "https://goerli.etherscan.io/images/favicon3.ico"
        }
    },
    "createdBy": "b2270629-5917-433a-93dc-aae28e190b5e",
    "organizationId": "TEST",
    "createdAt": "1670002739347",
    "updatedAt": "1670002739395"
}

Request

The request should include the specific CreateOrder model:

Field Data type Description
externalOrderId String Unique order identifier from client (should be unique for the portfolio, should not be blank)
orderType OrderType Order type: withdraw
payload String Serialised data payload for a smart contract
portfolioId String Unique identifier of the DeFi portfolio, for which the order will be created
blockchainTransactionType Optional<String> DeFi blockchain transaction type: send (default). A transaction request, which can include a smart contract payload
amount BigDecimal Order execution amount. It is recommended to set the amount to 0, unless the request is used to ether to a smart contract
baseCurrency Currency Currency for the amount (e.g. for USDT, it could be ETH)
mainCurrency Currency Currency of main blockchain (e.g. for USDT, it could be ETH)
feeLevel Optional<feeLevel> The fee level: low, medium or high
toAddress Optional<String> Withdrawal or smart contract address
toCryptoAddressId Optional<String> Withdraw crypto address identifier
toPortfolioId Optional<String> Withdraw portfolioId identifier

Note: this method broadcasts the transaction automatically.

Response

The response of the method includes the Order model:

Field Data type Description
orderId String Unique order identifier generated upon its creation
externalOrderId String Unique order identifier passed in the request
status OrderStatus Operating status of the order
orderType OrderType Order type: deposit or withdraw
portfolioId String Unique identifier of the portfolio, for which the order will be created
portfolioType Enum<PortfolioType> Type of the portfolio (see the PortfolioType model below)
accountId String Account idenifier
amount BigDecimal Order execution amount
baseCurrency Currency Currency of the amount
mainCurrency Currency Main currency of the blockchain
extra OrderExtra Additional order data, including payload value and blockchainTransactionType
createdBy Optional<String> User ID of the order creator
organizationId Optional<String> Unique ID of the organisation of the creator
createdAt Long Time of order creation
updatedAt Optional<Long> Time of the latest order update

Create smart-call order

+ POST /platform/orders

This method creates a smart-call order containing an unsigned transaction. The transaction can be signed using Copper Unlimited.

Required API Key permissions: Withdraw

Properties


+ Request (application/json)
{
    "baseCurrency": "ETH",
    "externalOrderId": "464e66da-6183-44c5-a3c6-1a8655c44a95",
    "mainCurrency": "ETH",
    "orderType": "withdraw",
    "payload": "0xf8890884883190a28302064694bc1f23aba4f942559e090c637b36acef0c58e7f280b8643d7403a30000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b3132204f63742032303232000000000000000000000000000000000000000000808080",
    "portfolioId": "J4MZ46Jq27B3N74RI8tsYB5o",
    "blockchainTransactionType": "smart-call",
    "externalBroadcast": "true",
    "origin": {
        "url": "https://goerli.etherscan.io",
        "icon": "https://goerli.etherscan.io/images/favicon3.ico"
    },
    "amount": "0"
}
+ Response 201 (application/json)
{
    "orderId": "988",
    "externalOrderId": "464e66da-6183-44c5-a3c6-1a8655c44a95",
    "status": "awaiting-settlement",
    "orderType": "withdraw",
    "portfolioId": "J4MZ46Jq27B3N74RI8tsYB5o",
    "portfolioType": "custody",
    "accountId": "34b1f836-2b0c-45ca-af6a-50e33c0f31a9",
    "amount": "0",
    "baseCurrency": "ETH",
    "mainCurrency": "ETH",
    "extra": {
        "payload": "0xf8890884883190a28302064694bc1f23aba4f942559e090c637b36acef0c58e7f280b8643d7403a30000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b3132204f63742032303232000000000000000000000000000000000000000000808080",
        "reportingCurrencyRate": "1281.71",
        "includeFeeInWithdraw": false,
        "blockchainTransactionType": "smart-call",
        "origin": {
            "url": "https://goerli.etherscan.io",
            "icon": "https://goerli.etherscan.io/images/favicon3.ico"
        },
        "externalBroadcast": true
    },
    "createdBy": "b2270629-5917-433a-93dc-aae28e190b5e",
    "organizationId": "TEW",
    "createdAt": "1670002739347",
    "updatedAt": "1670002739395"
}

Request

The request should include the CreateOrder model specific for smart-call orders:

Field Data type Description
externalOrderId String Unique order identifier from client (should be unique for the portfolio, should not be blank)
orderType OrderType Order type: withdraw
payload String Serialised unsigned transaction. For Ethereum only type 0 (legacy) transactions are supported
portfolioId String Unique identifier of the portfolio (vault), for which the order will be created. The vault must be configured in the Copper Platform interface as the DeFi vault
blockchainTransactionType String DeFi blockchain transaction type: smart-call
externalBroadcast Boolean Sets broadcast mode. If true: manual broadcast. Use Retrieve order by id to get the fully signed trasactions, and then broadcast them manually. If false (default): automatic broadcast. Copper automatically broadcasts transactions to the network after fully signing
amount BigDecimal Order execution amount. To interact with a smart-contract or make a Layer 2 transfer (i.e. transfer USDC or USDT), the amount must be 0
baseCurrency Currency Currency of main blockchain (e.g. for USDT, it could be ETH)
mainCurrency Currency Currency of main blockchain (e.g. for USDT, it could be ETH)

Response

The response of the method includes the Order model:

Field Data type Description
orderId String Unique order identifier generated upon its creation
externalOrderId String Unique order identifier passed in the request
status OrderStatus Operating status of the order
orderType OrderType Order type: withdraw
portfolioId String Unique identifier of the portfolio, for which the order will be created
portfolioType Enum<PortfolioType> Type of the portfolio (see the PortfolioType model below)
accountId String Account idenifier
amount BigDecimal Order execution amount
baseCurrency Currency Currency of the amount
mainCurrency Currency Main currency of the blockchain
extra OrderExtra Additional order data, including payload value and blockchainTransactionType
createdBy Optional<String> User ID of the order creator
organizationId Optional<String> Unique ID of the organisation of the creator
createdAt Long Time of order creation
updatedAt Optional<Long> Time of the latest order update

Create multi-smart-call order with multiple transactions in payload

+ POST /platform/orders

This method creates a multi-smart-call order containing a a list of unsigned transactions. The transactions can be signed using Copper Unlimited.

Required API Key permissions: Withdraw

Properties


+ Request (application/json)
{
    "baseCurrency": "ETH",
    "externalOrderId": "ef2a1db4-baa3-4f11-80ee-eddeb2e1cf70",
    "mainCurrency": "ETH",
    "orderType": "withdraw",
    "payloads": [
        "0xeb1c85037545f602825208940c19377f8b628698dcaf6028b43a0b16d1c4401787038d7ea4c6800080808080",
        "0xf8691d85037545f60282fde89407865c6e87b9f70255377e024ace6630c1eaa37f80b844a9059cbb0000000000000000000000000c19377f8b628698dcaf6028b43a0b16d1c4401700000000000000000000000000000000000000000000000000000000000186a0808080"
    ],
    "portfolioId": "7yzQLWtDeZEYYsVYb028h3OM",
    "blockchainTransactionType": "multi-smart-call",
    "externalBroadcast": true
}

+ Response 201 (application/json)
{
    "orderId": "37242081",
    "externalOrderId": "ef2a1db4-baa3-4f11-80ee-eddeb2e1cf70",
    "status": "awaiting-settlement",
    "orderType": "withdraw",
    "portfolioId": "7yzQLWtDeZEYYsVYb028h3OM",
    "portfolioType": "custody",
    "accountId": "52ed19ee-c4d6-40c6-be0f-c9496e06a694",
    "amount": "0.001",
    "baseCurrency": "ETH",
    "mainCurrency": "ETH",
    "extra": {
        "payloads": [
            "0xeb1c85037545f602825208940c19377f8b628698dcaf6028b43a0b16d1c4401787038d7ea4c6800080808080",
            "0xf8691d85037545f60282fde89407865c6e87b9f70255377e024ace6630c1eaa37f80b844a9059cbb0000000000000000000000000c19377f8b628698dcaf6028b43a0b16d1c4401700000000000000000000000000000000000000000000000000000000000186a0808080"
        ],
        "reportingCurrencyRate": "1654.9549806311848",
        "includeFeeInWithdraw": false,
        "blockchainTransactionType": "multi-smart-call",
        "externalBroadcast": true
    },
    "createdBy": "d73ce276-4716-410a-a1a0-9fa9b7336798",
    "organizationId": "TEST",
    "createdAt": "1675882449886",
    "updatedAt": "1675882449943"
}

Request

The request should include the specific CreateOrder model:

Field Data type Description
externalOrderId String Unique order identifier from client (should be unique for the portfolio, should not be blank)
orderType OrderType Order type: withdraw
payloads List<String> Serialised list of unsigned transactions. For Ethereum only type 0 (legacy) transactions are supported
portfolioId String Unique identifier of the DeFi portfolio, for which the order will be created. The vault must be configured in the Copper Platform interface as the DeFi vault
blockchainTransactionType String DeFi blockchain transaction type: multi-smart-call. Creates multi-smart-call order with multiple transactions in payload
externalBroadcast Boolean Sets broadcast mode. If true: manual broadcast. Use Retrieve order by id to get the fully signed trasactions, and then broadcast them manually. If false (default): automatic broadcast. Copper automatically broadcasts transactions to the network after fully signing
baseCurrency Currency Currency of main blockchain (e.g. for USDT, it could be ETH)
mainCurrency Currency Currency of main blockchain (e.g. for USDT, it could be ETH)

Response

The response of the method includes the Order model:

Field Data type Description
orderId String Unique order identifier generated upon its creation
externalOrderId String Unique order identifier passed in the request
status OrderStatus Operating status of the order
orderType OrderType Order type: withdraw
portfolioId String Unique identifier of the portfolio, for which the order will be created
portfolioType Enum<PortfolioType> Type of the portfolio (see the PortfolioType model below)
accountId String Account idenifier
amount BigDecimal Order execution amount
baseCurrency Currency Currency of the amount
mainCurrency Currency Main currency of the blockchain
extra OrderExtra Additional order data, including payloads value and blockchainTransactionType
createdBy Optional<String> User ID of the order creator
organizationId Optional<String> Unique ID of the organisation of the creator
createdAt Long Time of order creation
updatedAt Optional<Long> Time of the latest order update

Wallet Messages API

Wallet Messages API is used for creating blockchain messages and obtaining data on existing ones. Particularly, this API is used in XZC staking.

Create a message

This method signs a blockchain message.

+ POST /platform/wallet-messages

Properties


+ Request (application/json)
{
    "externalMessageId": "8879aaa4-309a-4999-831d-109c10ddda56",
    "portfolioId": "07gX5HVJHhPTYifYwF8gTapm",
    "mainCurrency": "ETH",
    "message": "Test"
}

+ Response 201 (application/json)
{
    "externalMessageId": "8879aaa4-309a-4999-832d-109c10ddda56",
    "messageId": "207",
    "status": "working",
    "portfolioId": "07gX5HVJHhPTYifYwF8gTap1",
    "mainCurrency": "ETH",
    "extra": {
        "messageRequest": {
            "publicKeyHash": "4de54dca3c103ff970bf8d3951fe12d5fbea6db0db1f2ad14228e41a3f6c11aa",
            "currency": "ETH",
            "mainCurrency": "ETH",
            "message": "Test",
            "nonceNumber": "29"
        }
    },
    "createdBy": "c785c80a-e46c-4493-a8ed-c701fd5c5cc5",
    "organizationId": "6887239497",
    "accountId": "43cdead5-f14e-406b-871b-2878dda12f64",
    "createdAt": "1675780091940"
}

Request

The request can include the following parameters:

Field Data type Description
externalMessageId String Unique message identifier provided by a client (should be unique for a portfolio)
portfolioId String Unique identifier of a portfolio containing the message
mainCurrency Currency Main currency of the blockchain
message String Message to be signed
version Optional<MessageVersion> Version of the message

MessageVersion

MessageVersion is an enum with following values:

Status Description
empty Personal message
v3 message is a signTypedData message based on EIP-712. The message does not support arrays and recursive data structures
v4 message is a signTypedData message based on EIP-712. The message fully supports of arrays and recursive data structures
hash message is a message hash, e.g. for a personal message or an EIP-712 based message. A hash preserves the privacy of the actual message. This version is supported only on DeFi vaults
eip155-hash message is a replay protected EIP-155 hash, e.g. for a mainnet chain transaction. A hash preserves the privacy of the actual message. This version is supported only on DeFi vaults

Response

The response of the method includes the WalletMessage model:

Field Data type Description
externalMessageId String Unique message identifier given by a client (should be unique for a portfolio)
messageId String Unique message identifier
status MessageStatus Message processing working status (Processing the message: waiting for a client signature)
portfolioId String Unique identifier of a portfolio containing the message
mainCurrency Currency Main currency of the used blockchain
extra WalletMessageExtra Additional wallet message data (see below)
createdBy String User ID of a message creator
organizationId String Unique organization identifier
accountId String Unique account identifier
createdAt Long Timestamp of message creation

WalletMessageExtra

Field Data type Description
messageRequest MessageRequest Message request data (see below)

MessageRequest

Field Data type Description
publicKeyHash String Wallet public key hash
currency String Wallet currency
mainCurrency String Wallet currency
message String Message to be signed
version MessageVersion Version of the message
nonceNumber String Message number in this portfolio

Get all messages

+ GET /platform/wallet-messages?limit=1&offset=0

This method allows to retrieve information about all blockchain messages of the organisation.

Required API Key permissions: View

Properties

+ Response 200 (application/json)
{
    "walletMessages": [
        {
            "externalMessageId": "ckki3n7xj000r3f62ey5rr4r7",
            "messageId": "45",
            "status": "canceled",
            "portfolioId": "ck7bs8wpu000d3h5mt9ja3s8s",
            "mainCurrency": "ETH",
            "extra": {
                "messageRequest": {
                    "publicKeyHash": "d12f3b91e8446b6c49077c1dc16ab921f35f6e7d8bab43fda673f2a2858704ad",
                    "currency": "ETH",
                    "mainCurrency": "ETH",
                    "message": "IDEX_verifyWallet:address=0x1a75344addadcdecce4fbf859caa7ef9d9299f78,nonce=e5debb90-5fde-11eb-a6af-b3c7e31c67be",
                    "nonceNumber": "5"
                }
            },
            "createdBy": "c066a06c-c556-4105-99d9-9e6c8cfec489",
            "organizationId": "test",
            "accountId": "77bd1eec-7189-48fa-8e66-d3c114ff1e3e",
            "createdAt": "1611913442234"
        }
    ],
    "total": "1"
}

Request

The request can include the following optional parameters:

Field Data type Description
limit Optional<Int> Limit output of messages: 1000 by default, max. 2000
offset Optional<Int> An offset between the beginning of the message list and a first displayed element; 0 by default

Response

The response includes the WalletMessage model:

Field Data type Description
messageId String Unique message identifier
externalMessageId String Unique message identifier given by a client (should be unique for a portfolio)
status MessageStatus Message processing status (see below)
portfolioId String Unique identifier of a portfolio containing the message
accountId String Unique account identifier
mainCurrency Optional<Currency> Main currency of the used blockchain
extra WalletMessageExtra Additional wallet message data (see below)
createdBy String User ID of a message creator
organizationId String Unique organization identifier
createdAt Long Timestamp of message creation

MessageStatus MessageStatus is an enum with following values:

Status Description
working Processing the message: waiting for a client signature
canceled The message has been cancelled
part-signed-tx-added The message has been partly signed
full-signed-tx-added The message has been fully signed

WalletMessageExtra

Field Data type Description
messageRequest MessageRequest Message request data (see below)
partSigned Optional<PartSigned> Partly-signed message data (see below)
signed Optional<FullSigned> Fully-signed message data (see below)

MessageRequest

Field Data type Description
publicKeyHash String Wallet public key hash
currency String Wallet currency
message String Message to be signed

PartSigned

Field Data type Description
uploadBy String User ID of the uploader
partSignedMessage Object Data of the partly-signed message

FullSigned

Field Data type Description
uploadBy String User ID of the uploader
signedMessage Object Data of the fully-signed message

Get message by its ID

+ GET /platform/wallet-messages/{messageId}

This method retrieves information about a specific message.

Required API Key permissions: View

Properties

+ Response 201 (application/json)
{
      "externalMessageId": "ckf2lcuv4000g3i5uv3x4xn6f",
      "messageId": "11",
      "status": "full-signed-tx-added",
      "portfolioId": "ck8owwcvj000f3j5wrjoyip4d",
      "mainCurrency": "XZC",
      "extra": {
          "messageRequest": {
              "publicKeyHash": "d9f3c6b1066c188aa039e0f4a67dd8b10caf3de3e9c7862a8d0fb17320d57b14",
              "currency": "XZC",
              "message": "test",
              "nonceNumber": "14"
          },
          "partSigned": {
              "uploadBy": "191b5342-2157-4ede-9458-eb673f324468",
              "partSignedMessage": {
                  "type": "part-signed-message",
                  "value": "eyJjdXJyZW5jeSI6IlhaQyIsIm1lc3NhZ2..."
              }
          },
          "signed": {
              "uploadBy": "d098b47d-5387-4f01-956e-561f15f72f2d",
              "signedMessage": {
                  "signature": "IGqvr8lz78p7ZE1eIYkrRL1znpkcxhzhi1peiqoEnEDNKU3i0F5Bct509/dzjkrVeHKtQIl1S8aa82eh2IRG5jI="
              }
          }
      },
      "createdBy": "191b5342-2157-4ede-9458-eb673f324468",
      "organizationId": "TEST",
      "accountId": "67126cc0-357d-4642-9596-ac0c0bdf4006",
      "createdAt": "1600091821812"
  }

Request

The messageId parameter is mandatory. The method does not require any request fields.

Response

The response of the method includes the WalletMessage model for one message with the specified messageId (see above).

Cancel message

+ PATCH /platform/wallet-messages/{messageId}

This method cancels processing of an early pushed message. After the successful response, the message with the specified messageId will not be processed further, its status will be changed for canceled.

Required API Key permissions: Trading or Withdraw.

Properties


+ Header
  Content-Type: application/vnd.cancel-wallet-message+json

+ Request
  {}

+ Response 200 (application/json)
  {}

Request

The messageId parameter is mandatory. The method does not require any request fields.

Response

The response of the method includes only the status code.

Loans API

The loans api allows you to interact with our collateral management system, booking and managing loans between two organizations.

Create a loan

+ POST /loans

+ Request
  {
    "loanType": "secured-pledged",
    "externalId": "externalId1",
    "lenderOrganizationId": "org1",
    "borrowerOrganizationId": "org2",
    "terms": {
      "termType": "fixed",
      "amount": 100000.00,
      "loanCurrency": "BTC",
      "loanNetworkCurrency": "BTC",
      "collateralCurrency": "ETH",
      "collateralNetworkCurrency": "ETH",
      "marginCallPercentage": 100,
      "defaultPercentage": 120,
      "rebalancePercentage": 80,
      "borrowFeeCurrency": "USD",
      "borrowFeePercentage": 4.5,
      "borrowFeeCalculationMethod": "daily",
      "valuationTimezone": "Europe/London",
      "dayCountConvention": "Act/360",
      "startDate": 1660344486232,
      "maturityDate": 1676245686234,
    }
  }

+ Response 201 Created
  {
    "actions": [],
    "pendingUserActions": [],
    "borrowerOrganizationId": "02392-2932",
    "createdAt": "1666345839849",
    "createdBy": "23e78c83-677a-48b1-aa3c-f5ef878120e6",
    "externalId": "123456678",
    "lenderOrganizationId": "85439-3232",
    "loanArranger": "<your loan arranger ID>",
    "loanType": "secured-pledged",
    "loanStatus": "created",
    "loanId": "896",
    "terms": {
      "termType": "fixed",
      "amount": 100000.00,
      "loanCurrency": "BTC",
      "loanNetworkCurrency": "BTC",
      "collateralCurrency": "ETH",
      "collateralNetworkCurrency": "ETH",
      "borrowFeeAmount": 100,
      "borrowFeeCurrency": "USD",
      "borrowFeePercentage": 4.5
      "collateralAmount": 100,
      "marginCallPercentage": 85,
      "defaultPercentage": 65,
      "rebalancePercentage": 125,
      "startDate": 1660344486232,
      "maturityDate": 1676245686234,
    }
  }

Required API Key permissions: Lending or Lending Arranger

This allows the creation of a loan.

Model

Request

Parameter Data type Description
loanType Loan Type Unique identifier for the loan type.
externalId Optional<String> Unique identifier for externally originated loans, must be unique per loan arranger.
lenderOrganizationId String The organization id of the lender.
borrowerOrganizationId String The organization id of the borrower.
terms Terms The terms of the loan.

Reponse

See Loan

Start Repayment

+ PATCH /loans/{loanId} 

+ Headers
  Content-Type: application/vnd.start-repayment+json

+ Request
  {
  }

+ Response 200 OK

Required API Key permissions: Lending or Lending Arranger

This allows a lender to start the repayment of the loan.

Start Default

+ PATCH /loans/{loanId} 

+ Headers
  Content-Type: application/vnd.start-default+json

+ Request
  {
  }

+ Response 200 OK

Required API Key permissions: Lending or Lending Arranger

This allows a lender to start the default of the loan.

Start Margin Call

+ PATCH /loans/{loanId} 

+ Headers
  Content-Type: application/vnd.start-margin-call+json

+ Request
  {
  }

+ Response 200 OK

Required API Key permissions: Lending or Lending Arranger

This allows a lender to start a margin call on the loan.

Model

Request

Parameter Data type Description
targetPercentage Optional<Numeric> The target ltv to rebalance to, mutually exclusive with targetAmount.
targetAmount Optional<Numeric> The target collateral to rebalance to, mutually exclusive with targetPercentage.

Start Rebalance

+ PATCH /loans/{loanId} 

+ Headers
  Content-Type: application/vnd.start-rebalance+json

+ Request
  {
  }

+ Response 200 OK

Required API Key permissions: Lending or Lending Arranger

This allows a lender to rebalance the loan. Can optionally specify the target ltv (calculated from the last valuation) or the target collateral. If neither are specified it will use the collateral required to keep the loan at the maintenance percentage.

Model

Request

Parameter Data type Description
targetPercentage Optional<Numeric> The target ltv to rebalance to, mutually exclusive with targetAmount.
targetAmount Optional<Numeric> The target collateral to rebalance to, mutually exclusive with targetPercentage.

Cancelling a Loan

+ PATCH /loans/{loanId} 

+ Headers
  Content-Type: application/vnd.cancel+json

+ Request
  {
  }

+ Response 200 OK

Required API Key permissions: Lending or Lending Arranger

This allows a borrower or lender to trigger the cancellation of a loan before the funds have been released.

Updating a Loan

+ PATCH /loans/{loanId} 

+ Headers
  Content-Type: application/vnd.update+json

+ Request
  {
    "startDate": 1660344486232,
    "maturityDate": 1676245686234,
    "loanNetworkCurrency": "BTC",
    "collateralNetworkCurrency": "ETH",
    "borrowFeeAmount": 100,
    "borrowFeePercentage": 4.5
  }

+ Response 200 OK

Required API Key permissions: Lending or Lending Arranger

This allows a borrower or lender to update the loan if various things have changed.

Model

Request

Parameter Data type Description
startDate Optional<Long> Timestamp in epoch milliseconds of the start date.
maturityDate Optional<Long> Timestamp in epoch milliseconds of the maturity date.
borrowFeeAmount Optional<Numeric> The total amount of the borrow fee over the term of the loan, this will be pro-rated in billing.
borrowFeePercentage Optional<Numeric> The LTV of the borrow fee.
loanNetworkCurrency Optional<Currency> Currency code of the network being used to transfer the asset.
collateralNetworkCurrency Optional<Currency> Currency code of the network being used to transfer the collateral.

Assign Lender Portfolio

+ PATCH /loans/{loanId} 

+ Headers
  Content-Type: application/vnd.update-lender-portfolio+json

+ Request
  {
    "portfolioId": "<lender portfolio ID>"
  }

+ Response 200 OK

Required API Key permissions: Lending or Lending Arranger

This allows a lender or loan arranger to assign the lender portfolio ID.

Model

Request

Parameter Data type Description
portfolioId String The ID of the portfolio to be assigned.

Assign Borrower Portfolio

+ PATCH /loans/{loanId} 

+ Headers
  Content-Type: application/vnd.update-borrower-portfolio+json

+ Request
  {
    "portfolioId": "<borrower portfolio ID>"
  }

+ Response 200 OK

Required API Key permissions: Lending or Lending Arranger

This allows a borrower or loan arranger to assign the lender portfolio ID.

Model

Request

Parameter Data type Description
portfolioId String The ID of the portfolio to be assigned.

Update Loan Valuations

+POST /loan-valuations

+ Request
{
  "organizationId": "12345",
  "pricedAt": 1676245686234,
  "loanIds": [
    "3000819"
  ],
  "marketPrices": [
    {
      "baseCurrency": "BTC",
      "quoteCurrency": "USDC",
      "price": 10
    }
  ]
}

+Response 201 CREATED

Required API Key permissions: Lending or Lending Arranger

This allows a lender to batch update the valuation of a loan where the cross pair valuation is provided between loan and collateral asset and the ltv and required collateral to keep the loan at the maintenance percentage is calculated.

Model

Request

Parameter Data type Description
organizationId String Unique identifier of the lender organization.
pricedAt Optional<Long> The time the prices were fetched from the market.
loanIds Optional<List<String>> An optional list of loan ids to apply the values to.
organizationId String Unique identifier of the lender organization.
marketPrices List<MarketPrice> The list of cross pair valuations.

Shared Model

The following are common types used throughout the loan api.

Loan

Parameter Data type Description
loanId String Unique identifier of the loan.
loanArranger Optional<String> Unique identifier of the loan arranger.
externalId Optional<String> Unique identifier for externally originated loans, must be unique per loan arranger.
loanStatus Loan Status The status of the loan.
connectionId String The id of the connection which defines whether there is a signed account control agreement in place.
borrowerCollateralPortfolioId String The id of the account which is to be used for collateral between the lender and borrower.
lenderOrganizationId String The organization id of the lender.
lenderPortfolioId Optional<String> The account id of the lender.
borrowerOrganizationId Optional<String? The organization id of the borrower.
borrowerPortfolioId String The account id of the borrower.
terms Terms The terms of the loan.
createdBy String The id of the user who created the loan.
createdAt Long Epoch millis of when the loan was created.
updatedBy Optional<String> The id of the user who last updated the loan.
updatedAt Optional<Long> Epoch millis of when the loan was last updated.
securedCollateralAmount Numeric How much collateral has been secured.
collateralSecuredAt Optional<Long> Epoch millis of when the collateral was first secured.
collateralReleasedAt Optional<Long> Epoch millis of when the collateral was released.
collateralClaimedAt Optional<Long> Epoch millis of when the collateral was claimed.
loanDisbursedAt Optional<Long> Epoch millis of when the loan was was disbursed.
loanReturnedAt Optional<Long> Epoch millis of when the loan was repaid.
collateralPercentage Numeric The percentage of collateral secured vs required.
ltvPercentage Numeric The ltv percentage of the loan as per the last valuation.
closedReason Optional<ClosedReason> The reason the loan was closed.
actions List<Action> The actions that have happened to the loan.
pendingUserActions List<RequestedUserAction> The requested user actions the calling user needs to perform.

Terms

The terms contain details about the loan agreement.

Parameter Data type Description
amount Numeric The amount of the loan.
loanCurrency Currency Currency code of the asset being lent.
loanNetworkCurrency Currency Currency code of the network being used to transfer the asset.
collateralAmount Numeric The amount of the collateral required.
collateralCurrency Currency Currency code of the asset being used for collateral.
collateralNetworkCurrency Currency Currency code of the network being used to transfer the collateral.
termType Term Type The type of the term of the loan.
startDate Long Timestamp in epoch milliseconds of the start date.
maturityDate Optional<Long> Timestamp in epoch milliseconds of the maturity date.
borrowFeeCalculationMethod BorrowFeeCalculationMethod The method used to calculate the borrow fees.
borrowFeeCurrency Optional<Currency> The currency of the borrow fee.
borrowFeeAmount Optional<Numeric> The total amount of the borrow fee over the term of the loan, this will be pro-rated in billing.
borrowFeePercentage Optional<Numeric> The APR to be used in the borrow fee calculation.
dayCountConvention Optional<Day Count Convention> The day count convention to be used in the borrow fee calculation.
valuationTimezone Optional<String> The timezone in which to use when applying the borrow fee, in ISO standard.
marginCallPercentage Optional<Numeric> The LTV of collateral at which a margin call is made.
defaultPercentage Optional<Numeric> The LTV of collateral at which default occurs.
rebalancePercentage Optional<Numeric> The LTV of collateral at which a rebalance occurs.
requireNoticeOfExclusiveControl Optional<Boolean> Whether this loan must have an explicit notice of exclusive control on a default.

Action

An action contains details about events that have happened to a loan, i.e. repayment started.

Parameter Data type Description
actionId String The id of the action.
actionName String The name of the action.
payload Object The command that caused the action to happen.
createdAt Long Timestamp in epoch milliseconds of the start date.
createdBy String The id of the user who triggered the action.
loanId String The id of the loan the action happened too.

Requested User Action

A requested user action identifies what action if any a user needs to take (either lender or borrower) to progress the loan.

Id Detail
assign-lender-portfolio Lender needs to select the account for the loan.
assign-borrower-portfolio Borrower needs to select the account for the loan.
deliver-additional-collateral Borrower needs to add additional funds to the account for securing collateral.
deliver-additional-lending-funds Lender needs to add additional funds to the account for disbursing the loan.
deliver-additional-repayment-funds Borrower needs to add additional funds to the account for repaying the loan.
sign-lending-funds-disbursal Lender needs to sign the transaction for disbursing the loan.
sign-lending-funds-return Borrower needs to sign the transaction for repaying the loan.
sign-claiming-collateral Borrower needs to sign the transaction for the collateral to be claimed by the lender.
treasury-approve-lending-funds-disbursal Disbursing the loan requires account manager assistance.
treasury-approve-lending-funds-return Repaying the loan requires account manager assistance.
treasury-approve-claiming-collateral Claiming the collateral requires account manager assistance.
notice-of-exclusive-control-required Claiming the collateral requires account manager assistance.
collateral-asset-activation The collateral assets needs activating on the borrowers collateral vault.

Loan Type

The loan type identifies how the loan is collateralized.

Loan Types
secured-pledged

Loan Status

The loan status identifies the current state of a loan.

Name Description
created Newly booked loan.
awaiting-configuration The borrower and lender must configure the loan.
configured The loan is configured and we are waiting for the start date.
securing-collateral The collateral is being secured.
disbursing-loan The loan is being sent to the borrower.
open The loan is open.
margin-call A margin call has been started and collateral being secured.
rebalancing A rebalance has been started and collateral being released.
releasing-collateral The collateral is being released after repayment.
repaying-loan The loan is being repaid to the lender.
defaulting The collateral is being claimed after default has been started.
closed The loan has been closed. See Closed Reason.
errored The loan has errored.
cancelling The loan has been cancelled.

Term Type

The term type identifies the type of duration that has been agreed.

Name Description
fixed The loan is active between the start date and the maturity date.
open The loan is active on the start date but has no fixed maturity date.

Closed Reason

The closed reason identities why the loan was closed.

Name Description
defaulted The loan was defaulted.
cancelled The loan was cancelled before the funds were released.
repaid The loan was repaid.

Market Price

Parameter Data type Description
price Numeric The cross pair valuation where it should be 1 baseCurrency is valued at (n) quoteCurrency.
baseCurrency Currency Currency code of the asset being lent.
quoteCurrency Currency Currency code of the asset being used for collateral.

Borrow Fee Calculation Method

The borrow fee calculation method identifies how fees are applied for the cost of borrowing the loan.

Name Description
none No calculation takes place for this loan.
daily The borrow fee percentage is calculated over the day count convention and is applied daily in the specified timezone.

Day Count Convention

The day count convention defines how the apr is applied to the loan each day.

Name Description
Act/360 The 'Act/360' day count, which divides the actual number of days by 360.
Act/365A The 'Act/365 Actual' day count, which divides the actual number of days by 366 if a leap day is contained, or by 365 if not.
1/1 The '1/1' day count, which always returns a day count of 1.

Copper Unlimited Online

Copper Unlimited Online is a dockerised application made by Copper as an alternative to Copper Unlimited Desktop.

CU Online can be deployed in your network and allows to automate the process of transaction signing. To do this, you can easily export shards of your wallet from CU Desktop to CU Online and sign transaction requests via its internal API.

Software requirements

CU Online is as a Docker image based on debian:10.5-slim and using Docker Compose and the NodeJS daemon for its operation.

The image is publicly available in Copper DockerHub.

Network characteristics of the image:

How to launch

  1. Export shards of your key from the CU Desktop application via wallet backup function: click the drop-down menu in the top right corner of the window and choose the Backup option. During the export process, CU Desktop will ask a password to encrypt each shard of the wallet. This will prevent accessing the shard data in case a potential attacker gains access to the filesystem. Choose a preferred folder to save the *.copper file containing the wallet shards.
  2. Start the dockerised CU Online. Before running, specify following fields:
    • a path to your folder with the *.copper file.
    • a port that CU Online endpoints will listen to.
    • the required environment as the APP_ENVIRONMENT environment variable:
      • testnet - https://api.testnet.copper.co/ (if the variable is not specified, this value will be used by default)
      • stage - https://api.stage.copper.co/
      • mainnet - https://api.copper.co/ The choice depends on a platform you are going to operate on.

To launch the server, use the command below (for any docker run command reference, see the official Docker documentation).

docker run --rm -ti \
  -v ${PWD}/key-backups/:/app/keys/ \
  -e APP_ENVIRONMENT='testnet' \
  -p your_port_for_the_cu_online:3010 \
  copperexchange/copper-unlimited:latest

# ${PWD}/key-backups/ is the folder containing the wallet backup.
# The APP_ENVIRONMENT variable can be 'testnet', 'stage' or 'mainnet' (see details above).

After startung the server, refer to the next section to get acquainted with typical CU Online use cases.

Transaction signing

docker run --rm -ti \
  -v ${PWD}/key-backups/:/app/keys/ \
  -e APP_ENVIRONMENT='testnet' \
  -p your_port_for_the_cu_online:3010 \
  copperexchange/copper-unlimited:latest
+ POST https://api.copper.co/platform/orders          
+ Request
{
  "externalOrderId": "ckdr8xy1l00303g5neu5iunh4",
  "orderType": "withdraw",
  "baseCurrency": "ETH",
  "mainCurrency": "ETH",
  "amount": "0.01",
  "portfolioId": "edd7e0ea-9d00-4538-b187-c14813d7b0ba",  # from account
  "toPortfolioId": "28a26c72-4d72-4f97-9b36-6811ab708216", # to account
  "includeFeeInWithdraw": true,
  "feeLevel": "low",
  "description": "Some description"
} 

+ Response 201
{
  "orderId": "5824946",
  "orderType": "withdraw",
  "amount": "0.01",
  "baseCurrency": "ETH",
  "mainCurrency": "ETH",
  "externalOrderId": "ckdr8xy1l00303g5neu5iunh4",
  "extra": {
    "feeLevel": "low",
    "includeFeeInWithdraw": true,
    "toAddress": "0xf71b4a401734a3f1fe9794003a4956ada7753175",
    "toPortfolioId": "28a26c72-4d72-4f97-9b36-6811ab708216"
  },
  "portfolioId": "edd7e0ea-9d00-4538-b187-c14813d7b0ba",
  "portfolioType": "custody",
  "status": "awaiting-settlement"
}
+ PATCH https://api.copper.co/platform/orders/{orderId}

+ Headers
  Content-Type: application/vnd.start-custody-settlement+json

+ Response 200
  {
    "amount": "0.01",
    "baseCurrency": "ETH",
    "externalOrderId": "ckdr8xy1l00303g5neu5iunh4",
    "extra": {
      "toPortfolioId": "ck8plg2if000f3j5qnnbw13op",
      "transactionRequest": {
        "transactionRequestId": "a5ba9f1c-c538-46e9-8b25-af21572b8077",
        "publicKeyHash": "765188378c75dd61140d765242a0a3d09cd15680a862769e4000f75204fa86de",
        "currency": "ETH",
        "mainCurrency": "ETH",
        "amount": "10000000000000000",
        "toAddress": "0xf71b4a401734a3f1fe9794003a4956ada7753175",
        "includeFee": true,
        "transactionRequest": {
          "fee": "231000000000000",
          "outputs": [
            {
              "value": "10000000000000000",
              "address": "0xf71b4a401734a3f1fe9794003a4956ada7753175"
            }
          ],
          "gasLimit": "21000",
          "gasPrice": "11000000000",
          "sequence": "4",
          "includeFee": true,
          "nonceNumber": "15"
        }
      },
      "toAddress": "0xf71b4a401734a3f1fe9794003a4956ada7753175",
      "reportingCurrencyRate": "338.15",
      "feesPercent": "0",
      "feeLevel": "low",
      "includeFeeInWithdraw": true,
      "withdrawFee": "0.000231000000000000"
    },
    "mainCurrency": "ETH",
    "orderId": "5824946",
    "orderType": "withdraw",
    "portfolioId": "edd7e0ea-9d00-4538-b187-c14813d7b0ba",
    "portfolioType": "custody",
    "status": "working"
  }
+ POST http://0.0.0.0:3010/sign-async/

+ Headers
  Content-Type: application/json

+ Request
  {
    "type": "request",
    "keyPassword": "myTestPaswordFromKeyBackup.1234#",
    "keyFilename": "BTC_My Default Vault_wallet.copper",
    "transactionRequestId": "a5ba9f1c-c538-46e9-8b25-af21572b8077",
    "masterPassword": "PASSWORD",
    "apiKey": "KEY",
    "apiSecret": "SECRET",

    # get all this fields from order.extra.transactionRequest described above
    "signRequest": {
      "transactionRequestId": "a5ba9f1c-c538-46e9-8b25-af21572b8077", # Same transactionRequestId as above
      "publicKeyHash": "765188378c75dd61140d765242a0a3d09cd15680a862769e4000f75204fa86de",
      "currency": "ETH",
      "mainCurrency": "ETH",
      "amount": "10000000000000000",
      "toAddress": "0xf71b4a401734a3f1fe9794003a4956ada7753175",
      "includeFee": true,
      "transactionRequest": {
        "fee": "231000000000000",
        "outputs": [
          {
            "value": "10000000000000000",
            "address": "0xf71b4a401734a3f1fe9794003a4956ada7753175"
          }
        ],
        "gasLimit": "21000",
        "gasPrice": "11000000000",
        "sequence": "4",
        "includeFee": true,
        "nonceNumber": "15"
      }
    }
  }

+ Response 200 OK
  {
    "transactionRequestId": "a5ba9f1c-c538-46e9-8b25-af21572b8077", # Same transactionRequestId as above
    "sessionKey": "9baa2670-2291-43d4-814f-e04427204925",
    "sessionTimestamp": "1608296004000"
  }

After signing (the transaction is in the completed status), the signed transaction will be uploaded to the Copper platform automatically.

+ GET http://0.0.0.0:3010/sign-async/{transactionRequestId}

+ Headers
  Content-Type: application/json

+ Response 200 OK
  {
    "status": "in-progress",
    "message": "AQRwL5FqGrbLaPO4w+NoEq9oZ...R5I/wjEQND/4YmIn+rbN9uh5U/0=",
  }

Possible statuses:

Status Description
starting The request is accepted for processing
session-established The CU session has been established
in-progress The signature is being generated
completed The transaction has been signed
error Something went wrong, see the message field

Transaction signing (deprecated)

You can also use the deprecated POST /signatures endpoint. In this case, the workflow will differ.

Particularly, you will have to upload a transaction partly signed by your CU Online to the platform.

docker run --rm -ti \
-v ${PWD}/key-backups/:/app/keys/ \
-p 3010:3010 \
copperexchange/copper-unlimited:latest
+ POST https://api.copper.co/platform/orders          
+ Request
{
  "externalOrderId": "ckdr8xy1l00303g5neu5iunh4",
  "orderType": "withdraw",
  "baseCurrency": "ETH",
  "mainCurrency": "ETH",
  "amount": "0.01",
  "portfolioId": "edd7e0ea-9d00-4538-b187-c14813d7b0ba",  # from account
  "toPortfolioId": "28a26c72-4d72-4f97-9b36-6811ab708216", # to account
  "includeFeeInWithdraw": true,
  "feeLevel": "low",
  "description": "Some description"
} 

+ Response 201
{
  "orderId": "5824946",
  "orderType": "withdraw",
  "amount": "0.01",
  "baseCurrency": "ETH",
  "mainCurrency": "ETH",
  "externalOrderId": "ckdr8xy1l00303g5neu5iunh4",
  "extra": {
    "feeLevel": "low",
    "includeFeeInWithdraw": true,
    "toAddress": "0xf71b4a401734a3f1fe9794003a4956ada7753175",
    "toPortfolioId": "28a26c72-4d72-4f97-9b36-6811ab708216"
  },
  "portfolioId": "edd7e0ea-9d00-4538-b187-c14813d7b0ba",
  "portfolioType": "custody",
  "status": "awaiting-settlement"
}
+ PATCH https://api.copper.co/platform/orders/{orderId}

+ Headers
  Content-Type: application/vnd.start-custody-settlement+json

+ Response 200
  {
    "amount": "0.01",
    "baseCurrency": "ETH",
    "externalOrderId": "ckdr8xy1l00303g5neu5iunh4",
    "extra": {
      "toPortfolioId": "ck8plg2if000f3j5qnnbw13op",
      "transactionRequest": {
        "publicKeyHash": "765188378c75dd61140d765242a0a3d09cd15680a862769e4000f75204fa86de",
        "currency": "ETH",
        "mainCurrency": "ETH",
        "amount": "10000000000000000",
        "toAddress": "0xf71b4a401734a3f1fe9794003a4956ada7753175",
        "includeFee": true,
        "transactionRequest": {
          "fee": "231000000000000",
          "outputs": [
            {
              "value": "10000000000000000",
              "address": "0xf71b4a401734a3f1fe9794003a4956ada7753175"
            }
          ],
          "gasLimit": "21000",
          "gasPrice": "11000000000",
          "sequence": "4",
          "includeFee": true,
          "nonceNumber": "15"
        }
      },
      "toAddress": "0xf71b4a401734a3f1fe9794003a4956ada7753175",
      "reportingCurrencyRate": "338.15",
      "feesPercent": "0",
      "feeLevel": "low",
      "includeFeeInWithdraw": true,
      "withdrawFee": "0.000231000000000000"
    },
    "mainCurrency": "ETH",
    "orderId": "5824946",
    "orderType": "withdraw",
    "portfolioId": "edd7e0ea-9d00-4538-b187-c14813d7b0ba",
    "portfolioType": "custody",
    "status": "working"
  }
+ POST http://0.0.0.0:3010/signatures

+ Headers
  Content-Type: application/json

+ Request
  {
    "type": "request",
    "keyPassword": "myTestPaswordFromKeyBackup.1234#",
    "keyFilename": "BTC_My Default Vault_wallet.copper",

    # get all this fields from order.extra.transactionRequest, described above
    "signRequest": {
      "publicKeyHash": "765188378c75dd61140d765242a0a3d09cd15680a862769e4000f75204fa86de",
      "currency": "ETH",
      "mainCurrency": "ETH",
      "amount": "10000000000000000",
      "toAddress": "0xf71b4a401734a3f1fe9794003a4956ada7753175",
      "includeFee": true,
      "transactionRequest": {
        "fee": "231000000000000",
        "outputs": [
          {
            "value": "10000000000000000",
            "address": "0xf71b4a401734a3f1fe9794003a4956ada7753175"
          }
        ],
        "gasLimit": "21000",
        "gasPrice": "11000000000",
        "sequence": "4",
        "includeFee": true,
        "nonceNumber": "15"
      }
    }
  }

+ Response 200 OK
  {
    "type": "part-signed-tx",
    "value": "AQRwL5FqGrbLaPO4w+NoEq9oZ...R5I/wjEQND/4YmIn+rbN9uh5U/0=",
  }

Note: "masterPassword" is an optional field, required only in case you sign a transaction for a Warm Vault. Here, enter your Withdrawal password.

+ PATCH https://api.copper.co/platform/orders/{orderId}

+ Headers
  Content-Type: application/vnd.upload-part-signed-tx+json

+ Request
  {
    "masterPassword": "97dee97560699a639f3cf55c464855eefe97ae97493b242fe01ecdbab39ea463",
  } 

+ Request
  {
    "transaction": {
      "type": "part-signed-tx",
      "value": "AQRwL5FqGrbLaPO4w+NoEq9oZ...R5I/wjEQND/4YmIn+rbN9uh5U/0="
    }
  }

+ Response 200
  {
    "amount": "0.01",
    "baseCurrency": "ETH",
    "externalOrderId": "ckdr8xy1l00303g5neu5iunh4",
    "extra": {
      "transactionId": "0xc5344c295cffc4db0dfe869bd395ced34e0877b0f139b8939cf2c357ea1599e4",
      ...
    },
    "mainCurrency": "ETH",
    "orderId": "5824946",
    "orderType": "withdraw",
    "portfolioId": "edd7e0ea-9d00-4538-b187-c14813d7b0ba",
    "portfolioType": "custody",
    "status": "processing"
  }

Enabling SSL/TLS

To enable SSL/TLS support, add a volume containing with your key and certificate to the CU Online container:

openssl genrsa -out privatekey.key
openssl req -new -key privatekey.key -out csr.pem
openssl x509 -req -days 9999 -in csr.pem -signkey privatekey.key -out certificate.cert
docker run --rm -ti \
  -v ${PWD}/key-backups/:/app/keys/ \
  -e APP_ENVIRONMENT='testnet' \
  -v ${PWD}/ssl/certificate.cert:/app/ssl/certificate.cert \
  -v ${PWD}/ssl/privatekey.key:/app/ssl/privatekey.key \
  -p 3010:3010 \
  copperexchange/copper-unlimited:latest

Example of the service

In order to familiarise you with operation of Copper Unlimited Online, the Copper Team have the ready-made containerised example of the service to deploy on your side.

It looks like one more image to deploy together with the Copper Unlimited Online and is available in Copper DockerHub.

The application works as follows:

  1. The application pulls orders in the working and awaiting-settlement status using Copper public API. If there are no orders available, application enters the sleeping mode for 10 seconds.
  2. Then, the application takes the first order, and if it is in the awaiting-settlement status, moves it to the working status.
  3. After this, it triggers the order signing request to the Copper Unlimited Server.
  4. The application waits until the request will be either in the completed or in the error status.
  5. If request is in error status - fires an error, if is in complete repeat the whole process starting from the first point.

To deploy and test the service, perform following steps:

1. Configure your docker-compose.yml file. Below, you will find a complete example with comments:

    version: "3.7"
    services:
      cu-server:                                            # Copper Unlimited Online service
        container_name: cu-server
        image: copperexchange/copper-unlimited:latest
        ports:
          - "3010:3010"
        volumes:
          - ${PWD}/key-backups/:/app/keys/                  # Specify the correct path to your shards before the colon
        environment:
          APP_ENVIRONMENT: "testnet"                        # Specify the environment where you are going to use the service. Possible variants: "testnet", "demo" or "mainnet"
          APP_NETWORK: "testnet"
        restart: always
        healthcheck:
          test: "timeout 10s bash -c ':> /dev/tcp/127.0.0.1/3010' || exit 1"
          interval: 30s
          timeout: 10s
          retries: 10
          start_period: 10s
        networks:
          - cu-network

      hot-wallet:
        image: copperexchange/hot-wallet:latest
        depends_on:
          - cu-server
        volumes:
          - ${PWD}/wallets-config.js:/app/wallets-config.js # Specify the correct path to your wallet-config.js file before the colon.
        environment:
          APP_ENVIRONMENT: "testnet"                        # Specify the environment (see above)
          APP_CUSTODY_DOCKER_URL: "http://cu-server:3010"   # Link to the CU Online container
          APP_API_KEY: ""                                   # Your API key from a desired environment
          APP_API_SECRET: ""                                # API secret associated with the API key
          APP_WITHDRAWAL_PASSWORD: ""                       # Withdrawal password from your organisation in a desired environment
        restart: always
        networks:
          - cu-network

    networks:
      cu-network:
        driver: bridge

2. Backup your wallet shards and place them in the directory specified as an external volume for the cu-server container (in the example: ${PWD}/key-backups/). Do not forget to activate the created wallets in the desired platform environment and request to switch corresponding vaults to hot if it is has not been done before.

3. Configure your wallets-config.js file containing details of the shards. Below, you will find the example with the comments:

    module.exports = [
      {
        portfolioId: 'ckuwfho1y000p3e626z2zmmoy',         // Identifier of the portfolio containing the wallet
        currency: 'SOL',                                  // Wallet currency
        walletFilename: 'sol-wallet.copper',              // Name of the file containing the wallet shard
        walletPassword: process.env.SOL_WALLET_PASSWORD,  // Password 
      },
      {
        portfolioId: 'cd213vvo1y000p3e62dd21dhy',         // You may specify as many shards as needed separating details with commas
        currency: 'ALGO',
        walletFilename: 'algo-wallet.copper',
        walletPassword: process.env.ALGO_WALLET_PASSWORD,
      },
    ];

Place this file in the directory specified as an extrnal volume for the hot-wallet container (in the example: ${PWD}/wallets-config.js).

As per the example, the resulting file composition on this step looks as follows:

    /${PWD}
    ├── key-backups
    │   ├── sol-wallet.copper
    │   └── algo-wallet.copper
    ├── docker-compose.yml
    └── wallets-config.js

4. Start your service with the use of the docker-compose up --build command.

5. Use the specified environment of the Copper platform to create withdrawal orders. They will be signed and pushed forward automatically.

Webhooks

+ POST {https://your-domain.com/webhook/path}

+ Headers:
  X-Signature: 97dee97560699a639f3cf5...9ea463
  X-Timestamp: 1567165602271

+ Request
  {
    "eventId": "test-b17c862a961fbba3a02af42a7de6e643",
    "event": "deposit-created",
    "subscriptionId": "test",
    "payload": {
      "extra": {
        "transaction": {
          "txId": "89a88991db6bd3c3c550d8d07a275748c074a3fea38eef4372e0b1096b237ab7",
          "inputs": [
            {
              "value": "1898836",
              "address": "2N4KgeDXHCnZP1XnAJsCZLR7XosMmjiQCMF"
            }
          ],
          "outputs": [
            {
              "value": "1888670",
              "address": "2Mt2TrU7nZkRxbciKxstS2egNVV1TgiwEvK",
              "txIndex": "0",
            },
            {
              "value": "10000",
              "address": "2NAdrCdqYGHR93Ft2koBXgdKbnoDmNdiS1n",
              "txIndex": "1",
            }
          ],
          "currency": "BTC",
          "isSuccess": true,
          "timestamp": "1608296004000",
          "blockHeight": "1898224",
          "mainCurrency": "BTC",
          "transactionType": "deposit"
        },
        "confirmations": "1",
        "transactionId": "89a88991db6bd3c3c550d8d07a275748c074a3fea38eef4372e0b1096b237ab7",
        "reportingCurrencyRate": "22886.1"
      },
      "amount": "0.0001",
      "status": "working",
      "orderId": "5842527",
      "accountId": "7814e6b5-ec66-47a3-b566-ed28228eec99",
      "createdAt": "1608296151293",
      "orderType": "deposit",
      "updatedAt": "1608296151308",
      "portfolioId": "edd7e0ea-9d00-4538-b187-c14813d7b0ba",
      "baseCurrency": "BTC",
      "mainCurrency": "BTC",
      "portfolioType": "custody",
      "organizationId": "TEST",
      "externalOrderId": "89a88991db6bd3c3c550d8d07a275748c074a3fea38eef4372e0b1096b237ab7:BTC:1"
    },
    "createdAt": "1608296152012"
  }

The Copper platform has a built-in webhook system to subscribe your service on definite events connected with deposit and withdrawal of funds.

The events will be automatically sent to your resource in JSON format as a POST method payload. Webhook events are not sent for internal transfers on the platform.

Available webhook events:

Webhook event Description
deposit-created Deposit order has been created
deposit-completed Deposit order has been completed
withdraw-created Withdraw order has been created
withdraw-transaction-sent Withdraw transaction has been sent to the corresponding blockchain
withdraw-completed Withdraw order has been completed

Contents of a webhook message

Each webhook message sent by the Copper platform to your service has the following structure:

Parameter Data type Description
eventId String Unique event identifier
event String Type of event from the list above
subscriptionId String Unique identifier of a webhook subscription
payload Order Payload of the webhook corresponding with the model containing data of the specified order (see example of orders in the Transfer API section for details)

On the right panel, you will find a corresponding example of the webhook message. The actual payload can differ depending on a corresponding order.

Webhook backend on your side

import hashlib
import hmac
from flask import Flask, request

app = Flask(__name__)

WebhookSecret = '<YOUR_SECRET_FROM_UI>'


@app.route('/', methods=['POST'])
def handle():
    timestamp = request.headers.get('X-Timestamp')
    event_id = request.get_json().get('eventId')

    signature = hmac.new(
        key=bytes(WebhookSecret, 'utf-8'),
        msg=bytes(timestamp + event_id + request.get_data().decode("utf-8"), 'utf-8'),
        digestmod=hashlib.sha256
    ).hexdigest()

    if hmac.compare_digest(request.headers.get('X-Signature'), signature):
        return 'OK', 200
    else:
        return 'Bad signature', 400


if __name__ == '__main__':
    app.run(debug=True)

To accept webhook messages, you have to add a web application with a route to accept POST calls from the Copper platform.

The platform calls do not require authorisation, that is why you have to implement verification of a signature provided with each webhook message. To compare signatures:

The X-Signature header is hmac sha256 hash in hex format.

On the right panel, you will find an example of the backend code on Python developed with the use of the Flask library.

To run it on your side, create the __init__.py file and run it. The service will be exposed to your localhost on the port 5000. Then, expose it to an external domain name - for instance, with the use of the ngrok package.

For debug purposes, you can calculate and verify a request signature of a webhook message with the use of following Bash commands:

# Variables:

echo -n "${timestamp}${eventId}${body}" | openssl dgst -sha256 -r -hmac ${secretKey} | awk '{print $1}'

# Values: 
echo -n '1567165602271test-b17c862a961fbba3a02af42a7de6e643{"eventId": "test-b17c862a9......96152012"}' | openssl dgst -sha256 -r -hmac ${secretKey} | awk '{print $1}'

In this example:

How to set up webhooks on the Copper platform

To set up webhooks on the Copper platform, navigate to the Webhooks sub-menu situated in the menu of your account in the bottom-left corner.

In the Webhooks menu, click the Add new button and enter following information:

Click the Generate button to obtain your secret key in order to verify incoming webhook messages. The secret key will be shown only while creating the webhook.

Then, click the Save button to add your webhook address. After this, your service will start to obtain webhook messages occuring within your organisation for specified portfolios.

In the Webhooks menu, you will see webhook endpoints that are currently in operation. You can suspend sending webhook messages to a definite URL by clicking the Pause button, as well as Edit the webhook setup or Delete it.

By clicking upon a definite webhook URL, you will see latest webhook messages transferred to your service and their content, as well as portfolios specified for a definite endpoint.

Webhook API

The /platform/organizations/<organization>/webhooks endpoints of the Copper API are used for creating, managing and removing subscriptions. There are also used to retrieve and re-sent events.

Events types:

This is the list of all available event types.

Event Description
deposit-status-updated The event occurs when status of deposit order changes
deposit-completed The event occurs when deposit order is completed
deposit-created The event occurs when deposit order is created
proxy-transaction-completed The event occurs when proxy transaction is completed
proxy-transaction-created The event occurs when proxy transaction is created
withdraw-status-updated The event occurs when status of withdraw order changes
withdraw-failed The event occurs when withdraw order fails
withdraw-transaction-sent The event occurs when withdraw order is send to blockchain
withdraw-completed The event occurs when withdraw order is completed
withdraw-created The event occurs when withdraw order is created
order-master-password-required The event occurs when the master password is required

1. Create subscription

This method allows to create new subscription.

Required permissions: create-webhook-subscription

Request

Field Data type Description
subscriptionId String Unique subscription identifier
portfolioIds Set <String> List of portfolio identifiers the subscription should listen to. If empty then listen to all portfolios.
events Set <String> List of event types to listen to. Please see available list above.
webhookUrl String URL to send webhooks to.
secret <Optional> String Secret value
ecdsaPrivate <Optional> String ECDSA private key
loanArrangers Set <String> List of loan arrangers that the subscription should listen to. If empty then listen to all. Valid values are copper, clst.

NOTE: Only one of the value secret or ecdsaPrivate value is required.

+ POST /platform/organizations/<organization>/webhooks

+ Headers
  Content-Type: application/vnd.create-webhook-subscription+json

+Body

{
    "webhookUrl": "https://local.com/webhook",
    "portfolioIds": [],
    "subscriptionId": "cl96u174k000p3b5rgcxjdj8f",
    "events": [
        "deposit-status-updated",
        "deposit-completed",
        "deposit-created",
        "proxy-transaction-completed",
        "proxy-transaction-created",
        "withdraw-status-updated",
        "withdraw-failed",
        "withdraw-transaction-sent",
        "withdraw-completed",
        "withdraw-created",
        "order-master-password-required"
    ],
    "secret": "5jAnjkpbi0vBBS2LW3QLDK09NYkveafh",
    "loanArrangers": []
}

Response

Fields:

Field Data type Description
subscriptionId String Unique subscription identifier
organizationId String Unique organization identifier
portfolioIds Set <String> List of portfolio identifiers the subscription should listen to. If empty then listen to all portfolios.
events Set <String> List of event types to listen to. Please see available values above.
webhookUrl String URL to send webhooks to.
isActive Boolean Flag indicates if subscription is active or inactive.
isPaused Boolean Flag indicates if subscription is paused or not.
createdAt Long Timestamp when the subscription has been created.
createdBy String Identifier of the subscription creator.
loanArrangers Set <String> List of loan arrangers that the subscription should listen to. If empty then listen to all.
+ Response 200

{
    "subscriptionId": "cl96u174k000p3b5rgcxjdj8f",
    "organizationId": "ONDREJ",
    "portfolioIds": [],
    "events": [
        "proxy-transaction-completed",
        "withdraw-status-updated",
        "order-master-password-required",
        "deposit-status-updated",
        "withdraw-failed",
        "withdraw-completed",
        "proxy-transaction-created",
        "deposit-created",
        "withdraw-created",
        "withdraw-transaction-sent",
        "deposit-completed"
    ],
    "webhookUrl": "https://local.com/webhook",
    "isActive": true,
    "isPaused": false,
    "createdBy": "d9e38c60-12b0-4ca3-9fe4-5d848e5411a7",
    "createdAt": "1665651745441",
    "loanArrangers": []
}

2. Get subscriptions

This method allows to retrieve all webhook subscriptions for user invoking the request for specified organization.

Required permissions: get-webhook-subscriptions

Request

+ GET /platform/organizations/<organization>/webhooks

The request of the method can have the following optional path parameters:

Parameter Data type Description
offset Optional <Long> Number of subscription skiped from response. Defualt value: 0
limit Optionl <Long> Maximum number of subscription returned. Default value: 100

Response

Fields:

Field Data type Description
webhookSubscriptions List <Webhook subscription> See below for details
_embedded Embedded See below for details

Webhook subscription fields:

Field Data type Description
subscriptionId String Unique subscription identifier
organizationId String Unique subscription identifier
portfolioIds Set <String> List of portfolio identifiers the subscription should listen to. If empty then listen to all portfolios.
events Set <String> List of event types to listen to. Please see availalbe values above.
webhookUrl String URL to send webhooks to.
isActive Boolean Flag indicates if subscription is active or inactive.
isPaused Boolean Flag indicates if subscription is paused or not.
createdAt Long Timestamp when the subscription has been created.
createdBy String Identifier of the subscription creator.
updatedAt Long Timestamp when the subscription has been last time update.
updatedBy String Identifier of user updating subscription.
loanArrangers Set <String> List of loan arrangers that the subscription should listen to. If empty then listen to all.

Embedded fields:

Field Data type Description
webhookEventTypes List <WebhookEventType> List of webbhook event types

WebhookEventType fields:

Field Data type Description
webhookEventTypeId String Webhook type identifier
category String Webhook category (UI used)
webhookEventTypeReadable String Webhook human readable name (UI used)
isInternal Boolean Flag indicates if webhook is internal or external
+ Response 200

{
    "webhookSubscriptions": [
        {
            "subscriptionId": "cl96u174k000p3b5rgcxjdj8f",
            "organizationId": "ONDREJ",
            "portfolioIds": [],
            "events": [
                "proxy-transaction-completed",
                "withdraw-status-updated",
                "order-master-password-required",
                "deposit-status-updated",
                "withdraw-failed",
                "withdraw-completed",
                "proxy-transaction-created",
                "deposit-created",
                "withdraw-created",
                "withdraw-transaction-sent",
                "deposit-completed"
            ],
            "webhookUrl": "https://local.com/webhook",
            "isActive": true,
            "isPaused": false,
            "createdBy": "d9e38c60-12b0-4ca3-9fe4-5d848e5411a7",
            "createdAt": "1665651745441",
            "loanArrangers": []
        },
        {
            "subscriptionId": "cl94fsw6b000m3b5r4mf0mbpo",
            "organizationId": "ONDREJ",
            "portfolioIds": [],
            "events": [
                "proxy-transaction-completed",
                "withdraw-status-updated",
                "order-master-password-required",
                "deposit-status-updated",
                "withdraw-failed",
                "withdraw-completed",
                "proxy-transaction-created",
                "deposit-created",
                "withdraw-created",
                "withdraw-transaction-sent",
                "deposit-completed"
            ],
            "webhookUrl": "https://webhook.site/7b9b4930-d68f-4f72-aa76-bd1494d2608a",
            "isActive": true,
            "isPaused": false,
            "createdBy": "d9e38c60-12b0-4ca3-9fe4-5d848e5411a7",
            "createdAt": "1665506905008",
            "updatedBy": "d9e38c60-12b0-4ca3-9fe4-5d848e5411a7",
            "updatedAt": "1665508930333",
            "loanArrangers": []
        },
        {
            "subscriptionId": "cl8lipatb000l3b5rb3uj8rv5",
            "organizationId": "ONDREJ",
            "portfolioIds": [],
            "events": [
                "deposit-status-updated",
                "deposit-created",
                "deposit-completed"
            ],
            "webhookUrl": "https://webhook.site/d928f3a4-c3e1-4737-b1dc-a5d4c7581b7c",
            "isActive": true,
            "isPaused": false,
            "createdBy": "d9e38c60-12b0-4ca3-9fe4-5d848e5411a7",
            "createdAt": "1664362921728",
            "loanArrangers": []
        }
    ],
    "_embedded": {
        "webhookEventTypes": [
            {
                "webhookEventTypeId": "deposit-created",
                "category": "Deposit",
                "webhookEventTypeReadable": "Created",
                "isInternal": false
            },
            {
                "webhookEventTypeId": "deposit-completed",
                "category": "Deposit",
                "webhookEventTypeReadable": "Completed",
                "isInternal": false
            },
            {
                "webhookEventTypeId": "proxy-transaction-created",
                "category": "Proxy-transaction",
                "webhookEventTypeReadable": "Created",
                "isInternal": false
            },
            {
                "webhookEventTypeId": "proxy-transaction-completed",
                "category": "Proxy-transaction",
                "webhookEventTypeReadable": "Completed",
                "isInternal": false
            },
            {
                "webhookEventTypeId": "withdraw-created",
                "category": "Withdraw",
                "webhookEventTypeReadable": "Created",
                "isInternal": false
            },
            {
                "webhookEventTypeId": "withdraw-completed",
                "category": "Withdraw",
                "webhookEventTypeReadable": "Completed",
                "isInternal": false
            },
            {
                "webhookEventTypeId": "withdraw-transaction-sent",
                "category": "Withdraw",
                "webhookEventTypeReadable": "Transaction sent",
                "isInternal": false
            },
            {
                "webhookEventTypeId": "order-master-password-required",
                "category": "Transfer",
                "webhookEventTypeReadable": "Conditional Transfers - Password Required",
                "isInternal": false
            },
            {
                "webhookEventTypeId": "withdraw-failed",
                "category": "Withdraw",
                "webhookEventTypeReadable": "Failed",
                "isInternal": false
            },
            {
                "webhookEventTypeId": "withdraw-status-updated",
                "category": "Withdraw",
                "webhookEventTypeReadable": "Withdraw status updated",
                "isInternal": false
            },
            {
                "webhookEventTypeId": "deposit-status-updated",
                "category": "Deposit",
                "webhookEventTypeReadable": "Deposit status updated",
                "isInternal": false
            }
        ]
    }
}

3. Update subscription

This method allows to update webhook subscription.

Required permissions: update-webhook-subscription

Request

Field Data type Description
portfolioIds Set <String> List of portfolio identifiers the subscription should listen to. If empty then listen to all portfolios.
events Set <String> List of event types to listen to. Please see available values above.
webhookUrl String URL to send webhooks to.
loanArrangers Set <String> List of loan arrangers that the subscription should listen to. If empty then listen to all. Valid values are copper, clst.
+ PATCH /platform/organizations/<organization>/webhooks/<subscriptionId>

+ Headers
  Content-Type: application/vnd.update-webhook-subscription+json

+ Body

{
    "webhookUrl": "https://local.com/webhook",
    "portfolioIds": [],
    "events": [
        "withdraw-created"
    ],
    "loanArrangers": []
}

Response

Fields:

Field Data type Description
subscriptionId String Unique subscription identifier
organizationId String Unique subscription identifier
portfolioIds Set <String> List of portfolio identifiers the subscription should listen to. If empty then listen to all portfolios.
events Set <String> List of events to listen to. Please see availalbe values on request.
webhookUrl String URL to send webhooks to.
isActive Boolean Flag indicates if subscription is active or inactive.
isPaused Boolean Flag indicates if subscription is paused or not.
createdAt Long Timestamp when the subscription has been created.
createdBy String Identifier of the subscription creator.
updatedAt Long Timestamp when the subscription has been last time update.
updatedBy String Identifier of user updating subscription.
loanArrangers Set <String> List of loan arrangers that the subscription should listen to. If empty then listen to all.
+ Response 200

{
    "subscriptionId": "cl96u174k000p3b5rgcxjdj8f",
    "organizationId": "ONDREJ",
    "portfolioIds": [],
    "events": [
        "withdraw-created"
    ],
    "webhookUrl": "https://local.com/webhook",
    "isActive": true,
    "isPaused": false,
    "createdBy": "d9e38c60-12b0-4ca3-9fe4-5d848e5411a7",
    "createdAt": "1665651745441",
    "updatedBy": "d9e38c60-12b0-4ca3-9fe4-5d848e5411a7",
    "updatedAt": "1665654329162",
    "loanArrangers": []
}

4. Pause subscription

This method allows to pause webhook subscription for user invoking the request for specified organization.

Required permissions: pause-webhook-subscription

Request

Fields:

Field Data type Description
isPaused Boolean If set to true then subscription is paused and not webhook are send.
+ PATCH /platform/organizations/<organization>/webhooks/<subscriptionId>

+ Headers
  Content-Type: application/vnd.pause-webhook-subscription+json

+ Body

{
    "isPaused": true
}

Response

This method does not return any fields.

5. Deactivate subscription

This method allows to remove webhook subscription.

Required permissions: deactivate-webhook-subscription

Request

+ DELETE /platform/organizations/<organization>/webhooks/<subscriptionId>

Response

This method does not return any fields.

6. Get webhook events

This method allows to get events for the subscription.

Required permissions: get-webhook-events

The request of the method can have the following optional path parameters:

Parameter Data type Description
payloadId String Payload identifier.
event String Type of the events to retrieve.
delivered Boolean Flag indicates if the event has been delivered or not.
from Long Timestamp from when to returns events
to Long Timestamp to when retrieve events
offset Optional <Long> Number of events skipped from response. Default value: 0
limit Optional <Long> Maximum number of events returned. Default value: 100

Request

+ GET /platform/organizations/<organization>/webhooks/<subscriptionId>/events

Response

Fields:

Field Data type Description
webhookEvents List <Webhook event> List of webhook events

Webhook event fields:

Field Data type Description
eventId String Event identifier.
event String Event type.
subscriptionId String Subscription identifier.
payload Json Json representation of payload.
response WebhookResponse See below.
payloadId String Payload identifier.
payloadType Enum Values: order, transaction
createdAt Long Timestamp when the event has been created.
sentAt Long Timestamp when the event has been send.

Webhook response event fields:

Field Data type Description
statusCode Integer Response code
response String Response message
+ Response 200

{
    "webhookEvents": [
        {
            "eventId": "cl94fsw6b000m3b5r4mf0mbpo-87cdd43428b476e1e3f404f6a47195b1",
            "event": "deposit-status-updated",
            "subscriptionId": "cl94fsw6b000m3b5r4mf0mbpo",
            "payload": {
                "extra": {
                    "confirmations": "1",
                    "fromAddresses": [
                        "rB5kHM3KyiUBrbcTsR4VxBHpfLPxSfK2B2"
                    ],
                    "transactionId": "11EDD1EDCE57C1A0C7B29E383D485A80F5A5B88577CC196D5AF25E78FF557984",
                    "depositTargetId": "b4f844fe-2d14-43bd-88de-9a5be37bb90c",
                    "fromPortfolioId": "cl94h8ija000o3b5r0agztb0w",
                    "withdrawOrderId": "30",
                    "reportingCurrencyRate": "0.255206"
                },
                "amount": "50",
                "status": "executed",
                "orderId": "31",
                "accountId": "f1ca3a79-29a3-4ae2-85d2-bede2f878609",
                "createdAt": "1665509841000",
                "orderType": "deposit",
                "updatedAt": "1665509979859",
                "portfolioId": "cl8ld1ci700133b5r8hi25usk",
                "baseCurrency": "XRP",
                "mainCurrency": "XRP",
                "terminatedAt": "1665509979859",
                "portfolioType": "custody",
                "organizationId": "ONDREJ",
                "externalOrderId": "XRP:3e82d0e4-e460-4017-ad7f-5a4e36a68240"
            },
            "response": {
                "statusCode": "200",
                "response": ""
            },
            "payloadId": "31",
            "payloadType": "order",
            "createdAt": "1665509979878",
            "sentAt": "1665509980795"
        }
    ]
}

7. Resent events

This method allows to re-sent selected events.

Required permissions: send-webhook-event

Request

Field Data type Description
eventIds List <String> List of event identifiers to resent
+ PATCH /platform/organizations/<organization>/webhooks/<subscriptionId>/events

+ Headers
  Content-Type: application/vnd.send-webhook-events+json

+Body

{
    "eventIds": [
        "cl94fsw6b000m3b5r4mf0mbpo-87cdd43428b476e1e3f404f6a47195b1",
        "cl94fsw6b000m3b5r4mf0mbpo-69ef3f24482af2a40303b5f95ac53d35"
    ]
}


Response

Field Data type Description
eventIds List <String> List of resend event identifiers
+ Response 200

{
    "eventIds": [
        "cl94fsw6b000m3b5r4mf0mbpo-87cdd43428b476e1e3f404f6a47195b1",
        "cl94fsw6b000m3b5r4mf0mbpo-69ef3f24482af2a40303b5f95ac53d35"
    ]
}

User flows

This section includes combined use-cases of the Copper platform API.

Create a deposit target

+ POST /platform/deposit-targets

+ Request
    {
        "externalId": "[[external id]]", # Enter the external ID manually
        "portfolioId": "[[portfolio id]]", # Paste the portfolio ID here
        "currency": "USDT", # Portfolio currency
        "mainCurrency": "ALGO", # Portfolio main currencny
        "name": "Algo Wallet", # Arbitrary name
        "metadata": {
          "tags": ["test"] # Arbitrary tag
        }
    }

Move funds between accounts

  + POST /platform/orders

  + Request (application/json)
  {
    "externalOrderId": "F7FCCFD3-B61B-4467-B456-B0FC27CE4494",   # Unique identifier
    "orderType": "withdraw",
    "baseCurrency": "ETH", # Currency to move
    "mainCurrency": "ETH", # What blockchain/vault wallet to use when moving
    "amount": "42", # Amount to move
    "portfolioId": "46",   # From this portfolioId
    "toPortfolioId": "7",   # To this portfolioId
    "withdrawalPassword": "97dee97560699a639f3cf55c464855eefe97ae97493b242fe01ecdbab39ea463" # Optional, sha256 has of organization Withdrawal Password 
  }

Withdraw fiat to bank account

  + POST /platform/orders

  + Request (application/json)
  {
    "externalOrderId": "F7FCCFD3-B61B-4467-B456-B0FC27CE4494",  # Unique identifier
    "orderType": "withdraw",
    "baseCurrency": "USD", # Fiat currency to withdraw
    "amount": "100", # Amount to withdraw
    "portfolioId": "46", # Chosen portfolioId
    "toBankAccountId": "67"      # Chosen bankAccountId
  }

Withdraw crypto to an unknown or external address

  + POST /platform/orders

  + Request (application/json)
  {
    "externalOrderId": "F7FCCFD3-B61B-4467-B456-B0FC27CE4494",     # Unique order identifier (e.g. UUID or timestamp)
    "orderType": "withdraw",
    "baseCurrency": "BTC",
    "mainCurrency": "BTC",
    "amount": "1.00451",
    "portfolioId": "46",
    "toAddress": "15BLpZebnTTTtfuBwmB8x1VRfcGtPJhK3p",      # Destination wallet address
    "destinationTag": 34,       # Optional, used only for XRP (Ripple) withdrawal
    "memo": "testme",       # Optional blockchain memo
    "feeLevel": "low",      # "low", "medium" or "high". Optional, "low" by default
    "includeFeeInWithdraw": true   # Include fee in the transaction amount, optional.
  }

After this, you will have to sign the withdraw from your vault.

Withdraw cryptocurrency to a whitelisted crypto address

  + POST /platform/orders

  + Request (application/json)
  {
    "externalOrderId": "F7FCCFD3-B61B-4467-B456-B0FC27CE4494",     # Unique order identifier (e.g. UUID or timestamp)
    "orderType": "withdraw",
    "baseCurrency": "BTC",
    "mainCurrency": "BTC",
    "amount": "1.00451",
    "portfolioId": "46",
    "toCryptoAddressId": "cbc328f5-85de-4c2d-a0b9-65a0c7f81b72"      # Destination cryptoAddressId
  }

After this, you will have to sign the withdraw from your vault.

Withdraw cryptocurrency to an address inside the platform

  + POST /platform/orders

  + Request (application/json)
  {
    "externalOrderId": "F7FCCFD3-B61B-4467-B456-B0FC27CE4494",   
    "orderType": "withdraw",
    "baseCurrency": "BTC",
    "amount": "3",
    "portfolioId": "ba8azuNgohfeiphietai9Angeiz2thi8",    # Withdraw from 
    "toPortfolioId": "poo5feesa8ahKai6phoo1iofai3niesh"   # Withdraw to
  }

After this, you will have to sign the withdraw from your vault.

Conditional transfers

The Copper API allows to create a withdrawal chain with the use of only one order.

+ POST /platform/orders

+ Request
  {
    "externalOrderId": "F7FCCFD3-B61B-4467-B456-B0FC27CE4494",   
    "orderType": "withdraw",
    "baseCurrency": "BTC",
    "amount": "3",
    "portfolioId": "ba8azuNgohfeiphietai9Angeiz2thi8",     # Withdraw from
    "toPortfolioId": "poo5feesa8ahKai6phoo1iofai3niesh",   # Withdraw to
    "nextTransferTo": [
      { "targetType": "portfolio", "portfolioId": "ckj45ee8f001k3g5vna9bf9vl" },  # Then transfer here
      { "targetType": "portfolio", "portfolioId": "ckj45eu0m001r3g5vbh1k2caf" }   # After this, transfer here
    ]
  }

+ Response:
  {
    "orderId": "234234",
    "externalOrderId": "F7FCCFD3-B61B-4467-B456-B0FC27CE4494",
    "orderType": "withdraw",
    "extra": { "transferChainId": "F7FCCFD3-B61B-4467-B456-B0FC27CE4494" },
    ...
  }

In this workflow, orders in the master-password-required status still require additional processing:

+ PATСH /platform/orders/554433

+ Headers:
  Content-Type: application/vnd.enter-withdrawal-password+json

+ Request
  {
  "withdrawalPassword": "97dee97560699a639f3cf55c464855eefe97ae97493b242fe01ecdbab39ea463" # SHA256 hash of the organization Withdrawal Password
  }

All orders in the withdraw chain will contain the same extra.transferChainId field. That is why, you can request all withdraw chain orders at once:

+ GET /platform/orders?transferChainId=PBTEST-939175d9-4d92-4d86-a8b5-1173554f645c

+ Response
  {
    "orders": [
      {
        "orderId": "1",
        "orderType": "withdraw",
        "extra": { "transferChainId": "PBTEST-939175d9-4d92-4d86-a8b5-1173554f645c" },
        ....
      },
      {
        "orderId": "2",
        "orderType": "deposit",
        "extra": { "transferChainId": "PBTEST-939175d9-4d92-4d86-a8b5-1173554f645c" },
        ....
      },
      {
        "orderId": "3",
        "orderType": "withdraw",
        "extra": { "transferChainId": "PBTEST-939175d9-4d92-4d86-a8b5-1173554f645c" },
        ....
      },
      {
        "orderId": "4",
        "orderType": "deposit",
        "extra": { "transferChainId": "PBTEST-939175d9-4d92-4d86-a8b5-1173554f645c" },
        ....
      }
    ]
  }

Create an ETH withdrawal transaction with a payload: unknown or external address

  + POST /platform/orders

  + Request (application/json)
  {
    "externalOrderId": "F7FCCFD3-B61B-4467-B456-B0FC27CE4494",     # Unique order identifier (e.g. UUID or timestamp)
    "orderType": "withdraw",
    "baseCurrency": "ETH",
    "mainCurrency": "ETH",
    "amount": "0",
    "portfolioId": "46",
    "toAddress": "0x7a250d5630b4cf539739df2c5dacb4c659f2488d",      # Destination wallet address
    "payload": "0x7ff36ab50000000000000000000000000000000000000000000000011f36d51e6b78ff1100000000000000000000000000000000000000000000000000000000000000800000000000000000000000001a75344addadcdecce4fbf859caa7ef9d9299f78000000000000000000000000000000000000000000000000000000005fb2ad0a0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000009f8f72aa9304c8b593d555f12ef6589cc3a579a2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef",       # Optional payload
    "feeLevel": "low",      # "low", "medium", "high". Optional, "low" by default
    "includeFeeInWithdraw": false 
  }

Create an ETH withdraw transaction with a payload: whitelisted crypto address

  + POST /platform/orders

  + Request (application/json)
  {
    "externalOrderId": "F7FCCFD3-B61B-4467-B456-B0FC27CE4494",     # Unique order identifier (e.g. UUID or timestamp)
    "orderType": "withdraw",
    "baseCurrency": "ETH",
    "mainCurrency": "ETH",
    "amount": "0",
    "payload": "0x7ff36ab50000000000000000000000000000000000000000000000011f36d51e6b78ff1100000000000000000000000000000000000000000000000000000000000000800000000000000000000000001a75344addadcdecce4fbf859caa7ef9d9299f78000000000000000000000000000000000000000000000000000000005fb2ad0a0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000009f8f72aa9304c8b593d555f12ef6589cc3a579a2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef",       # Optional payload
    "feeLevel": "low",      # "low", "medium", "high". Optional, "low" by default
    "includeFeeInWithdraw": false, 
    "toCryptoAddressId": "cbc328f5-85de-4c2d-a0b9-65a0c7f81b72"      # Destination cryptoAddressId
  }

Get supported currencies and tokens

In order to obtain a full list of currencies and tokens supported by Copper, use the GET /platform/currencies method. This method does not require any permissions and will return the currencies model containing the information on each supported currency.

To filter the output, specify following parameters in the request:

Parameter Type Additional information
currency Optional<[String]> Return an asset only with the specified market ticker.
rateFor Optional<String> Return the price of the currency only for an asset with the market ticker specified in this field.
+ GET /platform/currencies?currency=BTC&rateFor=USD

+ Response
  {
    "currencies": [
      {
        "currency": "BTC",
        "mainCurrency": "BTC",
        "name": "Bitcoin",
        "fiat": false,
        "priority": "6",
        "confirmations": "2",
        "decimal": "8",
        "tags": [
          "deposit-custody",
        ],
        "color": "#fa8a34",
        "feesLevels": [
          {
            "feeLevel": "low",
            "value": "0.00029"
          },
          {
            "feeLevel": "medium",
            "value": "0.00031"
          },
          {
            "feeLevel": "high",
            "value": "0.00033"
          }
        ],
        "explorerUrl": "blockchair.com/bitcoin/transaction/",
        "_embedded": {
          "price": {
            "baseCurrency": "BTC",
            "quoteCurrency": "USD",
            "price": "41038.46"
          }
        }
      }
    ]
  }

HNT Staking (Trading API)

Note: Minimum amount of the stake should be equal or more than 10,000 HNT.

To process HNT staking from your Vault, perform following steps:

  docker run --rm -ti \
  -v ${PWD}/key-backups/:/app/keys/ \  # Here, **key-backups** is a directory containing saved shards of your HNT wallet.
  -p 3010:3010 \
  copperexchange/copper-unlimited:latest
Field Type Additional information
externalOrderId String Unique order identifier given by the client (should be unique to portfolio)
orderType OrderType Type of order
baseCurrency Currency Currency used for the order
mainCurrency Currency Main currency of the blockchain
amount BigDecimal Order execution amount
portfolioId String Portfolio used for staking
blockchainTransactionType TransactionType Type of blockchain transaction to perform: stake-delegation
poolId String filter by tags, should be comma-separated string

  + POST /platform/orders

  + Request
  {
    "externalOrderId": "[[external id]]",  
    "orderType": "withdraw",
    "baseCurrency": "HNT",
    "mainCurrency": "HNT",
    "amount": "10000",
    "portfolioId": "[[portfolio id]]",
    "blockchainTransactionType": "stake-delegation",
    "poolId": "[[stake address]]"
  } 

  + Response 201
  {
    "orderId": "5824946",
    "orderType": "withdraw",
    "amount": "10000",
    "baseCurrency": "HNT",
    "mainCurrency": "HNT",
    "externalOrderId": "[[external id]]",
    "portfolioId": "[[portfolio id]]",
    "portfolioType": "custody",
    "status": "awaiting-settlement"
  } 
  + PATCH https://api.copper.co/platform/orders/{orderId}

  + Headers
    Content-Type: application/vnd.start-custody-settlement+json

  + POST http://172.17.0.2:3010/signatures

  + Headers
    Content-Type: application/json

  + Request
  {
    "type": "request",
    "keyPassword": "myTestPaswordFromKeyBackup.1234#",
    "keyFilename": "HNT_staking.copper",

    # Here, insert all the fields included into transactionRequest at the previous step.
  }

  + Response 200 OK
  {
    "type": "part-signed-tx",
    "value": "AQRwL5FqGrbLaPO4w+NoEq9oZ...R5I/wjEQND/4YmIn+rbN9uh5U/0=",
  }

+ PATCH https://api.copper.co/platform/orders/{orderId}

+ Headers
  Content-Type: application/vnd.upload-part-signed-tx+json

+ Request
{
  "transaction": {
    "type": "part-signed-tx",
    "value": "AQRwL5FqGrbLaPO4w+NoEq9oZ...R5I/wjEQND/4YmIn+rbN9uh5U/0="
  }
}

XZC staking (Wallet Messages API)

For staking operations with the XZC token, the Copper platform uses the Wallet Messages API. To learn more, refer to the corresponding section.

To stake XZC from your Copper account, follow these steps:

  docker run --rm -ti \
  -v ${PWD}/key-backups/:/app/keys/ \  # Here, **key-backups** is a directory containing saved shards of your HNT wallet.
  -p 3010:3010 \
  copperexchange/copper-unlimited:latest
  + POST https://api.copper.co/platform/wallet-messages

  + Request
  {
    "externalMessageId": "ckdr8xy1l00303g5neu5iunh4",
    "mainCurrency": "XZC",
    "message": "test",
    "portfolioId": "edd7e0ea-9d00-4538-b187-c14813d7b0ba",  # From account
  } 

  + Response 201
  {
    "externalMessageId": "ckfgpkesr000d3j5twa61gzl1",
    "messageId": "24",
    "status": "working",
    "portfolioId": "ck8owwcvj000f3j5wrjoyip4d",
    "mainCurrency": "XZC",
    "extra": {
      "messageRequest": {
        "publicKeyHash": "d9f3c6b1066c188aa039e0f4a67dd8b10caf3de3e9c7862a8d0fb17320d57b14",
        "currency": "XZC",
        "mainCurrency": "XZC",
        "message": "test",
        "nonceNumber": "16"
      }
    },
    "createdBy": "191b5342-2157-4ede-9458-eb673f324468",
    "organizationId": "PSHENKIN",
    "accountId": "67126cc0-357d-4642-9596-ac0c0bdf4006",
    "createdAt": "1600945419113"
  }
  + POST http://127.0.0.1:3010/signatures

  + Headers
    Content-Type: application/json

  + Request
  {
    "type": "message-request",
    "keyPassword": "myTestPaswordFromKeyBackup.1234#",
    "keyFilename": "XZC_My Default Vault_wallet.copper",


    # Get all this fields from message.extra.messageRequest, described above
    "signRequest": {
      "publicKeyHash": "d9f3c6b1066c188aa039e0f4a67dd8b10caf3de3e9c7862a8d0fb17320d57b14",
      "currency": "XZC",
      "mainCurrency": "XZC",
      "message": "test",
      "nonceNumber": "16"
    }
  }

  + Response 200 OK
  {
    "type": "part-signed-message",
    "value": "AQRwL5FqGrbLaPO4w+NoEq9oZ...R5I/wjEQND/4YmIn+rbN9uh5U/0=",
  }
  + PATCH https://api.copper.co/platform/wallet-messages/{walletMessageId}

  + Headers
    Content-Type: application/vnd.upload-part-signed-wallet-message+json

  + Request
  {
    "partSignedMessage": {
      "type": "part-signed-tx",
      "value": "AQRwL5FqGrbLaPO4w+NoEq9oZ...R5I/wjEQND/4YmIn+rbN9uh5U/0="
    }
  }

ClearLoop: delegating funds to exchange

To delegate funds to an exchange via the ClearLoop, use the POST /platform/orders method: create a new withdraw order for transferring funds from your Trading account to the ClearLoop account.

+ POST /platform/orders

+ Request
  {
    "externalOrderId": "720A55C4-30FB-4418-8B73-F12E4AD99AA5",  # Unique order identifier (e.g. UUID or timestamp)
    "amount": "1",
    "baseCurrency": "BTC",
    "orderType": "withdraw",
    "portfolioId": "Bahng9nai9ieGhaeg8Heasokahshee7A",   # From the parent Trading account
    "toPortfolioId": "oishiphoosaipho9ooTikohk5foo4Wah"  # To the ClearLoop account
  } 

ClearLoop: undelegating funds

To undelegate funds delegated earlier to an exchange, use the POST /platform/orders method: create a new withdraw order for transferring funds from the ClearLoop account to the parent Trading account.

+ POST /platform/orders

+ Request
{
  "externalOrderId": "720A55C4-30FB-4418-8B73-F12E4AD99AA5",  # Unique order identifier (e.g. UUID or timestamp)
  "amount": "1",
  "baseCurrency": "BTC",
  "orderType": "withdraw",
  "portfolioId": "oishiphoosaipho9ooTikohk5foo4Wah",   # From the parent ClearLoop account
  "toPortfolioId": "Bahng9nai9ieGhaeg8Heasokahshee7A"  # To the ClearLoop account
} 

ClearLoop: get data on delegated funds

To retrieve information about funds delegated within the organisation, use the GET /platform/wallets with the portfolioId={clearLoopPortfolioId} parameter to output only wallets related to your specified ClearLoop portfolio.

+ GET /platform/wallets?portfolioId={clearLoopPortfolioId}

+ Response 200 OK
{
  "wallets": [
  {
    "walletId": "ck92vvxyc000a3g5mb74gcdjh",
    "portfolioId": "oishiphoosaipho9ooTikohk5foo4Wah",
    "organizationId": "MYORG1"
    "currency": "BTC",
    "balance": "13",
    "reserve": "0",
    "available": "13"
  },
  {
    "walletId": "oWou4Queir5eevaezeed6",
    "portfolioId": "oishiphoosaipho9ooTikohk5foo4Wah",
    "organizationId": "MYORG1"
    "currency": "ETH",
    "balance": "1348.4562",
    "reserve": "0",
    "available": "1348.4562"
  }
  ]
}

Binance Smart Chain: sending unjail transaction

The unjail transaction is designed for releasing validator nodes that were jailed (blocked) for suspiciously malicious or negative behaviour.

This transaction can be sent from an address of a validator operator that is within the Copper ecosystem.

Official reference about the unjail transaction can be found here.

The unjail transaction can be sent from the address within the Copper ecosystem with the use of the POST /platform/orders method with the payload described below.

+ POST /platform/orders

+ Request
{
    "externalOrderId": "{{externalId}}",  
    "orderType": "withdraw",
    "baseCurrency": "BNB",
    "mainCurrency": "BNB",
    "amount": "0",
    "blockchainTransactionType": "unjail",
    "portfolioId": "{{portfolioId}}"
}

+ Response 200 OK

Fetch all updated orders

#!python

import hashlib
import hmac
import json
import os
import requests
import time

ApiKey = os.getenv("COPPER_LIVE_API_KEY")
ApiSecret = os.getenv("COPPER_LIVE_API_SECRET")


def copper_api(method, path, body=None):
    timestamp = str(round(time.time() * 1000))

    body_string = json.dumps(body) if body else ""

    signature = hmac.new(
        key=bytes(ApiSecret, 'utf-8'),
        msg=bytes(timestamp + method + path + body_string, 'utf-8'),
        digestmod=hashlib.sha256
    ).hexdigest()

    url = 'https://api.copper.co' + path

    resp = requests.request(method, url, data=body_string, headers={
        'Authorization': 'ApiKey ' + ApiKey,
        'X-Signature': signature,
        'X-Timestamp': timestamp
    })

    print("Copper API ~~~> " + method + " " + url + " <~~~ " + str(resp.status_code) + " " + resp.reason)

    if resp.status_code >= 400:
        raise Exception("Copper API Error: " + str(resp.status_code) + " " + resp.reason + " <~~~ " + resp.text)

    return resp.json()


def get_latest_updated_at():
    # retrieve the updated_at value from a database or return 0
    return 0


def save_latest_updated_at(updated_at):
    # store the updated_at value in a database
    pass


def fetch_updated_orders(last_updated_at):
    # fetch all orders from Copper that have been updated since updated_at
    # return a list of orders
    limit = 100

    response = copper_api("GET", "/platform/orde1rs?orderType=deposit&updatedSince=" + str(last_updated_at) + "&limit=" + str(limit))

    orders = response.get('orders', [])

    if len(orders) > 0:

        for order in orders:
            # do something with the order

            print(order.get('orderId') + " - " + order.get('updatedAt'))

            pass

        last_updated_at = orders[-1].get('updatedAt')

        save_latest_updated_at(last_updated_at)

        if len(orders) != limit:
            time.sleep(10) # wait 10 seconds before fetching the next batch of orders

        fetch_updated_orders(last_updated_at)


if __name__ == "__main__":
    fetch_updated_orders(get_latest_updated_at())

Models

The following are common types used throughout the API.

Order

Parameter Data type Description
orderId String Unique order identifier generated upon its creation
externalOrderId String Unique order identifier passed in the request
status Order Type Operating status of the order
orderType Order Type Type of the order
portfolioId String Unique identifier of the portfolio, for which the order will be created
portfolioType Enum<PortfolioType> Type of the portfolio
accountId String Account identifier
amount BigDecimal Order execution amount
baseCurrency Currency Currency of the amount
mainCurrency Optional<Currency> Currency defining a blockchain network for baseCurrency
quoteCurrency Optional<Currency> Quote currency of the trading order
quoteMainCurrency Optional<Currency> Currency defining a blockchain network for quoteCurrency
limitType Optional<Limit Type> Limit type of the order
priceLimit Optional<BigDecimal> Price of a settle or trading order
extra OrderExtra Additional order data
createdBy Optional<String> User ID of the order creator
organizationId String Unique ID of the organisation of the creator
createdAt Long Time of order creation
updatedAt Optional<Long> Time of the latest order update
terminatedAt Optional<Long> Time of the order termination

Order Types

Name Description
buy Buy order
sell Sell order
withdraw Withdraw order
multi-withdraw Withdraw to multiple addresses order
deposit Deposit order
earn-reward Order to earn rewards for staking the assets

Order Statuses

Status Description
error something went wrong, see the errorDescription field
new order has been created.
reserved required amount of funds has been reserved on the balance (for withdraw, buy and sell orders only)
working order processing
waiting-approve awaiting administrator approval (for deposit and withdrawal orders)
co-sign-require order still needs to be co-signed by an authorised organisation member
approved deposit or withdraw order has been approved by Copper’s admin, and will be processed shortly
processing waiting for the minimum required number of network confirmations from the blockchain (for withdraw orders)
executed order is completed
canceled order has been cancelled
part-signed-tx-added partly-signed transaction has been added for a Vault order
full-signed-tx-added fully-signed transaction has been added for a Vault order
rejected-part-signed-tx-added after rejected: a rejected part-signed transaction has been added for a Vault order
rejected-full-signed-tx-added after rejected: a rejected fully-signed transaction has been added for a Vault order
awaiting-settlement a Vault order is waiting for settlement (as a rule, requires a user action: press the Start settlement button in the UI)
master-password-required a Vault order requires a master password from the user to proceed
rejected a request has been rejected by Copper’s admin, now waiting for rejection transaction signature
waiting-counterparty-approve awaiting counterparty to approve OTC order
require-initializer-approve an OTC requires approval of its initializer
require-counterparty-approve new OTC order requires counterparty approval
settled an OTC order has been settled

Limit Types

Name Description
otc Limit type of the settle order
rfq Limit type of a trading order

Portfolio Types

Name Description
custody Portfolio type of a vault portfolio
trading-vault Portfolio type of a trading vault portfolio
trading Portfolio type of a trading portfolio
external Portfolio type of an external portfolio (Walled-Garden accounts)
clearloop Portfolio type of a ClearLoop portfolio

CreateOrder

Field Data type Description
externalOrderId String Unique order identifier from client (should be unique for the portfolio, should not be blank)
orderType OrderType Order type: withdraw
portfolioId String Unique identifier of the portfolio, for which the order will be created
amount BigDecimal Order execution amount
baseCurrency Currency Currency for the amount
mainCurrency Optional<Currency> Currency of main blockchain (e.g. for USDT, it could be either ETH or BTC currency)
toAddress Optional<String> Withdraw address
toCryptoAddressId Optional<String> Withdraw crypto address identifier
toBankAccountId Optional<String> Withdraw bank account identifier
toPortfolioId Optional<String> Withdraw portfolioId identifier
blockchainTransactionType Optional<String> Blockchain transaction type
destinationTag Optional<Long> Withdraw destination tag
memo Optional<String> Withdraw memo
withdrawalPassword Optional<String> Withdraw password for External portfolio (sha256 hash string)
description Optional<String> Arbitrary description allowing to identify an order

Changelog

May 2023

January 2023

November 2022

August 2022

July 2022

May 2022

February 2022

December 2021

November 2021

October 2021